我正在努力了解AngularJS是如何工作的。我有一个指令count-Date
,它按月份和年份计算年龄。我不能直接写入数据模型,因为我有很多字段,但我想多次使用我的代码。
HTML:
<div>Date of birth first child
month: <input type = "text" id = "MonthFirstChild" ng-model='MonthFirstChild' required maxlength="2" only-Digits month required count-Date>
year: <input type = "text" name='YearFirstChild' ng-model='YearFirstChild' maxlength="4" only-Digits year-Of-Birth required count-Date>
<span ng-model = "AgeFirstChild">{{AgeFirstChild}}</span>
</div>
<div>Date of birth second child
month: <input type = "text" id = "MonthSecondChild" ng-model='MonthSecondChild' required maxlength="2" only-Digits month required count-Date>
year: <input type = "text" name='YearSecondChild' ng-model='YearSecondChild' maxlength="4" only-Digits year-Of-Birth required count-Date>
<span ng-model = "AgeSecondChild">{{AgeSecondChild}}</span>
</div>
JS:
app.directive('countDate', function () {
return {
link: function ($scope, element, attrs) {
element.bind('blur', function(event,el) {
var el = angular.element(element),
month = +el.parent().children().eq(0).val(),
year = +el.parent().children().eq(1).val(),
dateOfBirth = new Date(year,month),
now = new Date(),
today = new Date(now.getFullYear(), now.getMonth()),
age = Math.round((now - dateOfBirth)/(32140800000);
});
}
};
});
我需要帮助重写指令。
如果你只想计算年龄,那么写指令有点过头了——你可以简单地写一个计算年龄的scope方法,比如:
HTML:
<div>Date of birth first child
month: <input type="number" min="1" max="12" ng-model="MonthFirstChild" required maxlength="2" />
year: <input type="number" min="0" max="9999" ng-model="YearFirstChild" required maxlength="4" />
<span>{{getAge(YearFirstChild, MonthFirstChild)}}</span>
</div>
JS(控制器):
$scope.getAge = function(year,month) {
var dateOfBirth = new Date(year, month),
now = new Date();
return now.getFullYear() - dateOfBirth.getFullYear();
};
以下是我要做的:
我会使用ng-repeat
来迭代一组子对象。
父范围:
app.controller('wrapperController', ['$scope', function(scope){
scope.children = [{
name: 'John'
}
,{
name: 'Bill'
}
,{
name: 'Bob'
}];
}]);
现在,我将冒险猜测,在您的实际应用程序中,您有某种用于儿童的动态数据源,但让我们假设它是硬编码的。
然后我们可以做的是将整个模板包装为html,假设以下内容在文件child.html
:中
<count-date date-container="child">Date of birth of child:
month:<input type = "text" ng-model='dateContainer.month' required maxlength="2">
year: <input type = "text" ng-model='dateContainer.year' maxlength="4">
<span>{{child.age}}</span>
<br>
</count-date>
假设我们有以下两个指令:
angular.module('demo').directive('child', [function(){
return {
restrict:'E',
templateUrl: './child.html'
}
}]);
angular.module('demo').directive('countDate', [function () {
return {
restrict: 'E',
scope: {
dateContainer: '='
},
link: function (scope, element, attrs) {
scope.$watch('dateContainer.month', function(newVal, oldVal){
if(newVal && scope.dateContainer.year){
scope.dateContainer.age = Math.round((new Date() - new Date(JSON.parse(scope.dateContainer.year), JSON.parse(newVal)))/32140800000);
}
});
scope.$watch('dateContainer.year', function(newVal, oldVal){
if(newVal && scope.dateContainer.month){
scope.dateContainer.age = Math.round((new Date() - new Date(JSON.parse(newVal), JSON.parse(scope.dateContainer.month)))/32140800000);
}
});
}
}
}]);
http://plnkr.co/edit/3tnQEnnm7DQbbn0yIEbe?p=preview
这会奏效的,而且(我相信)你想做什么就做什么。让我们谈谈它是如何工作的以及为什么工作的:
1) 我们存储了所有孩子的数组。这允许我们使用ng-repeat
以可重复的方式对它们进行迭代
2) 在计数日期指令中,我们将每个子项传递到隔离作用域上的双向绑定中。这意味着指令将创建自己的作用域,该作用域不从任何父作用域继承。这是为了使指令易于重用。但是,通过使用=
将双向绑定传递到作用域声明中,我们可以绑定到父(控制器)作用域中的变量。因此,当我们修改count-date
上的dateContainer
时,它最初绑定的变量(在我们的情况下为child
)也会被修改。类似地,如果父母中的一方修改了child
,这也会影响dateContainer
。由于ng-repeat
还通过引用绑定到它正在迭代的对象,因此任何更改都将一直传播到堆栈中。
3) 通过在child.year
和child.month
上设置ng-model
,而不是month
或year
,我们确保将字段添加到现有对象中,并且因此在所有作用域中都可用。如果我们将ng-model
绑定到year
,我们将只在最内部的隔离范围内实例化该变量,并且我们的父母都不会收到这些新数据。
4) 我们$watch
我们想要的孩子的属性。这意味着,每当两个属性(dataContainer.month
或dataContainer.year
)发生变化时,它们都会运行所提供的回调(计算年龄),然后触发$digest
迭代,强制重新发布{{child.age}}