【问题标题】:Transclude function needs to modify clone properlyTransclude函数需要正确修改clone
【发布时间】:2016-07-07 15:26:18
【问题描述】:

我有一个简单的指令,它将一段嵌入的内容重复两次。像这样。

link: function (scope, element, attrs, controller, transclude) {

    transclude(scope.$parent, function(clone) {
        element.find('[transclude-main]').replaceWith(clone);
    });

    transclude(scope.$parent, function(clone) {
        element.find('[transclude-overflow]').replaceWith(clone);
    });

});

这主要按预期工作,但如果内容包含一个表单,那么我最终会得到两个具有相同名称的表单。

更重要的是,我的主页控制器(客户)仅引用其中一种表单(customers.myForm),因此如果我尝试重置表单或调用任何其他表单控制器功能,显然只有其中一种表单发生变化。

因此,我尝试修改我的代码以查找表单并将表单名称更改为新名称,例如这样。

link: function (scope, element, attrs, controller, transclude) {

    transclude(scope.$parent, function(clone) {
        element.find('[transclude-main]').replaceWith(clone);
    });

    transclude(scope.$parent, function(clone) {

        clone.find('FORM').each(function() {
            $(this).attr('name', $(this).attr('name') + '2');
        });
        element.find('[transclude-overflow]').replaceWith(clone);

    });

});

这确实为我修改了 HTML,我最终得到了两个表单 - myForm 和 myForm2。

问题是我的主控制器中仍然只有一个对 myForm 的引用。第一个有效,但第二个无效。我只能假设它们是以某种方式针对 scope.$parent 编译的,在我弄乱克隆之前,我将其传递给 transclude 函数?如果是这种情况,我不知道如何解决。

编辑:

在此处添加了一个 plunkr:

https://plnkr.co/edit/XE7REjJRShw43cpfJCh2

如果您打开开发控制台,您会看到我正在使用 console.log 写出 myForm 和 myForm2 的内容,这应该是我的第二个工具栏中的表单的两个副本。 myForm2 不存在,我怀疑这是因为它是在克隆之前针对父范围编译的。

【问题讨论】:

  • “我的主控制器中仍然只有一个对 myForm 的引用”是什么意思?你能链接到一个 plunker 吗?
  • 我还没有真正使用过 Plunkr,但会试一试。
  • Plunkr 补充说:)我还在这里提出了一个后续问题,询问是否可以在不包含嵌入的情况下完成此操作。如果可以在这个有赏金的问题上得到答案,那么我很乐意删除另一个问题。 stackoverflow.com/questions/38332873/…
  • 您的 plunkr 中既不存在 $scope.myForm 也不存在 $scope.myForm2(从您的 2 个 console.log 打印)?
  • 在 plunkr 中,您似乎也在尝试查找不存在的 FORM 元素?

标签: javascript angularjs angularjs-ng-transclude transclusion


【解决方案1】:

所以这里有一个 plunkr,我认为你正在尝试做的事情:https://plnkr.co/edit/8VxNPVmeLNLKyaQNReM3?p=preview

请特别注意以下几行:

HTML:

  <toolbar name="myForm" form-one="myForm1" form-two="myForm2">
    <form name="myForm" submit="appController.submit()">
      Search:<br />
      <input type="text" ng-model="appController.searchText" />
    </form>
  </toolbar>

请注意,两个name 属性都指向同一个字符串"myForm"form-oneform-two 是普通的双向绑定,可以绑定到您选择的范围属性,在我的示例中,myForm1myForm2

JS:

双向绑定定义

    scope: {
      formOne: '=',
      formTwo: '='
    },

并将两个新表单绑定到各自的范围属性:

    link: function (scope, element, attrs, controller, transclude) {

        var parent = scope;

        transclude(function(clone, scope) {
            element.find('[transclude-main]').replaceWith(clone);
            var unwatch = scope.$watch(attrs.name, function(form) {
              if (form) {
                parent.formOne = form;
                unwatch();
              }
            });
        });

        transclude(function(clone, scope) {
            element.find('[transclude-overflow]').replaceWith(clone);
            var unwatch = scope.$watch(attrs.name, function(form) {
              if (form) {
                parent.formTwo = form;
                unwatch();
              }
            });
        });

回顾你的代码,这个控制台console.log("myForm", $scope.myForm2)打印了undefined,因为角度form指令are not dynamic。因此,手动查找 html 元素并将名称从 myForm 更改为 myForm2 不会更改绑定到范围的表单的名称,除非 html 尚未编译。但是the clone passed to transclude has been freshly compiled

【讨论】:

  • 感谢 jbmilgrom,但我显然没有解释我想要做得很好。我不能对工具栏指令上的表单使用绑定,因为我的指令的用户可以将任何东西放入工具栏中,一个表单,没有表单甚至十个表单。无论他们放入什么都必须被克隆,这样做我需要在任何需要具有唯一名称的表单名称(实际上是输入名称)上附加一个“2”。你写的最后一段是我的问题,因为我需要克隆内容然后编译它。不确定我可以通过嵌入来做到这一点,因此是后续问题。
  • 啊,是的,你可能想避免嵌入。一旦您获得访问权限,所有嵌入的模板都将被预编译。考虑使用指令 api 的compile 属性来获取预编译的模板进行操作。祝你好运
  • 谢谢。我会给你声誉点数,因为这真的对我有帮助,而且从技术上讲,这是正确的答案,因为我不能做我想做的事。
猜你喜欢
  • 1970-01-01
  • 2012-10-22
  • 2018-06-29
  • 2012-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多