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"
})
::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;
}
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.