【问题标题】:Named view in angular ui-router not updating, despite being watched尽管正在观看,但角度 ui-router 中的命名视图未更新
【发布时间】:2014-08-21 04:45:13
【问题描述】:

我有一个作用域变量$scope.foo,我正在密切关注。它可以通过表单中的文本字段进行更新。

我在使用 Angular ui-router 渲染的页面上有两个命名视图 AB。 命名视图A 具有文本表单字段,通过ng-model="foo" 监视控制器中的更改。当foo 的值被用户更改时,它会更改控制器中另一个作用域变量$scope.bar 的值,该变量是一个数组,该控制器在命名视图ng-repeat 指令中使用B$scope.bar 中的更改是使用控制器中的$scope.$watch 方法进行的。

我面临的问题是,当 foo 更改时,我可以在命名视图 A 上看到 bar 的更改,但 不是 在命名视图B

有人可以帮我解决这个问题吗?

编辑Here 是这个问题的 plunker。

【问题讨论】:

标签: javascript angularjs angularjs-scope angularjs-ng-repeat angular-ui-router


【解决方案1】:

有一个plunker,应该表明您的方案正在运行。

该解决方案最重要的部分是:

请记住,如果您的状态的视图是嵌套的,范围属性只会沿状态链继承。 范围属性的继承与状态的嵌套无关,与视图(模板)的嵌套有关。

您完全有可能拥有嵌套状态,其模板在您的站点内的各种非嵌套位置填充 ui-views。 在这种情况下,您不能期望在子状态视图中访问父状态视图的范围变量。

让我再说一遍:scope 继承只能通过 view 嵌套

这样我们可以创建这个状态定义:

$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
            }
        }
    })

所以状态定义支持嵌套视图 - 让我们从中获利并将 $scope.bar 集合放入父集合。然后所有涉及的视图都可以访问同一个集合:

.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) {

})

*) 注意:这里我们做 1) 从 bar 设置 2) $watch 和 3) 设置回 bar 以遵循问题描述...但是如果数组包含对象,我们可以直接使用它们.. . 没有那个开销,但那是另一回事了......

检查here 是如何工作的,并且视图 A 中的任何更改在 B 中也是可见的......因为对数组 的继承引用bar 在父 $scope 中声明。

【讨论】:

  • 你好 Radim,这里 plnkr.co/edit/y7BMdyRhj2WvFXq0UUud?p=preview 是我为我所面临的问题创建的 plunker。
  • 谢谢,我正在创建 plunker,所以还不能回答。现在正在做。
  • 我决定创建新的答案,因为它的内容更加复杂和不同,不适合编辑。希望这有帮助。 ui-router 是一个很棒的库 ;) 享受它
  • 有时文档会掩盖本质并描绘未使用或很少使用的内容。很好的解释,所有广泛使用ui-router的人都必须阅读。
【解决方案2】:

我创建了第二个答案, 也是为了关注这个 plunker 中的问题,@skip (OP) 将它作为问题的示例传递给我。

首先有一个更新的工作version

plunker,它满足了我们的需求。主要变化如下:

statedef:

.state('home', {
            url: '/',
            views: {

                '': { templateUrl: 'home.html' },

                'A@home': {
                    templateUrl: 'a.html',
                    controller: 'MainCtrl'
                },

                'B@home': {
                    templateUrl: 'b.html',
                    controller: 'MainCtrl'
                }
            }

已替换为 RootCtrl 定义:

.state('home', {
            url: '/',
            views: {

                '': { 
                  templateUrl: 'home.html', 
                  controller: 'RootCtrl' // here we do use parent scoping
                },

                'A@home': {
                    templateUrl: 'a.html',
                    controller: 'MainCtrl'
                },

                'B@home': {
                    templateUrl: 'b.html',
                    controller: 'MainCtrl'
                }
            }

这是一个控制器:

app.controller('MainCtrl', function($scope) {
  var fruits = [{"name": "Apple"}, {"name": "Banana"}, {"name": "Carrot"}];

  $scope.bar =  $scope.bar || []; 

  $scope.foo = 2;

  $scope.$watch('foo',function(value, oldValue){
      $scope.bar = [];
      getBar(fruits, value);
  });

  function getBar(fruits, howManyFruits) {
    for(var i=0; i < $scope.foo; i++) {
        $scope.bar.push(fruits[i]);
    }
  }

});

但现在我们确实有两个(父母和孩子):

app.controller('RootCtrl', function($scope) { 
  $scope.bar = []; 
})
app.controller('MainCtrl', function($scope) {
  var fruits = [{"name": "Apple"}, {"name": "Banana"}, {"name": "Carrot"}];

  //$scope.bar =  $scope.bar || []; 

  $scope.foo = 2;

  $scope.$watch('foo',function(value, oldValue){
      $scope.bar.length = 0;
      getBar(fruits, value);
  });

  function getBar(fruits, howManyFruits) {
    for(var i=0; i < $scope.foo; i++) {
        $scope.bar.push(fruits[i]);
    }
  }

});

需要提及的一些重要部分

我。最小公分母

我们必须将共享集合(数组栏)​​移动到父集合中。为什么?

我们必须将共享引用移动到最小公分母 - 到父范围

二。对数组的引用必须保持不变

我们必须保持对$scope.bar 的引用不变!。这是必不可少的。如何做到这一点?见:

我们没有创建新的引用,而是清除数组,保留对它的引用

// wrong
$scope.bar = [];
// good
$scope.bar.length = 0;

三。控制器可以有多个实例

另外,两个视图 AB 具有相同的控制器 (实际上是相同的控制器名称),这绝对不意味着,他们是同一个实例。

,它们是两个不同的实例……不共享任何东西。我猜,这是最关键的困惑。见

控制器的特殊之处在于,与服务不同,应用程序中可以有它们的许多实例。例如,模板中的每个 ng-controller 指令都有一个实例。

请注意updated example中的所有内容

【讨论】:

  • 很高兴见到这位先生! ui-router 太棒了 ;)
  • 这是一篇旧帖子...但我想知道...在示例中,您是否甚至需要MainCtrl 或者您是否可以只拥有根并使用$parent 的东西在视图中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多