我无法理解为什么对ngModel的更改不会从一个指令传播到另一个指令。 Here's a plunker that shows a simplified version of what we're trying to do
基本上,我已经声明了一个使用ngModel和一个隔离范围的指令:
.directive('echo', function() {
var link = function(scope, element, attrs, ngModel) {
// --- 8< ---
scope.$watch(attrs['ngModel'], function() {
scope.model = ngModel.$modelValue;
console.log("***** Echo model updated: ", scope.model);
});
};
return {
restrict: 'E',
require: 'ngModel',
link: link,
scope: {
id: "="
}
}
})
然后该指令被另一个指令包装,同时依赖于ngModel和一个隔离范围:
.directive('wrapper', function() {
var link = function(scope, element, attrs, ngModel) {
scope.$watch(attrs['ngModel'], function() {
var model = ngModel.$modelValue;
console.log("----- Wrapper model updated", model);
scope.model = model;
})
};
return {
restrict: 'E',
require: 'ngModel',
link: link,
scope: {
},
template: "<div><h2>Echo:</h2> <echo id='myEcho' ng-model='model'></echo></div><div><h2>Model text:</h2>{{ model.text }}</div>"
}
})
您可以看到“包装器”指令需要ngModel
,echo
指令也是如此。
当我在HTML中使用“wrapper”指令,然后我将值推入ngModel时,“wrapper”指令正确识别模型已更改(console.log显示了这一点)。此时,包装器指令然后更新其范围的模型,我将期望将该模型更新传播到“echo”指令。
但是,观看控制台时,“echo”指令永远不会看到模型得到更新。
问:为什么“echo”指令不能从“wrapper”指令中看到更新的模型?
注意:由于“echo”不是仅从“wrapper”指令消耗的事实,这可能会稍微复杂一些 - 有时会直接使用它。
答案 0 :(得分:2)
更新回答:
不,这个问题与时间无关 - 无论是在观看值设定之前还是之后添加,手表仍然会发光。
我建议在你的echo
指令中添加一些断点,然后逐步查看观察者的设置方式。
这是一个正在运行的更新的plunker:http://plnkr.co/edit/bbv2vpZ7KaDiblVcoaNX?p=preview
.directive('echo', function() {
var link = function(scope, element, attrs, ngModel) {
console.log("***** Linking echo");
var render = function (val) {
var htmlText = val || 'n/t';
element.html(htmlText);
};
scope.$watch("model.text", render);
};
return {
restrict: 'E',
link: link,
scope: {
id: "=",
model: '=echoModel'
}
}
})
.directive('wrapper', function() {
var link = function(scope, element, attrs, ngModel) {
console.log("---- Linking Wrapper");
};
return {
restrict: 'E',
require: 'ngModel',
link: link,
scope: {
wrapperModel: '=ngModel'
},
template: "<div><h2>Echo:</h2> <echo id='myEcho' echo-model='wrapperModel'></echo></div><div><h2>Model text:</h2>{{ wrapperModel.text }}</div>"
}
})
它不起作用的原因是因为attrs
和观察者的工作方式可能有点出乎意料。
基本上,您尝试在示波器上查看scope.model
属性,而不是您所期望的ngModel
属性的评估值:
.directive('echo', function() {
var link = function(scope, element, attrs, ngModel) {
// Your HTML is `<echo ng-model='model'></echo>`
// which means this `scopePropertyToWatch` will have the value 'model'.
var scopePropertyToWatch = attrs['ngModel'];
// This means it will try to watch the value
// of `scope.model`, which isn't right because
// it hasn't been set.
scope.$watch(scopePropertyToWatch, function() {
scope.model = ngModel.$modelValue;
console.log("***** Echo model updated: ", scope.model);
});
};
// ...
})
有两个简单的解决方案。
<强> 1。在ngModel
属性上设置双向绑定:
.directive('echo', function() {
var link = function(scope, element, attrs, ngModelCtrl) {
// Watch the `scope.ngModel` property on the scope.
// NOT the attr['ngModel'] value which will still
// be 'model'.
scope.$watch('ngModel', function() {
scope.model = ngModelCtrl.$modelValue;
console.log("***** Echo model updated: ", scope.model);
});
};
return {
restrict: 'E',
require: 'ngModel',
link: link,
scope: {
id: "=",
ngModel: "=" // This will make the `ngModel` property available on the scope.
}
}
});
使用ngModel
方式有点复杂 - 我建议您查看有关如何在自定义组件中使用ngModel的视频:Jason Aden - Using ngModelController to Make Sexy Custom Components
<强> 2。在$ parent范围内观察该属性:
.directive('echo', function() {
var link = function(scope, element, attrs, ngModelCtrl) {
// Add a watch on the **parent** scope for the attribute value.
// NOTE that we use the attrs['ngModel'] value because the property
// on the parent scope **is**: `scope.$parent.model`
scope.$parent.$watch(attrs['ngModel'], function() {
scope.model = ngModelCtrl.$modelValue;
console.log("***** Echo model updated: ", scope.model);
});
};
return {
restrict: 'E',
require: 'ngModel',
link: link,
scope: {
id: "="
}
}
});
同样,使用ngModelCtrl.$modelValue
可能会有点复杂,但至少会让你的观察者开火。