2015-04-28 4 views
7

Я новичок в Angular и все еще мучительно обволакиваю голову вокруг пользовательских директив.angularjs pass ngModel от директивы обертки до обернутой директивы

Я хотел бы повторно использовать этот бит HTML

<ui-select ng-model="model.selectedLanguages" multiple search-enabled="true" theme="select2" style="width: 300px;"> 
    <ui-select-match placeholder="Pick one...">{{$item.name}}</ui-select-match> 
    <ui-select-choices repeat="lang.id as lang in langs |filter: { name : $select.search }"> 
     <div ng-bind-html="lang.name | highlight: $select.search" ></div> 
    </ui-select-choices> 
</ui-select> 

, обернув его в моей пользовательской директивы:

<language-picker ng-model="model.selectedLanguages"/> 

что-то вроде этого:

app.directive('languagePicker', function() { 
      return { 
       template : '<ui-select ng-model="**PARENT'S NGMODEL**" multiple search-enabled="true" theme="select2" style="width: 300px;"><ui-select-match >{{$item.name}}</ui-select-match><ui-select-choices repeat="lang.id as lang in langs | filter: { name : $select.search }"><div ng-bind-html="lang.name | highlight: $select.search"></div></ui-select-choices></ui-select>', 
       restrict : 'E', 
       require : 'ngModel', 
       replace : true 
        .... 
      }; 
     }); 

Но как Я передаю ngModel из моего language-picker в директиву ui-select?

UPDATE

Используя предложения ниже, я получил его работать с UI-выбора, но внешняя модель не обновляется вообще, см plnkr.co/edit/Y43dmMGIc5GxM9fLoNPW, вероятно, потому, что ребенок сфера и родительская сфера остается одна и та же?

UPDATE 2

Я получил его на работу в свернутой таким образом, что выглядит ужасно для меня, потому что я понятия не имею, почему она «работает» в первую очередь (см странные вещи происходят в контроллер):

app.directive('languagePicker', function(LanguageService) { 
      return { 
       templateUrl : 'LanguagePickerTpl.html', 
       restrict : 'E', 
       scope : { 
        languages : '=' 
       }, 
       controller : function($scope, LanguageService) { 
        console.log($scope); 
        $scope.langs = LanguageService.get(); 
        $scope.model = $scope; 
       } 

      }; 
     }) 

шаблона:

<ui-select ng-model="model.languages" multiple search-enabled="true" 
    theme="select2" style="width: 300px;"> 
    <ui-select-match>{{$item.name}}</ui-select-match> 
    <ui-select-choices repeat="lang.id as lang in langs | filter: { name : $select.search }"> 
     <div ng-bind-html="lang.name | highlight: $select.search"></div> 
    </ui-select-choices> 
    </ui-select> 

Я был бы очень рад, если бы кто-нибудь может объяснить, что происходит («рабочий» экса mple здесь http://plnkr.co/edit/B53F9sc7UGkj0uxUpC17 )

+0

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

ответ

4

Для использования директивы вы должны использовать синтаксис «equals». Это сохранит значения, заполненные родительской областью. Так ваша директива становится:

app.directive('languagePicker', function() { 
     return { 
      template : '<ui-select ng-model="**PARENT'S NGMODEL**" multiple search-enabled="true" theme="select2" style="width: 300px;"><ui-select-match >{{$item.name}}</ui-select-match><ui-select-choices repeat="lang.id as lang in langs | filter: { name : $select.search }"><div ng-bind-html="lang.name | highlight: $select.search"></div></ui-select-choices></ui-select>', 
      restrict : 'E', 
      require : 'ngModel', 
      replace : true, 
      scope: { 
       ngModel: "=ngModel" 
      } 
      ... 
     }; 
    }); 

Я уверен, что это будет работать для вас :) Дайте мне знать, если это не так!

+1

Спасибо, это работает! по крайней мере, он работает со встроенным '' в шаблоне. С 'ui-select', я не уверен, поскольку теперь я столкнулся с ошибкой' multidir', потому что я совмещаю две директивы с областью выделения, поэтому впереди еще больше работы) – AunAun

+0

На самом деле я не могу сделать он работает с 'ui-select', внешняя модель вообще не обновляется, см. http://plnkr.co/edit/Y43dmMGIc5GxM9fLoNPW – AunAun

+2

Я получил это, чтобы работать чрезвычайно запутанно, и я понятия не имею, почему он работает http://plnkr.co/edit/B53F9sc7UGkj0uxUpC17 – AunAun

0

Вы можете передать model.selectedLanguages ​​как свойство директивы, такие как:

< language-picker language="model.selectedLanguage" />

И внутри директивы использовать свойство языка. Вы можете решить, какой объем вам нужен.

Я также рекомендую использовать шаблон url в html-документе с этим битом кода. Это действительно облегчает жизнь. Затем вы можете изменить html-документ, чтобы просто поместить ng-model = "language" после редактирования вашей директивы, как было предложено.

В официальной документации действительно много примеров. https://docs.angularjs.org/guide/directive

13

ng-model имеет специальную обработку, см. here под заголовком «Пример пользовательского контроля».Этапы:

  1. Предлагаю вам использовать изолированный объем; это делает интерфейс для вашего компонента более четким и избавляет вас от побочных эффектов. В этом случае вы хотите, чтобы передать список доступных опций (языки):

    scope: { 
        langs: '=' 
    } 
    

    Использование будет:

    <language-picker ng-model="model.selectedLanguages" langs="langs"/> 
    
  2. Ваша директива требует (может быть необязательно) ngModel:

    require: ['ngModel'] 
    
  3. Вы переоцениваете метод ngModel$render, например:

    link: function(scope,elem,attrs,ctrls) { 
        var ngModelCtrl = ctrls[0]; 
        ngModelCtrl.$render = function() { 
         ... 
        }; 
    } 
    

    Логика визуализации отвечает за передачу значения модели (здесь: <language-picker ng-model="model.selectedLanguages"/>, то есть model.selectedLanguages). Самое простое, что я могу думать, это использование изолированных областей видимости и передачи внешняя стоимость модели на переменную изолированного объема как:

    ngModelCtrl.$render = function() { 
         scope.innerSelection = ngModelCtrl.$viewValue; 
        }; 
    

    Bind эту переменную в шаблоне, как:

    <ui-select ng-model="innerSelection" ...> 
        ... 
    </ui-select> 
    
  4. Последних вы должны убедиться, что изменения внутреннего отбора будут распространяться на внешнюю модель:

    // still inside link() 
        scope.$watch('innerSelection', function(newval, oldval) { 
         if(newval != oldval) { // skip the first time 
          ngModelCtrl.$setViewValue(newval); 
         } 
        }); 
    

Это решение может быть немного более сложным, чем другие, но позволяет использовать все функции ngModel, например. валидация, разбор/форматирование (т. е. преобразование данных).

+0

'NgModelController. $ Render()' был последним недостающим кусочком головоломки для меня. Спасибо! –

Смежные вопросы