无法将ngModel从控制器传递/更新到指令

时间:2015-04-18 06:46:58

标签: javascript angularjs

我正在使用ui-select插件,并且我将ng-model从我的控制器传递到名为richSelect的自定义指令,但ng-model似乎没有更新任何选择项目

<richselect ng-model="dataModel"></richselect>

自定义指令

app.directive('richselect', ['$compile', function ($compile) {
return {
    restrict: 'AE',
    scope: {
        ngModel: '='               /* Model associated with the object */
    },
    link: function (scope, element, attrs, ngModel) {
        scope.options = [
                         {
                             'Value' : 'value1',
                             'Desc' : 'Value One'
                         },
                         {
                             'Value' : 'value2',
                             'Desc' : 'Value Two'
                         }
        ]
        scope.getRichSelectTemplate = function () {

            return '<ui-select multiple ng-model="ngModel" theme="bootstrap"  ng-disabled="disabled">' +
            '{{ngModel}} <ui-select-match placeholder="Select">{{$select.selected.Desc}}</ui-select-match>' +
                '<ui-select-choices repeat="option in options | filter: $select.search">' +
                        '<span ng-bind-html="option.Desc | highlight: $select.search"></span>' +
                '</ui-select-choices>' +
            '</ui-select>';
        }       

         var linkFn = $compile(scope.getRichSelectTemplate())(scope);
         element.append(linkFn);
    }
}
}]);

Plnkr:http://plnkr.co/edit/Im8gpxEwnU7sgrKgqZXY?p=preview

2 个答案:

答案 0 :(得分:1)

在这里,试试这个。我不确定您尝试获取的格式或输出,但这会将选定的选项传递给View。

  • 编辑 - 我摆脱了曾经在这里的那个人。

您必须使用ngModel.$setViewValue才能在视图中更改指令中ng-model的值。另外,要获得ui-select的值,您需要将ng-model指向options.selected

然后,只需要添加ng-click指向使用ngModel.$setViewValue(scope.options.selected更新视图的函数。

另外,我相信你需要在你的指令中`require:'ngModel',这样你才能访问ngModelController。

app.directive('richselect', ['$compile', function ($compile) {
    return {
        restrict: 'AE',
        require: 'ngModel',
        scope: {
            blah: '='               /* Model associated with the object */
        },
        link: function (scope, element, attrs, ngModel) {
          scope.changer = function() {
            ngModel.$setViewValue(scope.options.selected)
            console.log(scope.options.selected)
          }
            scope.options = [
                             {
                                 'Value' : 'value1',
                                 'Desc' : 'Value One'
                             },
                             {
                                 'Value' : 'value2',
                                 'Desc' : 'Value Two'
                             }
            ]
            scope.getRichSelectTemplate = function () {

                return '<ui-select multiple ng-model="options.selected" theme="bootstrap" ng-click="changer()" ng-disabled="disabled">' +
                '{{options.selected}} <ui-select-match placeholder="Select">{{$select.selected.Desc}}</ui-select-match>' +
                    '<ui-select-choices repeat="option in options | filter: $select.search">' +
                            '<span ng-bind-html="option.Desc | highlight: $select.search"></span>' +
                    '</ui-select-choices>' +
                '</ui-select>';
            }       

             var linkFn = $compile(scope.getRichSelectTemplate())(scope);
             element.append(linkFn);
        }
    }
}]); 

修改 经过大量的挖掘和修补,根据下面的评论 - 获得双向约束工作已经证明有点难以捉摸。我发现使用标准的ui-select指令非常容易,如此处所示(来自ui-select的修改示例代码),因为我们可以轻松访问指令的范围: Standard Directive Demo

我也遇到了与OP中的一个类似的包装,但是在使用它之后,那个似乎有同样的问题 - 很容易把东西拿出去,但是如果你需要将数据推送到指令中不想去。 有趣的是,在上面的解决方案中,我可以看到`scope.options.selected'对象实际上包含数据,它永远不会落在ui-select指令的范围内,因此永远不会允许我们推送数据。

在我正在处理的项目中遇到与其他包装器指令类似的问题之后,我想出了如何通过不同的范围推送数据。

我的解决方案是修改ui-select脚本本身,添加一个内部$ watch函数,检查其$parent范围内的变量。由于ui-select指令使用scope: true,因此它创建了一个子范围(如果我没有记错,那么父级将是此OP中的指令)。

在uiSelect指令的link函数的底部,我添加了以下监视功能:

scope.$watch(function() {
  return scope.$parent.myVar;
}, function(newVal) {
  $select.selected = newVal;
})

在我们的直接链接功能中,我添加了这个$​​ watch功能:

scope.$watch(function() {
  return ngModel.$viewValue;
}, function(newVal) {
  scope.myVar = newVal;
})

所以这里发生的是,如果$ viewValue发生了变化(即,我们将一些来自http服务的数据等分配给dataModel绑定,$ watch函数将捕获它并将其分配给范围。 myVar.ui-select脚本中的$ watch函数监视范围。$ parent.myVar用于更改(我们告诉它在其父级的范围内观察变量)。如果它看到任何更改,则将它们推送到 $select.selected - 这就是ui-select通过单击下拉列表中的项目来保留已选择的任何值的地方。我们只需覆盖它并插入我们想要的任何值。

<强> Plunker - Two-way binding

答案 1 :(得分:0)

首先,dataModel是一个字符串。由于您定义了multiple,因此模型将是一个数组。

更重要的是uiSelect指令创建了一个新范围。这意味着ng-model="ngModel"不再指向dataModel。你有效地破坏了绑定。

在你的控制器中使dataModel成为一个对象:

$scope.dataModel = {};

在您的指令中,让选定的值绑定到属性:

return '<ui-select multiple ng-model="ngModel.selection"

现在所选的值将绑定到dataModel.selection

如果您不使用ngModelController,则不应在您的指令中使用ng-model