Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Named view in angular ui-router not updating, despite being watched

I have a scoped variable $scope.foo that I am keeping a watch on. It could be updated through a text field in a form.

I have two named views A and B on a page that I am rendering using angular ui-router. The named view A has the text form field that is being watched for changes in a controller through ng-model="foo". When the value of foo is changed by a user it changes the value of another scoped variable $scope.bar, which is an array, in the controller that is being used in the ng-repeat directive on the named view B. The changes in the $scope.bar is made using $scope.$watch method in the controller.

The issue that I am facing is that the when the foo is changed I could see the changes in bar on the named view A but not on the named view B.

Could somebody help me resolve this issue?

Edit: Here is the plunker for this issue.

like image 459
skip Avatar asked Feb 12 '23 05:02

skip


1 Answers

There is a plunker, which should show that your scenario is working.

The most important part of that solution is driven by:

  • Scope Inheritance by View Hierarchy Only (cite:)

Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).

It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.

Let me express it again: A scope inheritance goes only via the view nesting.

With that we can create this states definitions:

$stateProvider
    .state('root', { 
        url: '/root',
        templateUrl: 'tpl.root.html',
        controller: 'RootCtrl',            // this root scope will be parent
    })
    .state('root.entity', {
        url: '/entity',
        views:{
            'A': {
                templateUrl: 'tpl.a.html',
                controller: 'ACtrl',        // scope is inherited from Root
            },
            'B': {
                templateUrl: 'tpl.b.html',
                controller: 'ACtrl',        // scope is inherited from Root
            }
        }
    })

So the state defintion support nested views - let's profit from that and place the $scope.bar collection into the parent. All views involved will then have access to the same collection:

.controller('RootCtrl', function ($scope, $state) {
  $scope.bar = ['first', 'second', 'last'];

})
.controller('ACtrl', function ($scope, $state) {
  // *) note below
  $scope.foo = $scope.bar[0];
  $scope.$watch("foo", function(val){$scope.bar[0] = val; });
})
.controller('BCtrl', function ($scope, $state) {

})

*) note: here we do 1) set from bar 2) $watch and 3) set back to bar to follow the question description... but if the array would contain objects, we can work with them directly... without that overhead, but that's another story...

Check here how that works, and that any changes in view A are also visible in B ... because of inherited reference to the array bar declared in parent $scope.

like image 123
Radim Köhler Avatar answered Feb 15 '23 10:02

Radim Köhler