Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually applying the ngModel directive

My directive needs to use ngModel.

I need to do this dynamically from within another directive as I want to do some funky stuff with scopes and abstract this away from the person writing the HTML.

My first thought was to use the $set function provided by the attrs argument in the link function, that works to modify the HTML but the directive itself does not get compiled. We can then combine this with the $compile provider, and it works.

attrs.$set('ngModel', someVar);
$compile(element)(scope);

The problem is that this creates infinite recursion if I do not (and I can not) replace the elements tag as the directive gets reapplied and recompiled indefinitely.

However I can fiddle with the priorities and get that to work:

module.directive('input', [
  '$compile',
  function($compile) {
    return {
      restrict: 'E',
      scope: {},
      priority: 100, // Set this high enough to perform other directives
      terminal: true, // Make sure this is the last directive parsed
      link: function(scope, element, attrs) {
          var key = 'example';
          attrs.$set('ngModel', key);
          $compile(element, null, 100)(scope);
      }
    };
  }
]);

This works fine, but it just feels wrong:

  • I now have to ensure that all other directives on the element are capable of being recompiled as they will all get compiled twice.

  • I have to make sure that nobody uses a higher priority.

So this got me thinking why can't I just inject the ngModelDirective and force compile it against my element?

module.directive('input', [
  'ngModelDirective',
  function(ngModel) {
    return {
      restrict: 'E',
      scope: {},
      priority: 100, // Set this high enough to perform other directives
      terminal: true, // Make sure this is the last directive parsed
      require: '?^form',
      link: function(scope, element, attrs, formCtrl) {
          var key = 'example';
          attrs.$set('ngModel', key);
          var ngModelFactory = ngModel[0];
          var ngModelLink = ngModelFactory.compile(element);
          ngModelLink.call(this, scope, element, attrs, [ngModelFactory.controller, formCtrl]);
      }
    };
  }
]);

See: https://github.com/angular/angular.js/blob/v1.2.x/src/ng/directive/input.js#L1356

No errors thrown, but nothing happens. It seems this isn't enough to hook it up, so my question is can anyone elaborate on to what I need to do link the ngModelDirective to my custom directive without forcing a recompile?

like image 653
George Reith Avatar asked Dec 19 '25 01:12

George Reith


1 Answers

ngModel seems a bad fit for what you are trying to do. But you don't need it anyway. You can two-way-bind some variable and pass the name into the model directive scope:

app.directive("myDirective", function() {
    // ...
    scope: {
        myModel = "=",
        modelName = "myModel"
        // ...
    }
    // ...
});

app.directive("ngModelDirective", function() {
    // ...
    // ...
    transclude: true,
    link: function(scope, element, attrs) {
        var modelName = scope.modelName;
        console.assert(modelName, '`modelName` must be set when using `ngModelDirective`.');
        // TODO: Check if `scope[modelName]` is actually bound
        doSomethingFancyWith(scope, modelName);
    }
});

Template example:

<myDirective ngModelDirective my-model="..." />

Note that doSomethingFancyWith can read and write the model variable, with bindings to the outside world.

like image 193
Domi Avatar answered Dec 20 '25 15:12

Domi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!