javascript Angular 指令数据绑定无法正常工作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16965215/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular directive data binding not working properly
提问by Bjarki
I have been trying to write a shared directive for my angular apps that turns an input field into jquery timepicker.
我一直在尝试为我的 angular 应用程序编写一个共享指令,将输入字段转换为 jquery 时间选择器。
I have two input fields, fromTime and toTime, and I want to update the toTime when the fromTime is changed.
我有两个输入字段,fromTime 和 toTime,我想在更改 fromTime 时更新 toTime。
My code is as follows:
我的代码如下:
HTML
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()"
/>
Directive
指示
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 included
包括共享服务
var roomsApp = angular.module("roomsApp", ["ngResource",'ui', 'sharedServices','ui.bootstrap']).config(function($routeProvider) { ...
The directive loads and the timepicker is initalized and attached to the element, but when I change the input fields nothing happens, not even the ng-change event that is attached to the element. The input fields are also empty when the page loads, even though the model is set to contain some value in the app's controller. Can anyone shed some light on the matter?
指令加载并且 timepicker 被初始化并附加到元素,但是当我更改输入字段时什么也没有发生,甚至附加到元素的 ng-change 事件也没有。页面加载时,输入字段也为空,即使模型设置为包含应用程序控制器中的某些值。任何人都可以对此事有所了解吗?
*Updatehttp://plnkr.co/edit/t3BzShezEdh29ZAlI8ZI?p=previewthis demonstrates my problem. Nothing is console logged when the date is changed
*更新http://plnkr.co/edit/t3BzShezEdh29ZAlI8ZI?p=preview这说明了我的问题。更改日期时,控制台不会记录任何内容
回答by Martin
To fix the problem
解决问题
You'll need to listen to changes to the input field and update scope.time
.
您需要监听输入字段的更改并更新scope.time
。
First change I did was to include Angular afterjQuery, that way the element
parameter will be a jQuery object.
我所做的第一个更改是在jQuery之后包含 Angular ,这样element
参数将是一个 jQuery 对象。
Then listen to the change event and update scope.time
. Wrap the call in scope.$apply
to tell Angular that something has changed.
然后监听 change 事件和 update scope.time
。将调用包裹起来scope.$apply
,告诉 Angular 有些事情发生了变化。
element.on('change', function () {
scope.$apply(function () {
scope.time = element.datepicker('getDate');
});
});
Alternative approach
替代方法
Personally when writing directives that are applied on input elements I want to allow the user to use ngModel
directive to keep the data in sync, since that is a known convention. By using ngModel you could also (optionally) use it's controller to add custom validation or other logic, e.g. parsers/formatters (not needed in this case).
就个人而言,在编写应用于输入元素的指令时,我希望允许用户使用ngModel
指令来保持数据同步,因为这是一个已知的约定。通过使用 ngModel,您还可以(可选)使用它的控制器来添加自定义验证或其他逻辑,例如解析器/格式化程序(在这种情况下不需要)。
By using the $parse
service we can read/write data back to the ngModel field.
通过使用该$parse
服务,我们可以将数据读/写回 ngModel 字段。
I also changed so that datetime options can be passed if needed.
我还进行了更改,以便在需要时可以传递日期时间选项。
Lastly I moved the first datetime()
call to the compile function since that's the place where DOM manipulation should be made.
最后,我将第一个datetime()
调用移到了 compile 函数,因为这是应该进行 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);
});
});
}
};
}
};
}])
And the directive is used like this:
该指令是这样使用的:
<input type="text" datetime="{showButtonPanel: true}" ng-model="parentTime" />
回答by Jason
Update:Here is a very rudimentary implementaion using jquery datepicker - http://plnkr.co/edit/4JZIWo6mJqg59F5o7xdh?p=preview
更新:这是一个使用 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();
});
Have a look at angular-ui calendar module. If you don't want to use it, you can look at their code to help you.
看看angular-ui 日历模块。如果你不想使用它,你可以查看他们的代码来帮助你。
Also, the way you set up your scope looks strange. I think you want to bind you directive's time
property, to a property managed by the directive's parent scope, not the ng-model.
此外,您设置示波器的方式看起来很奇怪。我认为您想将指令的time
属性绑定到由指令的父作用域管理的属性,而不是 ng-model。
try this
试试这个
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);
});
}
};
and use it
并使用它
<input type="text"
time-picker="{ timeFormat: 'H:i'}"
class="input-block-level"
name="toTime"
time="filter.toTime"
ng-change="update()"
/>
also you don't need to wrap attrs.TimePicker
in $scope.eval
.
你也不需要包裹attrs.TimePicker
在$scope.eval
.