Miron
Miron

Reputation: 2137

How to pass NgModelController to directive controller?

Can i pass NgModelController to directive controller? That's required so i can assign values to model in controller.

This example does not work:

   angular
     .module('directives.selectBox', [])
     .directive('selectBox', selectBox);  

    function selectBox() {
        return {
          restrict   : 'E',
          require    : 'ngModel',
          scope      : {
             list     : '=',
          },
          replace     : true,
          templateUrl : 'common/directives/selectBox/selectBox.html',
          controller :  SelectBoxController,
        };
    }  
    function SelectBoxController(ngModel) {
       ngModel.$setViewValue(10); // ???
    }

Upvotes: 15

Views: 8403

Answers (3)

Valery Kozlov
Valery Kozlov

Reputation: 1577

If you want to affect only model value, $parse method best suit for you because it provides common way to comminicate with outer scope and write code, which does not depends on new scope creation.

angular.directive('selectBox', function($parse){
    return {
       // your directive stuff
       link: function(scope, iElem, iAttrs){
           var angularVarSetter = $parse(iAttrs.ngModel).assign;
           // in case of no own scope.
           angularVarSetter(scope, 100500);
           // in case of new scope
           angularVarSetter(scope.$parent, 100500);
       }
    };
});

Upvotes: 0

Robba
Robba

Reputation: 8314

Pretty simple actually, what you need to do is to get access to the element by injecting $element into your controller and then calling the .controller() function on it.

angular
   .module('directives.selectBox', [])
   .directive('selectBox', selectBox);  

function selectBox() {
    return {
      restrict   : 'E',
      require    : 'ngModel',
      scope      : {
         list     : '=',
      },
      replace     : true,
      templateUrl : 'common/directives/selectBox/selectBox.html',
      controller :  SelectBoxController,
    };
}  
function SelectBoxController($element) {
   var ngModel = $element.controller('ngModel');
   ngModel.$setViewValue(10); // ???
}

Angular 1.5 update

Note that in AngularJS 1.5 the new component() function was added in addition to the existing directive() function. This function takes a configuratoin object as second parameter that allows you to directly specify the required controllers, which will then be bound to the component's controller.

Below the same example again, but as component.

angular
   .module('directives.selectBox', [])
   .component('selectBox', 
        {
            controller: SelectBoxController,
            controllerAs: 'vm',
            templateUrl : 'common/directives/selectBox/selectBox.html',
            bindings: {
                list: '=' // though '<' would be better
            }, 
            require: {
                ngModel: '='
            },
            // replace: true ==> No longer possible with component
        }
    );  

function SelectBoxController($element) {

    $onInit() {
        // This function is called automatically whenever the controller is ready
        this.ngModel.$setViewValue(10); // ???
    }
}

I hope I typed it out ok, this tiny textarea is hardly an IDE :)

Upvotes: 27

MrE
MrE

Reputation: 20798

First I note your controller is not declared in the module, so it is not called. (might also want to rename it so it's not confusing

angular
     .module('directives.selectBox', [])
     .controller('SelectBoxController',SelectBoxController)
     .directive('selectBox', selectBox);

The directive takes the ng-model. then you can access it using $scope.ngModel within the link function of the directive.

function selectBox() {
        return {
          restrict   : 'E',
          require    : 'ngModel',
          scope      : {
             list     : '=',
          },
          replace     : true,
          templateUrl : 'common/directives/selectBox/selectBox.html',
          controller :  SelectBoxController,
          link: function($scope, $element, $attr, ngModel) {

                $scope.ngModel.$setViewValue(10);
           }
        };

here the controller is not even needed actually. Note that you don't necessarily need ngModel, you are passing 'list' as a 2 way binding param here already, so if you want to pass another argument as a parameters, just pass it like your 'list' param in the isolated scope. You should also not be assigning directly to the ng-model or param you pass, but rather to a 'child' element of the object, or you'll see weird behavior as your local object will shadow the original object of the parent scope.

So you may pass 'model.list' as the 'list' param, and then modify 'list' in the local scope which will modify 'model.list' in the parent scope. if you pass 'list' and modify it in the local scope, it will be overriding the list in the parent scope and probably not get your the 2-way binding you expect.

Upvotes: 0

Related Questions