0

My application has two controllers. I have a pageCtrlwhich I use to handle my navigation and sidebar. I also have a calendarCtrl for handling the data on my page. This controller is configured as shown below:

$stateProvider
  .state('calendar', {
    url: '/calendar/:category/:competition/:team',
    controller: 'calendarCtrl',
    templateUrl: 'app/modules/calendar/calendarView.html',
  })

To make my navigation work I also need access to the :category/:competition/:team-params in my pageCtrl. Can I configure this using the same way? Something like:

$stateProvider
  .state("page", {
   abstract: true,
   controller: 'pageCtrl',
   // params: :category/:competition/:team
})

Edit: Using $stateParams in the calendarCtrl works fine. I just can't figure out how I can make sure my pageCtrl also can get read the url.

Thijs
  • 3,015
  • 4
  • 29
  • 54
  • This is against the principle http://stackoverflow.com/a/24306250/1679310. It cannot be achieved (without hacking the UI-Router architecture) ... sorry for not having The Answer ;( – Radim Köhler May 19 '15 at 05:59
  • So it is not possible to read the url parameters from 2 different controllers at the same time? Is there a 'ui-router'-way of doing something alike? – Thijs May 19 '15 at 06:41
  • 1
    I would say, that you should change the approach. Really. There is a solution, but in a totally different approach. We would move the stuff you need on a parent to be consuming params... into child state. Give me sec, I will try to show you – Radim Köhler May 19 '15 at 06:46
  • Comment is not enough, I created a plunker(s) to show the way, which I believe is what the UI-Router founders placed in there for us.. Hope it helps a bit – Radim Köhler May 19 '15 at 07:07

3 Answers3

2

Since you're using ui.router, inject $stateParams in your controller(s) and then you can access those values like so:

controller.js

function($stateParams){

$stateParams.category
$stateParams.competition
$stateParams.team
jusopi
  • 6,791
  • 2
  • 33
  • 44
  • the `$stateParams`-variable is empty when I inject it. – Thijs May 18 '15 at 18:11
  • are you sure you're currently within the `calendar` state or a child state of the `page` state? – jusopi May 18 '15 at 18:17
  • @Thijs How do you know? Try console.log($stateParams). – Michelangelo May 18 '15 at 18:17
  • My url is `/#/calendar/SH/8/2059` so I'm currently in my `calendarCtrl`. I've put a breakpoint in my `pageCtrl`to view the `$stateParams` and it's empty. – Thijs May 18 '15 at 18:19
  • I also tried using `$state` but this variable is also empty. – Thijs May 18 '15 at 19:22
  • `$state` only provides your APIs to your current state objects defined in your original code. I'd suggest making a jsFiddle for this so we can try to help solve it with code. – jusopi May 19 '15 at 16:37
0

My suggestion would be - use more views - the UI-Router built feature.

Multiple Named Views

There is a working plunker

Let's have the 'Parent' state which has this template:

This blue is the parent template. Orange are child views

<!-- HERE is one named view target -->
<div ui-view="title">This is a title filled by child having access to param</div>

  ...  

<!-- HERE is other view target un-named -->
<div ui-view></div>

And its state is very simple. The interesting is the child state, which is taking care about both views:

  .state('parent', {
      abstract: true,
      url: "/parent",
      templateUrl: 'tpl.parent.html',
  })
  .state('parent.child', { 
      url: "/child/:id",
      views : {
        '': {
          templateUrl: 'tpl.child.html',
        },
        'title': {
          templateUrl: 'tpl.title.html',
          controller: 'TitleCtrl',
        },
      }
  })

So, we do have a target for "some other view" title or side bar. Check it here

And we can even place some default implementation there inside of our "non-abstract" parent state.

There is extended plunker with non abstract parent state definition:

  .state('parent', {
      url: "/parent",
      views : {
        '': {
          templateUrl: 'tpl.parent.html',
        },
        'title@parent': {
          template: 'the parent own TITLE',
        },
      }
  })

Check it here

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • The example you've given let child views use the parameters. I'm trying to read the parameters in the parent view. – Thijs May 19 '15 at 18:05
  • I respect that you do not like it. If I could, I would at least ask you to evaluate again if you cannot use this. My second answer does show some way how to go arround... but I would prefer this approach – Radim Köhler May 20 '15 at 06:10
0

There is a way, how to grant access to latest/up-to-date $stateParams - including current state and its child(ren) as well. (working example here)

It is surprisingly easy:

.run(['$rootScope', '$state', '$stateParams',
  function ($rootScope, $state, $stateParams) {
    $rootScope.$state = $state;
    $rootScope.$stateParams = $stateParams;
}])

And that's it. (check similar answer and some discussion here)

With this approach, we will even in parent $scopes have updated reference to the latest $stateParams. While in our own, we will still receive just our own part

.controller('ParentCtrl', ['$scope', '$stateParams', function ($scope, $stateParams) {
  $scope.currentStateParams = $stateParams;
}])

The above is valid for states like these:

.state('parent', {
  url: "/parent?area",
  templateUrl: 'tpl.html',
  controller: 'ParentCtrl',
})
.state('parent.child', { 
  url: "/child/:id",
  templateUrl: 'tpl.html',
  controller: 'ChildCtrl',
})

Working example to play here.

But I still would say, that this is a bit ... against the UI-Router. I would prefer this answer. Because in that case, each view (while injected into some parent area) is really aware about $stateParams, which belongs to that state. What we are doing here is introduction of some observer pattern (we should watch changes if we want to react in parent) and that would later bring more issues then profit

Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335