简单的控制等级
让我们构建一个简单的控件,一个评级小部件,旨在用作:
<rating min="0" max="5" nullifier="true" ng-model="data.rating"></rating>
现在没有花哨的 CSS; 这将呈现为:
0 1 2 3 4 5 x
点击一个数字可选择该评级; 然后单击 x
将评级设置为 null。
app.directive('rating', function() {
function RatingController() {
this._ngModel = null;
this.rating = null;
this.options = null;
this.min = typeof this.min === 'number' ? this.min : 1;
this.max = typeof this.max === 'number' ? this.max : 5;
}
RatingController.prototype.setNgModel = function(ngModel) {
this._ngModel = ngModel;
if( ngModel ) {
// KEY POINT 1
ngModel.$render = this._render.bind(this);
}
};
RatingController.prototype._render = function() {
this.rating = this._ngModel.$viewValue != null ? this._ngModel.$viewValue : -Number.MAX_VALUE;
};
RatingController.prototype._calculateOptions = function() {
if( this.min == null || this.max == null ) {
this.options = [];
}
else {
this.options = new Array(this.max - this.min + 1);
for( var i=0; i < this.options.length; i++ ) {
this.options[i] = this.min + i;
}
}
};
RatingController.prototype.setValue = function(val) {
this.rating = val;
// KEY POINT 2
this._ngModel.$setViewValue(val);
};
// KEY POINT 3
Object.defineProperty(RatingController.prototype, 'min', {
get: function() {
return this._min;
},
set: function(val) {
this._min = val;
this._calculateOptions();
}
});
Object.defineProperty(RatingController.prototype, 'max', {
get: function() {
return this._max;
},
set: function(val) {
this._max = val;
this._calculateOptions();
}
});
return {
restrict: 'E',
scope: {
// KEY POINT 3
min: '<?',
max: '<?',
nullifier: '<?'
},
bindToController: true,
controllerAs: 'ctrl',
controller: RatingController,
require: ['rating', 'ngModel'],
link: function(scope, elem, attrs, ctrls) {
ctrls[0].setNgModel(ctrls[1]);
},
template:
'<span ng-repeat="o in ctrl.options" href="#" class="rating-option" ng-class="{\'rating-option-active\': o <= ctrl.rating}" ng-click="ctrl.setValue(o)">{{ o }}</span>' +
'<span ng-if="ctrl.nullifier" ng-click="ctrl.setValue(null)" class="rating-nullifier">✖</span>'
};
});
关键点:
- 实现
ngModel.$render
以将模型的视图值传输到视图。 - 只要你觉得应更新视图值,请调用
ngModel.$setViewValue()
。 - 控制当然可以参数化; 使用
'<'
范围绑定参数,如果在 Angular> = 1.5 中清楚地表示输入 - 单向绑定。如果你必须在参数更改时执行操作,则可以使用 JavaScript 属性(请参阅Object.defineProperty()
)来保存一些手表。
注 1:为了不使实现过于复杂,将评级值插入数组中 - ctrl.options
。这不是必需的; 当 min
/ max
发生变化时,更高效但也更复杂的实现可以使用 DOM 操作来插入/删除评级。
注 2:除'<'
范围绑定外,此示例可用于 Angular <1.5。如果你在 Angular> = 1.5,那么将它转换为一个组件并使用 $onInit()
生命周期钩子来初始化 min
和 max
,而不是在控制器的构造函数中这样做是个好主意。
一个必要的小提琴: https : //jsfiddle.net/h81mgxma/