0
votes

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>
2
Can you reproduce with a plunkr? Edit: I ask because I don't see anything obviously wrong. - Christopher Gillis
Yes, I will get right on that. I think something else in my code is breaking. - Josue Espinosa
What's going on with all those single quotes and slashes in your ui-sref? Seems like you have some mis-matched quotes, and the slashes really aren't necessary. Can't you just do: ui-sref="name(column: column, sort: sort:sorting.reverse})" Also, the ng-click changes values of the parameters that are fed to the ui-sref -- how do you know which one happens first? - Sunil D.
Excellent observations! The quotes are because the SQL guy has columns with spaces, so without quotes it causes problems. as far as the ng-click/ui-sref, valid point. I'm actually not sure. I would assume ng-click because after the initial load everything works. - Josue Espinosa
Ah makes perfect sense, don't know why I didn't read them as backslash escaped characters :) And since it works as expected, I would guess that the ng-click directive has a higher priority than ui-sref. - Sunil D.

2 Answers

1
votes

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.

1
votes

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.