initial $stateParams empty? - angularjs

Plunker:
I am using UI-Router for a simple single page application. It is a just a table that you can sort and filter. When you apply a filter, like ordering a column in ascending order, the URL updates to something like:
www.domain.com#/column/'column name'/desc/false/
I then grab the paramters using $stateParams, and update the table accordingly.
$scope.$on('$stateChangeSuccess', function (evt, toState, toParams, fromState, fromParams) {
$scope.sorting.predicate = toParams.column;
$scope.sorting.reverse = boolVal(toParams.sort);
});
However, if I were to visit www.domain.com#/column/'column name'/desc/false/,
the table doesn't load with the data filtered. I am trying the following (after injecting $stateParams to my controller):
$scope.$on('$viewContentLoaded', function (event, viewConfig) {
console.log('VCL stateParams: ' + angular.toJson($stateParams));
});
However, stateParams is always empty regardless of the URL (only on viewContentLoaded). I can't seem to get the parameters of the URL on page load. Am I doing something incorrectly?
Here is the state config:
app.config(['$stateProvider', '$urlRouterProvider',
function ($stateProvider, $urlRouterProvider) {
$stateProvider.state("name", {
url: '/column/:column/desc/:sort/',
controller: 'Ctrl',
resolve: {
logSomeParams: ['$stateParams', '$state', function ($stateParams, $state) {
console.log($stateParams);
console.log(this); // this is the state you transitioned From.
console.log($state); // this is the state you transitioned To.
}]
}
});
$urlRouterProvider.otherwise('/');
}
]);
Here is how the state change is called:
<a ui-sref="name({column:'\''+column+'\'',sort:sorting.reverse})"
ng-click="sorting.predicate = '\'' + column + '\''; sorting.reverse=!sorting.reverse;">
{{column}}</a>

Here's a few options I'd investigate further.
Option 1: $rootScope listener
$scope.$root.$on('$stateChangeSuccess', function (evt, toState, toParams, fromState, fromParams) {
$scope.sorting.predicate = toParams.column;
$scope.sorting.reverse = boolVal(toParams.sort);
});
$scope.$root.$on('$viewContentLoaded', function (event, viewConfig) {
console.log('VCL stateParams: ' + angular.toJson($stateParams));
});
Option 2: Resolve objects
In your state definition, try to add this:
resolve: {
logSomeParams: ['$stateParams', '$state', function ($stateParams, $state) {
console.log($stateParams);
console.log(this); // this is the state you transitioned From.
console.log($state); // this is the state you transitioned To.
}]
}
Please give either of those a go and let me know what results you get.
The resolve object should run prior to $viewContentLoaded, but since all you are really interested in are the stateParams in your $viewContentLoaded callback, might aswell put it in the state definition.
Good luck,
Kasper.
Edit:
Try giving your state a parent state with the resolve object.
Like this:
$stateProvider.state('parentState', {
url: '',
abstract: true,
resolve: {
logSomeParams: ['$stateParams', '$state', function ($stateParams, $state) {
console.log($stateParams);
console.log(this); // this is the state you transitioned From.
console.log($state); // this is the state you transitioned To.
}]
}
});
$stateProvider.state("name", {
url: '/column/:column/desc/:sort/',
parent: 'parentState',
controller: 'Ctrl'
});
Let me know how that works out for ya.

Figured it out, quite unfortunate how simple the answer was. I needed to inject $state. I only injected $stateParams. You need both. Hope this saves someone some hair pulling and screaming.

Related

Angularjs ui-router 404 not evaluating

The scenario is rather simple I have a local site that uses angular. I have my state provider set up us ui router lib.
If I type in http://localhost.com/#/lwejfpwef it will redirect me properly to my other wise clause to the state '/login'.
However I tried typing in http://localhost.com/lwjpoifwef it doesn't fire off any of the events that I have in my module config.
I have tried
$stateChangeSuccess
$stateChangeStart
$stateChangeError
$httpinterceptors
I'm not sure what I am doing wrong. It doesn't seem to hit any of the break points I put in there. Here is a snippet of what I have
angular.module('app').run(['$rootScope', '$state', 'service', function ($rootScope, $state, service) {
$rootScope.$on('$stateChangeSuccess', function (evt, to, params) {
alert('success');
});
$rootScope.$on('$stateChangeStart', function (event, to, params) {
alert('start');
});
$rootScope.$on('$stateChangeError', function (evt, toState, toParams, fromState, fromParams, error) {
$state.go('login');
});
}]);
angular.module('dealer-portal.core').config(CoreConfig);
function CoreConfig($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'wwwroot/app/login/login.html',
data: {
displayName: 'Login'
}
})
.state('home', {
url: '/home',
templateUrl: 'wwwroot/app/login/login.html',
data: {
displayName: 'Home'
}
})
.state('error', {
url: '/login'
});
$urlRouterProvider.otherwise('/login');
}
$state.go should have the state name and not the url passed in
$state.go('login');
and NOT
$state.go('/login');
Also, you need to inject $stateParams in your run function

Capturing and using URL in angular UI-router

I have a state:
.state('series', {
url: '/{series}/',
template: '<div configurator-list></div>',
resolve: {
stateService: 'ConfiguratorStateService'
},
params: {
series: '{series}'
},
controller: 'ConfiguratorListController',
ncyBreadcrumb: {
label: '{series}',
parent: 'home'
}
});
I'd like to use actual value for {series} that is in the URL to update a few things. I'm lost and haven't had any luck searching. Everything takes me to the UI-router page, but I don't see any concrete examples there.
You need to listen for any of the UI-Router state change events and use the parameters from that function to obtain it. Add a listener in upon your app run (substitute app name for 'myApp') which is detailed below...
(function() {
angular.module('myApp')
.run(runOptions);
runOptions.$inject = ['$rootScope', '$state'];
function runOptions($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if (toState.name === 'series') {
//output the parameter here... since the series parameter is actually the string of the url, use the url property
console.log(toState.url);
}
});
}
})();
There are other state change events you can use as well, depending on your intended use: https://github.com/angular-ui/ui-router/wiki#state-change-events
OR
What sounds more relevant with further reading of your question, modify your route definition...
Change url: '/{series}/' to '/:series'
Then, in your controller....
angular.controller('ConfiguratorListController', function($stateParams) {
var vm = this;
vm.series = $stateParams.series;
}

inject resolve into toParams on $stateChangeStart

I have a config file which contains a state that looks like the following:
$stateProvider.state('home', {
url: '?data',
abstract: true,
resolve: {
data: ['MyModel', '$stateParams', function (MyModel, $stateParams) {
return MyModel.getData($stateParams);
}]
}
});
and then a module file that looks like this:
App.module.run(['$rootScope', '$state', function ($rootScope, $state) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
where toParams would return object{data:undefined}. I know that the resolve works and should have data. How do I correctly pass the resolve from my state into the $stateChangeStart and then access it?
I have tried injecting my data resolve manually into my module file, but it returns undefined. I have tried setting the params attribute to see if that was the way to go:
resolve: {
data: ['MyModel', '$stateParams', function (MyModel, $stateParams) {
return MyModel.getData($stateParams);
}]
},
params: {
'foo':'bar', // this would be available in toParams
'data': //can i put my data here?
}
You should simply be able to inject MyModel into your run function, and read it the same way you read it inside your resolve process. Example run function (assumes your getData function returns a promise):
App.module.run(function($rootScope, MyModel) {
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
// get the same data your resolve is using (you can also pass in toParams or the like)
MyModel.getData(toParams).then(function(data){
// do something with your data here inside $stateChangeStart
});
});
});
This is what makes injection great, you simply inject something when you want to use it.

AngularJS: Get previous url (path) from page

I have a question: When I'm in a page I want return to previous page. I use the $routeProvider. How can I read the previous url?
I try to use this code in my controller but doesn't work...
angular.module.controller('myController',
function($scope, $routeParams, $http, $location, $rootScope) {
$rootScope.$on("$routeChangeSuccess",
function (event, current, previous, rejection) {
console.log(previous);
$location.path('PREVIOUS PATH');
});
});
How can I read the previous path? Thanks!
I am not fully sure, what you want to achieve. So I would suggest, check this before you go your own way:
How to implement history.back() in angular.js
But, in case, you want to know how to keep the last state with angular and UI-Router, we can do it with a service. There is some naive implementation tracking just last state (not challenging the history.back())
Check the working example
Service definition:
.factory('PreviousState', ['$rootScope', '$state',
function ($rootScope, $state) {
var lastHref = "/home",
lastStateName = "home",
lastParams = {};
$rootScope.$on("$stateChangeSuccess", function (event, toState, toParams
, fromState, fromParams) {
lastStateName = fromState.name;
lastParams = fromParams;
lastHref = $state.href(lastStateName, lastParams)
})
return {
getLastHref: function (){ return lastHref ; },
goToLastState: function (){ return $state.go(lastStateName, lastParams); },
}
}])
So we just do listen the $stateChangeSuccess and keep the track of last state name and its $stateParams.
We can inject our service to all scopes:
.run(['$rootScope', 'PreviousState',
function ($rootScope, PreviousState) {
$rootScope.PreviousState = PreviousState;
}])
And we can use it as a click or href:
<button ng-click="PreviousState.goToLastState()">go back</button>
<a ng-href="#{{PreviousState.getLastHref()}}" > go to last href</a>
Check that in action here

Need to catch ui.router state and its url when the url changes

I wish to attach a listener to URL changes in the ui.router module I use in an AngularJS app, because I need to get the new state and its url when the url changes. In order to customize the url change listener, I've done the following, but it's not working (yet):
in the config section of ui.router, I added this line:
$urlRouterProvider.deferIntercept();
and after the config(), I have the following code, hoping to cactch the ui.router's state and its url
config(
//ui.router's config ommitted....
).run(function($rootScope, $urlRouter) {
$rootScope.$on('$locationChangeSuccess', function(e) {
console.log(e);
e.preventDefault(); //prevent the default handler
$urlRouter.sync(); //once the interception is done, sync the current url
$urlRouter.listen();
})
});
I am not sure if this is possible to do with ui.router. Or there is a much easier way to get the state and its url?
I am not 100% sure what is the real requirement behind. But with UI-Router, we should use $stateChangeStart event I'd say.
There is an example, a working plunker
$rootScope.$on('$stateChangeStart', function (event, toState, toParams
, fromState, fromParams)
{
console.log(event)
console.log(toState)
console.log(toParams)
console.log(fromState)
console.log(fromParams)
console.log(toState)
console.log($location.url())
});
Check it here
The $urlRouter and its .deferIntercept() and .listen() or more useful for declaring states in a .run() phase
// config
.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProviderRef = $stateProvider;
$urlRouterProvider.otherwise('/home');
$urlRouterProvider.deferIntercept();
// run
.run(['$rootScope', '$urlRouter',
function($rootScope, $urlRouter) {
$stateProviderRef
.state('home', {
url: "/home",
templateUrl: 'tpl.html',
})
$urlRouter.listen();
}
]);

Resources