Как передать NgModelController директивному контроллеру?

Могу ли я передать NgModelController директивному контроллеру? Это требует, чтобы я мог назначать значения модели в контроллере.

Этот пример не работает:

   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); // ???
    }

Ответы

Ответ 1

Довольно просто, что вам нужно сделать, это получить доступ к элементу, вставив $element в ваш контроллер, а затем вызовите на нем функцию .controller().

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 обновление

Обратите внимание, что в AngularJS 1.5 добавлена ​​новая функция component() в дополнение к существующей функции directive(). Эта функция принимает объект configuratoin как второй параметр, который позволяет вам напрямую указывать требуемые контроллеры, которые затем будут привязаны к контроллеру компонента.

Ниже того же примера снова, но как компонент.

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); // ???
    }
}

Надеюсь, я набрал его в порядке, эта маленькая текстовая область вряд ли является IDE:)

Ответ 2

Сначала я отмечаю, что ваш контроллер не объявлен в модуле, поэтому он не вызывается. (может также захотеть переименовать его, чтобы он не запутывал

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

Директива принимает ng-модель. то вы можете получить к нему доступ, используя $scope.ngModel в пределах функции ссылки директивы.

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);
           }
        };

здесь контроллер вообще не нужен. Обратите внимание, что вам не обязательно нужно ngModel, вы передаете "список" как 2-сторонний параметр привязки здесь, поэтому, если вы хотите передать другой аргумент в качестве параметров, просто передайте его, как ваш параметр "list" в изолированной области, Вам также не следует назначать непосредственно ng-model или param, которые вы передаете, а скорее "дочернему" элементу объекта, или вы увидите странное поведение, так как ваш локальный объект будет теневать исходный объект родительской области.

Таким образом, вы можете передать 'model.list' в качестве параметра 'list', а затем изменить "список" в локальной области, который будет изменять "model.list" в родительской области. если вы передадите "список" и измените его в локальной области, он будет переопределять список в родительской области и, вероятно, не получит ваше двухстороннее связывание, которое вы ожидаете.

Ответ 3

Если вы хотите повлиять только на модельное значение, метод $parse наилучшим образом подходит для вас, потому что он обеспечивает общий способ извлечения с внешней областью и писать код, который не зависит от создания новой области.

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);
       }
    };
});