在我的示例代码中,我有两种我无法真正理解的行为,我希望你们能够启发我发生了什么以及我做错了什么:
- 我在指令数组到字符串中有一个格式化程序,它只是 在初始化过程中被调用。当我更新 我的 Controller 中的数组带有推送功能,格式化程序不是 被调用。这是为什么?我能做些什么来克服这个问题?
- 在数组到字符串的格式化函数中,我将数组的值提取到单个字符串中。转换后我返回该字符串。现在为什么 mydir 的 ng-model 没有被更改为数组到字符串的格式化程序返回的值?这对我来说毫无意义,因为 mydir 的格式化程序获取数组到字符串格式化程序的结果(我在 mydir 指令中滥用了格式化程序来显示我认为发生了什么错误)
angular.module("app", []);
angular.module("app").directive("arrayToString", function() {
return {
restrict: "A",
require: "?ngModel",
link: function(scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(array) {
console.log("formatter called");
var text = "";
angular.forEach(array, function(e) {
text += e.label + ", ";
});
text = text.substring(0, text.length - 2);
console.log(text);
return text;
});
}
};
});
angular.module("app").directive("mydir", function() {
return {
restrict: "E",
scope: {
ngModel: "="
},
require: "?ngModel",
link: function(scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(alreadyFormattedValue) {
scope.myString = alreadyFormattedValue;
});
},
template: "<div>{{myString}}</div><div>{{ngModel}}</div>"
}
});
angular.module("app").controller("Controller", function() {
var _this = this;
_this.myValues = [
{ label: "apple" },
{ label: "lemon" },
{ label: "pear" }
];
_this.add = function() {
_this.myValues.push({ label: "strawberry" });
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8" data-require="angular.js@1.3.20"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="Controller as ctrl">
<mydir ng-model="ctrl.myValues" array-to-string=""></mydir>
<button type="button" ng-click="ctrl.add()">Add</button>
</body>
</html>
最佳答案
如果深入了解 ngModel 指令的源代码,我们可以发现对于 watch 使用 custom function 。在此函数中存在 if
和下一个条件。
if (modelValue !== ctrl.$modelValue &&
// checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
(ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
)
因此,modelValue
只是与 !==
进行比较,如果引用未更改,则 viewValue 既不会应用格式化程序,也不会应用验证程序。
最简单的方法 - 只需更改引用,即使用,例如 concat函数 push .
_this.myValues = _this.myValues.concat({ label: "strawberry" });
示例
angular.module("app", []);
angular.module("app").directive("arrayToString", function() {
return {
restrict: "A",
require: "?ngModel",
link: function(scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(array) {
console.log("formatter called");
var text = "";
angular.forEach(array, function(e) {
text += e.label + ", ";
});
text = text.substring(0, text.length - 2);
console.log(text);
return text;
});
}
};
});
angular.module("app").directive("mydir", function() {
return {
restrict: "E",
scope: {
ngModel: "="
},
require: "?ngModel",
link: function(scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(alreadyFormattedValue) {
scope.myString = alreadyFormattedValue;
});
},
template: "<div>{{myString}}</div><div>{{ngModel}}</div>"
}
});
angular.module("app").controller("Controller", function() {
var _this = this;
_this.myValues = [
{ label: "apple" },
{ label: "lemon" },
{ label: "pear" }
];
_this.add = function() {
_this.myValues = _this.myValues.concat({ label: "strawberry" });
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8" data-require="angular.js@1.3.20"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="Controller as ctrl">
<mydir ng-model="ctrl.myValues" array-to-string=""></mydir>
<button type="button" ng-click="ctrl.add()">Add</button>
</body>
</html>
下一个变体:您可以添加自己的$watch
并手动应用格式化程序
scope.$watchCollection(function() {
return ngModelCtrl.$modelValue;
}, function(n) {
var formatters = ngModelCtrl.$formatters,
idx = formatters.length;
var viewValue = n;
while (idx--) {
viewValue = formatters[idx](viewValue);
}
ngModelCtrl.$setViewValue(viewValue);
});
示例:
angular.module("app", []);
angular.module("app").directive("arrayToString", function() {
return {
restrict: "A",
require: "?ngModel",
link: function(scope, element, attrs, ngModelCtrl) {
scope.$watchCollection(function() {
return ngModelCtrl.$modelValue;
}, function(n) {
var formatters = ngModelCtrl.$formatters,
idx = formatters.length;
var viewValue = n;
while (idx--) {
viewValue = formatters[idx](viewValue);
}
ngModelCtrl.$setViewValue(viewValue);
});
ngModelCtrl.$formatters.push(function(array) {
console.log("formatter called");
var text = "";
angular.forEach(array, function(e) {
text += e.label + ", ";
});
text = text.substring(0, text.length - 2);
console.log(text);
return text;
});
}
};
});
angular.module("app").directive("mydir", function() {
return {
restrict: "E",
scope: {
ngModel: "="
},
require: "?ngModel",
link: function(scope, element, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(alreadyFormattedValue) {
scope.myString = alreadyFormattedValue;
});
},
template: "<div>{{myString}}</div><div>{{ngModel}}</div>"
}
});
angular.module("app").controller("Controller", function() {
var _this = this;
_this.myValues = [{
label: "apple"
}, {
label: "lemon"
}, {
label: "pear"
}];
_this.add = function() {
_this.myValues.push({
label: "strawberry"
});
}
});
<!DOCTYPE html>
<html>
<head>
<script src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8" data-require="angular.js@1.3.20"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body ng-app="app" ng-controller="Controller as ctrl">
<mydir ng-model="ctrl.myValues" array-to-string=""></mydir>
<button type="button" ng-click="ctrl.add()">Add</button>
</body>
</html>
关于javascript - 数组更改时不调用 AngularJs Formatter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34963002/