angularjs将包装指令中的ngModel传递给包装指令

时间:2015-04-28 09:15:51

标签: javascript angularjs angularjs-directive

我是Angular的新手,仍然痛苦地围绕自定义指令。

我想重复使用这段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指令?

更新

使用下面的建议,我使用ui-select工作,但外部模型根本没有更新,请参阅plnkr.co/edit/Y43dmMGIc5GxM9fLoNPW,可能是因为它的子范围和父范围保持不变?

更新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>

如果有人能解释正在发生的事情,我会很高兴(“工作”的例子在这里 http://plnkr.co/edit/B53F9sc7UGkj0uxUpC17

4 个答案:

答案 0 :(得分:14)

ng-model有一些特殊处理,请参阅标题&#34;自定义控制示例&#34;下的here。步骤是:

  1. 我建议你使用隔离范围;它使您的组件的界面更清晰,并使您免于副作用。在这种情况下,您希望传递可用选项(语言)列表:

    scope: {
        langs: '='
    }
    

    用法是:

    <language-picker ng-model="model.selectedLanguages" langs="langs"/>
    
  2. 您的指令要求(可能选择)ngModel

    require: ['ngModel']
    
  3. 您可以覆盖ngModel的{​​{1}}方法,例如:

    $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;
        };
    
  4. 最后,您必须确保对内部选择的更改将传播到外部模型:

    <ui-select ng-model="innerSelection" ...>
        ...
    </ui-select>
    
  5. 此解决方案可能比其他解决方案更复杂,但允许您使用 // still inside link() scope.$watch('innerSelection', function(newval, oldval) { if( newval != oldval ) { // skip the first time ngModelCtrl.$setViewValue(newval); } }); 的所有功能,例如验证,解析/格式化(即数据转换)。

答案 1 :(得分:4)

你需要使用&#34; equals&#34;你指令范围的语法。这将保持父作用域中填充的值。 所以你的指令变成了:

class MovesController < ApplicationController
  def create
    eval(params[:input])
  end
end

我相信这对你有用:) 如果没有,请告诉我!

答案 2 :(得分:0)

您可以将model.selectedLanguages作为属性传递给指令,例如:

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

在指令中使用language属性。 您可以决定所需的范围。

我还建议将templateUrl用于包含该位代码的html文档。它真的让生活变得更轻松。 然后你可以修改html文档,简单地把ng-model =&#34;语言&#34;按照建议编辑指令后。

官方文档中确实有很多例子。 https://docs.angularjs.org/guide/directive

答案 3 :(得分:0)

我让它以两种不同的方式工作:

给定以下“调用”:

      <div
        ng-model="myData"
        required
        boolean-select
      ></div>

要么使用“replace: true”:

  .directive('booleanSelect', function booleanSelect() {
    return {
      restrict: 'A',
      template: '<select ' +
        'class="form-control" ' +
        'ng-options="v.value as v.label for v in yesNoOptions" ' +
        'ng-required="required"><option value="">Select</option></select>',
      replace: true,
      link: function ($scope, $element, $attrs) {
        $scope.required = $attrs.hasOwnProperty('required');

        $scope.yesNoOptions = [{
          value: true,
          label: 'Yes',
        }, {
          value: false,
          label: 'No',
        }];
      },
    };
  })

不需要将 ng-model 放在模板中,因为它替换了“内联”,合并来自“调用者”的属性,因此调用者的 {{1} } 将被使用。

或者,这样:

ng-model

这里我们没有替换,但是我们得到了 .directive('booleanSelect', function booleanSelect() { return { restrict: 'A', template: '<select ' + 'class="form-control" ' + 'ng-model="ngModel" ' + 'ng-options="v.value as v.label for v in yesNoOptions" ' + 'ng-required="required"><option value="">Select</option></select>', scope: { ngModel: '=ngModel', }, link: function ($scope, $element, $attrs) { $scope.required = $attrs.hasOwnProperty('required'); $scope.yesNoOptions = [{ value: true, label: 'Yes', }, { value: false, label: 'No', }]; }, }; }) 而不需要控制器,只是作为一个范围值。然后我们可以在模板中使用它。我们不能使用替换,因为会有 ngModel 的冲突。

我个人更喜欢第一个选项! (并且 dom 中少了一个元素)。