Instead of simply monitoring the $submitted
property, you have the option to create a custom directive with the same name as the built-in form
directive. This custom directive can then be equipped with an event handler for form submission that triggers an angular event. The event can be captured by your myDirective
directive without interfering with the default behavior of the standard form
directive.
Check out the DEMO here
Alternatively, if you prefer not to extend the functionality of the form
directive, you can opt for a different directive name. Just remember to add this directive name as an attribute in the form tag to trigger the desired event.
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();
});
}
};
});
Update
In response to a query raised in the comments:
Is there an efficient way to check if the element labeled with the "my-directive" attribute also includes the "myForm" attribute (if I rename the "form" directive to "myForm") within its parent form? This would enable me to use "myDirective" with or without "myForm" attributes and adjust behavior accordingly.
There are a couple of methods to achieve this:
- You can utilize the
.data()
method in your myForm
directive during compilation, and access it in the link function of your myDirective
using the .inheritedData()
method, provided the data assigned in the original form
directive exists.
Note that passing the form
controller within the broadcast in the myForm
directive ensures that you receive the parent form controller for manipulation. In specific scenarios where the myDirective
is nested within an ng-form
, setting form.$setPristine()
on the form
element differs from setting it on the ngForm
form controller.
View the DEMO for a practical example
.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();
});
}
};
});
- Another optimized approach involves creating a controller within the
myForm
directive to store form event handlers for easy iteration when a form event occurs. Instead of employing the slower $broadcast
angular event, which traverses scopes downwards, this method offers a quicker alternative. By checking for the optional requirement of the ?^myForm
controller in the parent element, you can efficiently implement the logic as needed. Additionally, setting the scope to true in the myForm
directive enables reusability across multiple instances.
Explore the DEMO to see this implementation in action
.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();
});
}
};
});