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;
}
ng-include
dispatches an event$includeContentLoaded
when it loads a template. The event has asrc
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:52var 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