我想在指令中监听表单提交。假设我有这样的指令:
app.directive('myDirective', function () {
return {
restrict: 'A',
require: '^form',
scope: {
smth: '='
},
link: function (scope, el, attrs, formCtrl) {
scope.$watch(function(){
return formCtrl.$submitted;
},function(currentValue){
console.log('submitted');
});
}
}
});
用上面的方法我可以看到第一次提交,但不能看到其余的。我试图做这样的事情:
scope.$watch(function () {
return formCtrl.$submitted;
}, function (currentValue) {
if (currentValue) {
console.log('submitted');
formCtrl.$setPristine(); // Watch this line!
}
});
但问题是,如果我在一个表单中多次使用该指令,它只对第一次使用有效。
我想知道的是是否有类似 formCtrl.onsubmit(...)
的东西或任何解决方法来获得相同的功能。在此先感谢您的帮助...
最佳答案
您可以创建一个与 form
指令同名的指令,而不是观察 $submitted
属性,该指令附加了一个表单提交的事件处理程序广播一个 Angular 事件,您可以在 myDirective
指令中收听该事件。您不必担心覆盖 form
指令的 Angular 实现,它只会附加您的行为,不会覆盖内置实现。
注意:您也可以选择不将功能附加到 form
指令,而是选择另一个指令名称,只需确保将该指令名称附加为表单标记中的属性即可触发事件.
Javascript
.directive('form', function() {
return {
restrict: 'E',
link: function(scope, elem) {
elem.on('submit', function() {
scope.$broadcast('form:submit');
});
}
};
})
.directive('myDirective', function() {
return {
require: '^form',
link: function(scope, elem, attr, form) {
scope.$on('form:submit', function() {
form.$setPristine();
});
}
};
});
更新
鉴于下面评论中提出的问题:
what's the most efficient way to check if the element that has "my-directive" attribute has "my-form" (if I name "form" directive to "myForm") attribute in it's parent form? So I can either use "myDirective" with or without "myForm" (and behave accordingly of course)
有几种方法可以做到这一点:
- 在编译阶段使用
myForm
指令中的.data()
方法,并在myDirective
的链接函数中访问它如果在form
指令中分配的数据存在,则使用.inheritedData()
方法。
请注意,我在 myForm
指令的广播中传递了 form
Controller 。这确保您收到来自 form
元素的父表单 Controller 。在某些用例中,您可以通过 ng-form
在嵌套表单中使用 myDirective
,而不是设置 form.$setPristine()
到您要设置 ngForm
表单 Controller 的 form
元素表单 Controller 。
.directive('myForm', function() {
return {
require: 'form',
compile: function(tElem, tAttr) {
tElem.data('augmented', true);
return function(scope, elem, attr, form) {
elem.on('submit', function() {
scope.$broadcast('form:submit', form);
});
}
}
};
})
.directive('myDirective', function() {
return {
link: function(scope, elem, attr) {
if(!elem.inheritedData('augmented')) {
return;
}
scope.$on('form:submit', function(event, form) {
console.log('submit');
form.$setPristine();
});
}
};
});
- 另一种方式可能是针对此特定用例高度优化的方式。在
myForm
指令中创建一个 Controller ,该指令存储要在触发表单事件时迭代的表单事件处理程序。而不是使用$broadcast
Angular 事件,它实际上比下面的实现慢,因为它遍历从form
元素到最后一个范围链的每个范围。下面的myForm
Controller 创建了自己的机制来存储事件处理程序。正如#1 中所实现的,使用.data()
-inheritedData()
很慢,因为myDirective
被埋得很深并且嵌套在很多地方元素,因为它向上遍历DOM
,直到找到特定的data
。使用下面的实现,您可以检查父级中是否存在所需的?^myForm
Controller ,注意?
它代表可选要求。此外,在myForm
指令中将范围设置为 true 允许您使指令可重用,例如在一个页面中有多个myForm
指令..
.directive('myForm', function() {
return {
require: ['form', 'myForm'],
scope: true,
controller: function() {
this.eventHandlers = {
submit: [],
change: []
};
this.on = function(event, handler) {
if(this.eventHandlers[event]) {
this.eventHandlers[event].push(handler);
}
};
},
link: function(scope, elem, attr, ctrls) {
var form = ctrls[0],
myForm = ctrls[1];
angular.forEach(myForm.eventHandlers, function(handlers, event) {
elem.on(event, function(eventObject) {
angular.forEach(handlers, function(handler) {
handler(eventObject, form);
});
});
});
}
};
})
.directive('myDirective', function() {
return {
require: '?^myForm',
link: function(scope, elem, attr, myForm) {
if(!myForm) {
return;
}
myForm.on('submit', function(event, form) {
console.log('submit');
form.$setPristine();
});
}
};
});
关于javascript - 在指令中监听表单提交事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26383507/