Reputation: 16110
I need to access ngModelController of input element to check is it dirty or pristine.
I've managed to do it with directive which grabs ngModel of input to data object associated with element, making it obtainable from anywhere:
app.directive("input", [ function () {
return {
restrict: "E",
replace: false,
scope: false,
require: "ngModel",
link: function (scope, element, attrs, ctrls) {
element.data('ngModelController', ctrls);
}
}
}])
I know it could be modified to make directive as attribute, making it less coupled to 'input' tag.
I use that saved controllers in directives which represent UI elements and have input
elements in their markup. I don't use forms because those elements should work in any dom context, and forms imply certain limitations to hierarchy. So i'm using ngModelController to check some stuff required for validation of fields.
But is there any better way to get ngModelController of certain input?
Upvotes: 4
Views: 5213
Reputation: 21134
Apparently it was not sufficient for the OP to just use the ngModelController ** which angular already provides to you** (when you require
it). As described in the documentation:
To get a hold of the controller, you
require
it in thedirective
as shown in the example below.
Indeed, the OP and the highest-voted answer at this point, both already do this!. But then they do more; they either set, or get, using various techniques which rely on the data
attached to the DOM element using angular's jqLite, which defers to jQuery's, which defers to the Dataset API
These might be necessary if you want to access the controller outside of the angular framework; i.e. a jQuery extension could reach the controller. After all, the OP did have a goal of "making it obtainable from anywhere". But if you've managed to use angular exclusively, then there's no need to use teh data attribute.
However, I think it's worth calling out: that if you want to access the ngModelController
for a specific purpose, you've already done it! i.e. you can:
directive
for that purpose"ngModel"
as everyone has done ctrl
argument* passed to the link
function*or the appropriate element if require is an array , and therefore ctrl is an array
There is no need to set on the data()
object, and therefore no reason to get from the data()
object if you can just apply another directive. Indeed, requires
is one of the patterns described to support "directive to directive communication":
app.directive("purpose1", [ function () {
return {
require: "ngModel",
link: function (scope, element, attrs, ngModelCtrl) {
And some other purpose can still get at the ngModelCtrl
:
app.directive("purpose2", [ function () {
return {
require: "ngModel",
link: function (scope, element, attrs, ngModelCtrl) {
I myself want to avoid the directive altogether, so I was hoping there was an even more direct way to access the ngModelController.
Upvotes: 0
Reputation: 687
In my experience, Angular provides this to you already. In your directive where you want to access the ngModelController, do the following:
app.directive("randomDirective", function() {
return {
...
require: "ngModel",
link: function(scope, element, attrs, ctrl) {
var someInput = element.find('theInput'),
ngModelCtrlForInput = someInput.data().$ngModelController;
//Now you can access the ngModel controller for the <input> of the directive
}
}
});
Whether this is the best way to accomplish this feat remains to be seen. I haven't seen any better answers, yet (but if you know of one please ping me and let me know!).
EDIT
This answer has some other options, including something similar to:
element.find('theInput').controller('ngModel')
Upvotes: 6