在我的示例代码中,我有两个我无法理解的行为,我希望你们可以告诉我发生了什么以及我做错了什么:
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>
答案 0 :(得分:0)
如果对ngModel指令的源代码更深入,我们可以找到使用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" });
}
});
&#13;
<!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>
&#13;
下一个变体:您可以添加自己的$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"
});
}
});
&#13;
<!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>
&#13;