javascript Angular $ watch,$ watchCollection,$ attrs。$ observe
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了javascript Angular $ watch,$ watchCollection,$ attrs。$ observe相关的知识,希望对你有一定的参考价值。
//
// ANGULAR ELEMENT
//
// Ampliar: https://docs.angularjs.org/api/ng/function/angular.element
// angular.element acts as the interface between jQuery/jqLite and AngularJS.
// * note that all 'element' references in Angular are always wrapped with jQuery or jqLite; they are never raw DOM references
// ** NEVER USE ANGULAR ELEMENT IN CONTROLLERS (THEY ARE FOR BUSINESS LOGIC) ONLY MANIPULATE DOM IN DIRECTIVES!!!! **
<dumb-password></dumb-password>
//
// dumbpass.html
<div>
<input type="text" ng-model="model.input">
</div>
//
var app = angular.module("app", [])
app.directive("dumbPassword", function () {
// Create a DOM element via angular.element
var validElement = angular.element('<div>{{ model.input }}</div>'); // Use angular.element to create an element from the string:
// Link function defined outside as a variable
var link = function (scope) {
scope.$watch("model.input", function (value) { //Invoking scope.$watch on model.input sets a listener on that model and waits for it to change. When it changes, the value parameter can be used to check the new value in the listener function.
if(value === "password") {
validElement.toggleClass("alert-box alert"); //referencing our previously defined element is cleaner
}
});
};
return {
restrict: "E", //replace the <dumb-password> element
replace: true,
templateUrl: "dumbpass.html", //inject dumbpass.html template
compile: function (tElem) { // The compile service takes an HTML string and compiles it into a template function, returning a 'link' function which is used to bind template to a scope.
// Calling this linking function will then return the element of the template.
tElem.append(validElement); //tElem parameter is the jqLite wrapper of the dumbpass.html template. Since we created the angular.element reference before as a variable in the directive, the tElem jqLite API is used to append the element validElement.
return link; //The $compile service returns a link function, that we've moved into a variable, which is a bit cleaner
}
}
});
//
// TRACK CHANGES IN PROPERTIES/MODEL: $scope.$watch / $watchCollection / $attrs.$observe
//
// observe changes in a particular object inside a model -typically from inside a controller or a 'link' function inside a directive
//CounterController.js
function CounterController($scope){
this.count = 0;
this.increment = function(){
this.count++;
};
this.decrement = function(){
this.count--;
};
// track the changes in this.count: $watch is a special method that comes with the $scope object, so we need to keep it injected inside our controller
$scope.$watch(angular.bind(this, function(){ // First argument is a string or a function (here, the 'count' model).
return this.count; //'this' here is referencing $scope, which is the object calling the function, so we bind the 'this' in a lexical context back to the function (via angular's own .bind)
}), function(newValue, oldValue){ // Second argument is a function, parameters: newValue of the property, oldValue prior to the change
// $watch function runs at runtime (needs to set this initial changed values).
// So you can check initial values for running your logic conditionally on init:
if(newValue === oldValue){
return;
}
console.log(newValue, oldValue);
});
}
// * IMPORTANT TO REMEMBER
// - use $scope for only events and things like $scope.watch and $watchCollection
// ** FOR DEEPER OBJECTS OR ARRAYS, USE $watchCollection
// We're going to create countList where we're going to store all the changes happened to our counter:
function CounterController($scope){
this.count = 0;
this.countList = []; // create countList where we're going to store all the changes happened to our counter
this.increment = function(){
this.count++;
this.countList.unshift = {id: this.count}; // push change to the countList
};
this.decrement = function(){
this.count--;
this.countList.unshift = {id: this.count};
};
...
}
// You can watch arrays or objects using $watch:
$scope.$watch(angular.bind(this, function(){
return this.countList;
}), function(newValue, oldValue){
console.log(newValue, oldValue);
}, true); //you need this third argument, 'true', to do a deep watch in this particular property we want to observe
// But it's more performant to use $watchCollection, to track changes in arrays and objects in a more performant way, without using deep watch:
$scope.$watchCollection(angular.bind(this, function(){
return this.countList;
}), function(newValue, oldValue){
console.log(newValue, oldValue);
});
// ** IF WE WANT TO TRACK CHANGES IN ATTRIBUTES WHEN USING DIRECTIVES, USE $attrs.$observe
// $attrs.$observe doesn't actually set a watcher, so it's more performant than $scope.$watch
// * $attrs.$observe only works in interpolated values that are dynamically driven through angular
<counter name="{{ counter.name }}"></counter>
//
function counter(){
return {
template: `
<div class="counter">
<input type="text" ng-model="counter.count">
<button type="button ng-click="counter.decrement();"> - </button>
<button type="button ng-click="counter.increment();"> + </button>
</div>
`,
link: function($scope, $element, $attrs) {
$attrs.$observe('name', function(value){ //we want to observe the 'name' attribute. We pass the interpolated value to the function
if(value === 'Food counter'){
$attrs.$updateClass('counter--food', 'counter--drink'); //second parameter is the otherwise value, if the condition doesn't match -- updateClass es like: remove all classes and add this class?
} else if(value === 'Food counter'){
$attrs.$updateClass('counter--drink', 'counter--food');
}
});
}
};
}
以上是关于javascript Angular $ watch,$ watchCollection,$ attrs。$ observe的主要内容,如果未能解决你的问题,请参考以下文章
Angular2 无法使用 javascript 导入 FormsModule
如何为现有的 Javascript 库创建 Angular 库包装器?
另一个 javascript 库上的 Angular 2 templateURL 功能