setec
setec

Reputation: 16110

Getting ngModelController of the input

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

Answers (2)

Nate Anderson
Nate Anderson

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 the directive 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:

  1. make a directive for that purpose
  2. require "ngModel" as everyone has done
  3. manipulate the 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

Steve J
Steve J

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

Related Questions