title: Set dynamic URL on state in AngularJS with Ui-Router
body: <p>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.</p>
  
  <p>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:</p>
  
  <p><strong>Can an Ng-include update the page url when it loads a partial without having a state defined for that partial view</strong></p>
  
  <p><strong>OR</strong></p>
  
  <p><strong>something that would solve my problem altogether:</strong> is there a way to add states that have a url which can be dynamically updated? like:</p>
  
  <pre><code>.state( 'test',  {
          url: function( stateId ){
      // where stateId is somehow passed into the $stateParams of the new state
  },
      templateUrl: "templates/views/test.html"
  })
  </code></pre>
  
   <hr />
  
  <h2><strong>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.</strong></h2>
  
  <hr />
  
  <p><strong>::JS::</strong></p>
  
  <pre><code>// 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);
  
  }());
  </code></pre>
  
  <p><strong>::HTML::</strong></p>
  
  <pre><code>&lt;!-- this is loaded in the home state.  --&gt;
  
  &lt;div&gt;
      &lt;div id="{{ list.id }}" ng-repeat="list in list.list1" ng-click="setCurrentList( list.url )"&gt;
          &lt;p&gt;{{ list.name }}&lt;/p&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;div id="list-view-container"&gt;
      &lt;div class="rotateViewAnimate" ng-include src="currentList"&gt;&lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>::Rather irrelevant CSS::</strong></p>
  
  <pre><code>/* 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;
  }
  </code></pre>
  
  <p><br /><br />
  <hr /><hr /></p>