Join the Stack Overflow Community
Stack Overflow is a community of 6.5 million programmers, just like you, helping each other.
Join them; it only takes a minute:
Sign up

I have an ng-include rendering partials on my page but as is the nature of ng-include I do not need a state to load the partials. I would like the URL to update when the ng-include updates its view so my analytics track it as a page change. I am wondering the best way to do this.

Also I am using angular-ui-router, which makes ng-include irrelevant because of nested states; until one comes across my situation: I have a large number of partials loading into the ng-include, which is lovely because all I need to provide is a path to the partial and not a massive number of different states to my $stateProvider file; but then there is no custom url. As such what I was wondering is the following:

Can an Ng-include update the page url when it loads a partial without having a state defined for that partial view

OR

something that would solve my problem altogether: is there a way to add states that have a url which can be dynamically updated? like:

.state( 'test',  {
        url: function( stateId ){
    // where stateId is somehow passed into the $stateParams of the new state
},
    templateUrl: "templates/views/test.html"
})

here is the setup so far for my ng-include, if you have any ideas on how to get the url to change when the ng-include renders a different partial I would be most pleased.


::JS::

// states
 // self executing function
(function() {

var app = angular.module( 'app', [ 'ui.router', 'ngAnimate' ] );

app.config( function( $stateProvider, $urlRouterProvider ) {

  // if url not defined redirect to login
  $urlRouterProvider.when( '', "/home" );
  // if nonexistant url defined redirect to sign-in
  $urlRouterProvider.otherwise( "/home" );

  // Now set up the states
  $stateProvider
    .state('home', {
      url: "/home",
      templateUrl: "templates/views/home.html"
    });
}()); // self executing function end

// factory
//self executing container function
(function() {
var listFactory = function( ) {
  // declare factory for return at end of function
  var factory = {};

  var list = 
    { 
        list1 : [
            { 
                name: 'first',
                url: 'templates/views/partials/view1.html',
                id: '1'
            },
            {
                name: 'second',
                url: 'templates/views/partials/view2.html',
                id: '2'
            },
            {
                name: 'third',
                url: 'templates/views/partials/view3.html',
                id: '3'
            },
            {
                name: 'fourth',
                url: 'templates/views/partials/view4.html',
                id: '4'
            }
        ]
    };

    factory.getList = function(){
      return list;
    };

    // return factory object to access data
    return factory;
};

  angular.module( 'app' ).factory( 'listFactory', listFactory );

}());

// controller
//self executing container function
(function() {

    var listController = function ( $scope, listFactory ) {

        $scope.listFactory = listFactory.getList();
        // set a default list state
        $scope.currentList = 'templates/views/partials/default.html';

        // function sets list url on click to new scope item for rendering partial view
        $scope.setCurrentList = function( url ) {
            $scope.currentList = url;
        };
    };

    listController.$inject = [ '$scope', 'listFactory' ];

    angular.module('app')
      .controller('listController', listController);

}());

::HTML::

<!-- this is loaded in the home state.  -->

<div>
    <div id="{{ list.id }}" ng-repeat="list in list.list1" ng-click="setCurrentList( list.url )">
        <p>{{ list.name }}</p>
    </div>
</div>
<div id="list-view-container">
    <div class="rotateViewAnimate" ng-include src="currentList"></div>
</div>

::Rather irrelevant CSS::

/* Have to set height explicity on ui-view-container
to prevent collapsing during animation*/
#list-view-container {
    position: relative;
    min-height: 500px;
    overflow: hidden;
}    

/* rotate in / out animation transition */
.rotateViewAnimate.ng-enter, .rotateViewAnimate.ng-leave {
  /* settings so animations display together */
  position: absolute!important;
  left: 0!important;
  right: 0!important;
  -webkit-transition: 0.5s ease-in-out all;
  -moz-transition: 0.5s ease-in-out all;
  -o-transition: 0.5s ease-in-out all;
  transition: 0.5s ease-in-out all;
  transform-style: preserve-3d;
}

.rotateViewAnimate.ng-enter {
    transform: rotateY(90deg);
    opacity: 0;
}

.rotateViewAnimate.ng-enter-active {
    transform: rotateY(0deg);
    opacity:1;
}

.rotateViewAnimate.ng-leave {
    transform: rotateY(0deg);
    opacity:1;
}

.rotateViewAnimate.ng-leave-active {
    transform: rotateY(90deg);
    opacity:0;
}





share|improve this question
1  
ng-include dispatches an event $includeContentLoaded when it loads a template. The event has a src property which will give you the name of the partial. You could write something that listened for this event and changed the URL w/the $location service. Not sure how that will play with UI-Router (e.g. changing the URL would also trigger a state change). The other thing to look out for is when Angular puts your templates in the $templateCache, will the event be fired when you view the partial a second time... – Sunil D. Jul 23 '15 at 16:52
    
hm something like the following may work with your solution: var off = $scope.$on( '$stateChangeStart', function( e ) { e.preventDefault(); }); off(); $location.path('product/123').replace(); It will at least halt the statechange when you bugger around with $location service – Eolis Jul 23 '15 at 16:59

Alright so for partials when using Ui-Router you want to include a

<ui-view>
    <i>Some content will load here!</i>
</ui-view>

where you want the partial to load.

Looks like you have the home state working correctly but if you want to nest the view you have to do something like this

.state('home.view1', {
  url: '/notes',
  templateUrl: 'pages/view1.html',
  controller: 'mainController'
})

The full Url from doing this nested routing would be */#/home/notes For more info: https://github.com/angular-ui/ui-router/wiki

share|improve this answer
    
oh yes yes I have nested views working in my project splendidly; I quite enjoy them. What I am seeking is a way to use ng-include to include my partials and change the url when they are rendered. and I suppose knowledge on weither or not this is something I would ever even need since as you just stated I can nest states to get the same effect as an ng-include. – Eolis Jul 23 '15 at 15:46
    
Using ng-include with UI-Router will causes weird problems, as for the URL change if you do nested views with UI-ROuter it will change the url to be /#/home/notes instead of /#/home/ – Kurt Jul 23 '15 at 15:50
1  
hmmm alrighty. the thing is I am rendering 250 different partials into the same ng-include atm and I want to avoid having to add a state for each partial, but want them all treated as a different page – Eolis Jul 23 '15 at 15:52
up vote 0 down vote accepted


SOLVED


The Issue I was looking to solve is gone over in some detail in the ui-router docs; found here:

https://github.com/angular-ui/ui-router/wiki

I used the following method to achieve the effect mentioned here:

"Set a Dynamic URL on a state using ui-router and angularJS"

Going through the code displayed in the question I will adjust it accordingly with my solution.

// states
// self executing function
(function() {

var app = angular.module( 'app', [ 'ui.router', 'ngAnimate' ] );

app.config( function( $stateProvider, $urlRouterProvider ) {

  // if url not defined redirect to login
  $urlRouterProvider.when( '', "/home" );
  // if nonexistant url defined redirect to sign-in
  $urlRouterProvider.otherwise( "/home" );

  // Now set up the states
  $stateProvider
    .state('home', {
      url: "/home",
      templateUrl: "templates/views/home.html"
    })
    .state( 'home.urlChanger', {
        url: '/urlChanger/name=:name&url=:url',
        params: {
            'spareParam' : 'whateverString'
        },
        views: {
            'viewName@home': {
                templateUrl: function ( $stateParams ){
                    return $stateParams.url;
                },
                controller: "mainController"
            }
        }
    });
}()); // self executing function end

in the above state declaration the state "home.urlChanger" has a url with special characters which are given values from information passed to the $stateProvider variable. a VERY IMPORTANT note here is that if one wants to be able to access the item stored inside $stateParams it must be passed into the URL. as such, in my controller I use the following function to pass the information I want available in the state using the $state.go(); method as follows:

$scope.setParams = function( location ) {
        var urlname = object.stored.in.factory.NAME,
            url = object.from.factory.URL, // path to html file passed to be used in termplateurl from state
            // set stateParams.name to be used in URL
            $stateParams.name = urlName;

            // set params to be passed into URL when $state.go(); is called, they will be available for use then and update the URL with the state setup from above.
            $state.go( location, { name: $stateParams.name, url: url } );
        }; 

as can be seen from the above example I tried storing into $stateparams.name in order to see if it would become available in stateparams, but as is expected when the state.go(); is called a new state is loaded and the previous $stateparams object is no longer available. hence why the information must be passed during $state.go in order to store it into the newly transitioned states $stateParams object.

so the html for causing this to occur could be an ng-click on any element that calls the setparams( location ) function, which will set your variables into $stateParams by passing them through the URL and making them available in your state ie: a dynamic URL set by the state itself.

hopefully someone finds that a bit helpful, it took me some time to work through myself.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.