AngularJS : Child input directive needs to compile in the scope of its parent for ng-model to bind

标签 angularjs angularjs-directive transclusion

我们有一个在许多应用程序中使用的联系表单。有很多重复的默认值、验证规则、结构等。我们正在研究一组指令,以使 View 更语义化、更简洁。

我们正在瞄准几个目标。

  1. 在父指令中定义一次联系表单模型,如下所示:<div my-form model='formModel'> 。关联的子指令将能够从 model 获取基本模型属性。

  2. 为每个输入提供默认配置(大小、验证规则、占位符、类等),但允许在必要时覆盖属性。因此,我们使用 my-form 创建子指令指令的通信 Controller 。我们还希望这些子指令绑定(bind)到应用程序 Controller 的模型 formModel

我在实现这个时遇到了一些麻烦。

  • formModel通过父指令的 Controller 公开,但我必须手动 $compile子指令使用 scope.$parentlink功能。这对我来说似乎很臭,但如果我尝试使用子指令的作用域,编译后的 HTML 包含正确的属性(它在源代码中可见),但它没有绑定(bind)到 Controller ,并且在以下情况下它不会出现在任何作用域中:用Batarang检查。我猜我添加属性太晚了,但不确定如何更早添加属性。

  • 虽然我可以只使用ng-model对于每个子指令,这正是我想要避免的。我希望生成的 View 非常干净,并且必须在每个字段上指定模型名称是重复的且容易出错。我还能如何解决这个问题?

这是一个jsfiddle它对我想要完成的任务有一个有效但“臭”的设置。

angular.module('myApp', []).controller('myCtrl', function ($scope) {
    $scope.formModel = {
        name: 'foo',
        email: '<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="33555c5c73555c5c5152411d5d5647" rel="noreferrer noopener nofollow">[email protected]</a>'
    };
})
    .directive('myForm', function () {
    return {
        replace: true,
        transclude: true,
        scope: true,
        template: '<div ng-form novalidate><div ng-transclude></div></div>',
        controller: function ($scope, $element, $attrs) {
            $scope.model = $attrs.myModel;
            this.getModel = function () {
                return $scope.model;
            };
        }
    };
})
    .directive('myFormName', function ($compile) {
    return {
        require: '^myForm',
        replace: true,
        link: function (scope, element, attrs, parentCtrl) {

            var modelName = [parentCtrl.getModel(),attrs.id].join('.'),
                template = '<input ng-model="' + modelName + '">';

            element.replaceWith($compile(template)(scope.$parent));
        }
    };
});

最佳答案

有一个更简单的解决方案。

Working Fiddle Here

家长表格指令

首先,为父表单指令建立一个隔离范围,并使用 2 路绑定(bind)导入 my-model 属性。这可以通过指定 scope: { model:'=myModel'} 来完成。实际上没有必要指定原型(prototype)范围继承,因为您的指令没有使用它。

您的隔离作用域现在已导入“模型”绑定(bind),我们可以使用此事实来编译和链接子指令针对父作用域。为此,我们将从父指令中公开一个compile 函数,子指令可以调用该函数。

.directive('myForm', function ($compile) {
return {
    replace: true,
    transclude: true,
    scope: { model:'=myModel'},
    template: '<div ng-form novalidate><div ng-transclude></div></div>',
    controller: function ($scope, $element, $attrs) {
        this.compile = function (element) {
            $compile(element)($scope);
        };
    }
}; 

子现场指令

现在是时候设置您的子指令了。在指令定义中,使用 require:'^myForm' 指定它必须始终位于父表单指令中。在编译函数中,添加 ng-model="model.{id attribute}"。不需要弄清楚模型的名称,因为我们已经知道“模型”将在父范围中解析为什么。最后,在链接函数中,只需调用您之前设置的父 Controller 的编译函数即可。

.directive('myFormName', function () {
return {
    require: '^myForm',
    scope: false,
    compile: function (element, attrs) {
        element.attr('ng-model', 'model.' + attrs.id);
        return function(scope, element, attrs, parentCtrl) {
            parentCtrl.compile(element);

        };
      }
   };
});

这个解决方案是最小的,只需很少的 DOM 操作。它还保留了针对父范围编译和链接输入表单字段的初衷,并尽可能减少干扰。

关于AngularJS : Child input directive needs to compile in the scope of its parent for ng-model to bind,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21943242/

相关文章:

Angular 模板和嵌入 : content out of order

javascript - CasperJS 在 AngularJS 上运行不佳

javascript - Angular : ng-controller on directive does not work on transcluded elements within directive

javascript - AngularJS:使用自定义服务转换 $resource 中的响应

javascript - AngularJs 指令 - &lt;script&gt; inside template

javascript - 从另一个指令获取指令的属性?

angularjs - 在来自外部 Controller $scope 的指令中设置 ng-disabled

components - Angular 2 - 嵌入子组件

javascript - Angular JS - 在 View 渲染之前获取指令中的元素高度

javascript - 如何检测 div 中选定的文本?