如何在控制器中修改指令隔离范围变量,同时仍然保持隔离?
How to modify directives isolated scope variable in controller, while still keeping it isolated?
我有一个独立作用域的指令。我正在修改指令控制器中从父控制器传递的变量之一。我 运行 遇到的问题是,当我在同一视图上使用此指令的多个实例(具有不同的 options
和 model
)时,options
对象不会对指令的每个实例保持唯一。相反,它成为一个共享变量,指令的所有实例都使用相同的 options
对象。
所以如果我像下面这样在我的视图中使用它们,optionsA.isFlagOn = true
和 optionsB.isFlagOn = false
<my-directive model="modelA" options="optionsA">
<my-directive model="modelB" options="optionsB">
带有 modelB
的指令加载 optionsA
。
如何在为每个特定实例修改它时保持 options
唯一性?
angular.module('myModule', [])
.directive('myDirective', function($compile) {
template = '<h3><span ng-bind="model.title"><h3><p><span ng-bind="options"></span></p>';
return {
restrict: 'AE',
scope: {
model: "=",
options: "=?" //A JSON object
},
controller: function($scope) {
$scope.options = $scope.options || {};
//A function that sets default values if no options object passed
ensureDefaultOptions($scope);
//now based on some of the options passed in, I modify a property in the options object
if ($scope.options.isFlagOn)
$scope.options.thisProp = true;
},
link: function(scope, element, attr) {
let content = $compile(template)(scope);
element.append(content);
}
};
}
编辑: 我解决了我的问题。我的解决方案发布在下面的答案中。
你能把它改成你的单向绑定吗:
scope: {
model: "=",
options: "<?" //A JSON object
}
你的指令应该复制传入的选项和默认值,这样每个指令实例都有自己的选项对象。
您可以使用 extend
轻松实现
var defaultOptions = { a:1, b:2, c:3 };
var options = angular.extend(defaultOption, $scope.options);
// then use options everywhere
请注意,这只会在初始化期间执行一次,因此如果您的选项异步来自控制器,则需要额外处理。
我使用 1.4x 或更高版本中可用的 Angular 指令的 bindToController 属性 解决了这个问题。
angular.module('myModule', [])
.directive('myDirective', function($compile) {
template = '<h3><span ng-bind="vm.model.title"><h3><p><span ng-bind="myOptions"></span></p>';
return {
restrict: 'AE',
bindToController: {
model: "=",
options: "=?" //A JSON object
},
scope: {},
controller: function() {
var vm = this;
//a function that handles modifying options
vm.setOptions = function(options){
let newOptions = {};
angular.copy(options, newOptions);
// modify newOptions here
return newOptions;
}
},
controllerAs: 'vm',
link: function(scope, element, attr) {
ensureDefaultOptions(scope.vm);
scope.myOptions = scope.vm.setOptions(scope.vm.options);
let content = $compile(template)(scope);
element.append(content);
}
};
});
我有一个独立作用域的指令。我正在修改指令控制器中从父控制器传递的变量之一。我 运行 遇到的问题是,当我在同一视图上使用此指令的多个实例(具有不同的 options
和 model
)时,options
对象不会对指令的每个实例保持唯一。相反,它成为一个共享变量,指令的所有实例都使用相同的 options
对象。
所以如果我像下面这样在我的视图中使用它们,optionsA.isFlagOn = true
和 optionsB.isFlagOn = false
<my-directive model="modelA" options="optionsA">
<my-directive model="modelB" options="optionsB">
带有 modelB
的指令加载 optionsA
。
如何在为每个特定实例修改它时保持 options
唯一性?
angular.module('myModule', [])
.directive('myDirective', function($compile) {
template = '<h3><span ng-bind="model.title"><h3><p><span ng-bind="options"></span></p>';
return {
restrict: 'AE',
scope: {
model: "=",
options: "=?" //A JSON object
},
controller: function($scope) {
$scope.options = $scope.options || {};
//A function that sets default values if no options object passed
ensureDefaultOptions($scope);
//now based on some of the options passed in, I modify a property in the options object
if ($scope.options.isFlagOn)
$scope.options.thisProp = true;
},
link: function(scope, element, attr) {
let content = $compile(template)(scope);
element.append(content);
}
};
}
编辑: 我解决了我的问题。我的解决方案发布在下面的答案中。
你能把它改成你的单向绑定吗:
scope: {
model: "=",
options: "<?" //A JSON object
}
你的指令应该复制传入的选项和默认值,这样每个指令实例都有自己的选项对象。
您可以使用 extend
var defaultOptions = { a:1, b:2, c:3 };
var options = angular.extend(defaultOption, $scope.options);
// then use options everywhere
请注意,这只会在初始化期间执行一次,因此如果您的选项异步来自控制器,则需要额外处理。
我使用 1.4x 或更高版本中可用的 Angular 指令的 bindToController 属性 解决了这个问题。
angular.module('myModule', [])
.directive('myDirective', function($compile) {
template = '<h3><span ng-bind="vm.model.title"><h3><p><span ng-bind="myOptions"></span></p>';
return {
restrict: 'AE',
bindToController: {
model: "=",
options: "=?" //A JSON object
},
scope: {},
controller: function() {
var vm = this;
//a function that handles modifying options
vm.setOptions = function(options){
let newOptions = {};
angular.copy(options, newOptions);
// modify newOptions here
return newOptions;
}
},
controllerAs: 'vm',
link: function(scope, element, attr) {
ensureDefaultOptions(scope.vm);
scope.myOptions = scope.vm.setOptions(scope.vm.options);
let content = $compile(template)(scope);
element.append(content);
}
};
});