我一直在尝试为我的角度应用程序编写一个共享指令,将输入字段转换为jquery timepicker。
我有两个输入字段,fromTime和toTime,我想在更改fromTime时更新toTime。
我的代码如下:
HTML
<input type="text"
time-picker="{ timeFormat: 'H:i'}"
class="input-block-level"
name="fromTime"
ng-model="filter.fromTime"
ng-change="update()"
/>
<input type="text"
time-picker="{ timeFormat: 'H:i'}"
class="input-block-level"
name="toTime"
ng-model="filter.toTime"
ng-change="update()"
/>
指令
sharedServices.directive('TimePicker', function () {
return {
restrict: 'A',
scope: {
time: "=ngModel"
},
link: function(scope, element, attrs) {
//Initialize the timepicker
$(element).timepicker(scope.$eval(attrs.TimePicker));
//watch for changes
scope.$watch('time', function(stuff) {
console.log('some change', stuff);
});
}
};
});
包含的sharedServices
var roomsApp = angular.module("roomsApp", ["ngResource",'ui', 'sharedServices','ui.bootstrap']).config(function($routeProvider) { ...
指令加载并且timepicker被初始化并附加到元素,但是当我更改输入字段时没有任何反应,甚至连元素附加的ng-change事件也没有。页面加载时输入字段也为空,即使模型设置为在应用程序的控制器中包含某些值。谁能解释一下这个问题?
*的更新 http://plnkr.co/edit/t3BzShezEdh29ZAlI8ZI?p=preview这证明了我的问题。日期更改时,没有任何控制台记录
答案 0 :(得分:6)
解决问题
您需要收听输入字段的更改并更新scope.time
。
我做的第一个更改是在 jQuery之后包含Angular ,这样element
参数将是一个jQuery对象。
然后收听更改事件并更新scope.time
。将呼叫包裹在scope.$apply
中,告诉Angular某些内容已发生变化。
element.on('change', function () {
scope.$apply(function () {
scope.time = element.datepicker('getDate');
});
});
替代方法
就编写应用于输入元素的指令而言,我个人希望允许用户使用ngModel
指令来保持数据同步,因为这是一个已知的约定。通过使用ngModel,您还可以(可选)使用它的控制器来添加自定义验证或其他逻辑,例如解析器/格式化程序(在这种情况下不需要)。
通过使用$parse
服务,我们可以将数据读/写回ngModel字段。
我也进行了更改,以便在需要时传递datetime选项。
最后,我将第一个datetime()
调用移到了编译函数,因为那是应该进行DOM操作的地方。
.directive("datetime", ['$parse', function($parse) {
return {
require: '?ngModel',
restrict: 'A',
compile: function (element, attrs) {
var options = $parse(attrs.datetime)() || {};
console.log('Passed options:', options);
element.datepicker(options);
// Return the link function
return function (scope, element, attrs, ngModel) {
var getter, setter;
// If the ngModel directive is used, then set the initial value and keep it in sync
if (ngModel) {
getter = $parse(attrs.ngModel);
setter = getter.assign;
console.log('ngModel directive used, setting initial value')
element.datepicker("setDate", getter(scope));
scope.$watch(attrs.ngModel, function(val, prev) {
console.log('ngModel changed from', prev, 'to', val);
});
element.on('change', function () {
console.log('change');
var newValue = element.datepicker('getDate');
scope.$apply(function () {
setter(scope, newValue);
});
});
}
};
}
};
}])
该指令的使用方式如下:
<input type="text" datetime="{showButtonPanel: true}" ng-model="parentTime" />
答案 1 :(得分:0)
<强>更新强> 这是一个使用jquery datepicker - http://plnkr.co/edit/4JZIWo6mJqg59F5o7xdh?p=preview
的非常基本的实现angular
.module("demo", [])
.directive("test", function() {
return {
restrict: 'A',
scope: {
time: "="
},
link: function(scope, element, attrs) {
console.log("scope.time:" + scope.time);
$(element).datepicker();
$(element).datepicker("setDate", scope.time);
}
};
})
.controller("demoCtl", function($scope){
$scope.parentTime = new Date();
});
看看angular-ui calendar module。如果您不想使用它,可以查看他们的代码来帮助您。
另外,设置示波器的方式看起来很奇怪。我想你想要将指令的time
属性绑定到由指令的父作用域管理的属性,而不是ng-model。
试试这个
return {
restrict: 'A',
scope: {
time: "="
},
link: function(scope, element, attrs) {
//Initialize the timepicker
$(element).timepicker(scope.$eval(attrs.TimePicker));
//watch for changes
scope.$watch('time', function(stuff) {
console.log('some change', stuff);
});
}
};
并使用它
<input type="text"
time-picker="{ timeFormat: 'H:i'}"
class="input-block-level"
name="toTime"
time="filter.toTime"
ng-change="update()"
/>
您也不需要在attrs.TimePicker
中包裹$scope.eval
。