[英]Named view in angular ui-router not updating, despite being watched
我有一個范圍變量$scope.foo
,我正在監視。 它可以通過表單中的文本字段進行更新。
我在使用angular ui-router渲染的頁面上有兩個命名視圖A
和B
命名視圖A
具有文本表單字段,通過ng-model="foo"
監視控制器中的更改。 當用戶更改foo
的值時,它會在命名視圖B
上的ng-repeat
指令中使用的控制器中更改另一個作用域變量$scope.bar
(這是一個數組)的值。 $scope.bar
的更改是使用控制器中的$scope.$watch
方法進行的。
那我現在面臨的問題是,當foo
改變,我可以看到的變化bar
上的命名視圖A
但不能命名視圖上B
。
有人可以幫我解決這個問題嗎?
編輯 : 這是此問題的plunker。
有一個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)設置從2)$ watch和3)設置回bar以跟隨問題描述...但是如果數組包含對象,我們可以直接使用它們...沒有它開銷,但這是另一個故事......
檢查這是如何工作的,並且視圖A中的任何更改在B ...中也是可見的,因為繼承了對父$ scope中聲明的數組bar
引用。
我創建了第二個答案,也跟着問題在這個plunker ,這@skip(OP)傳給我的FO問題的例子。
那個plunker ,它做我們需要的。 主要變化有:
原始state
def:
.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]);
}
}
});
我們必須將共享集合(數組欄)移動到父集合中。 為什么?
我們必須將共享引用移動到最小公分母 - 到父范圍
看到
我們必須保持對Parent $scope.bar
的引用不變 ! 這很重要。 怎么實現呢? 看到:
而不是創建新的引用,我們清除數組,保持對它的引用
// wrong
$scope.bar = [];
// good
$scope.bar.length = 0;
此外,視圖A和B都具有相同的控制器(實際上是相同的控制器名稱)的事實 ,絕對不是說它們是相同的實例。
不 ,他們是兩個不同的實例......不分享任何東西。 這是我猜,最關鍵的混亂。 看到
控制器的特殊之處在於,與服務不同,應用程序中可能存在許多實例 。 例如,模板中的每個ng-controller指令都會有一個實例。
請在更新的示例中觀察所有內容
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.