【问题标题】:How to wait till the end of $compile in angularJS如何在angularJS中等到$compile结束
【发布时间】:2015-07-23 13:39:49
【问题描述】:

我正在加载一个模板,然后使用$compile 服务针对我的范围编译它。

var template = "<div> .. {{someCompilingStuff}} ..</div>";
var compiled = $compile(template)(cellScope);

然后在弹出窗口中使用它

cellElement.popover({
    html: true,
    placement: "bottom",
    trigger: "manual",
    content: compiled
});

我的模板相当复杂,可能需要一些时间来编译。

如何确保 Angular 在弹出框中使用模板之前已完成编译?

编辑:我尝试在创建弹出框之前将 angular 强制设置为 $apply(),它确实有效,但会生成我无法接受的 javascript 错误。

【问题讨论】:

  • 但是$compile服务返回link函数,你希望你是怎样的html?
  • 一种方法是使用 $applyAsync 或 $evalAsync 或 $$postDigest
  • 这是什么.popover?这是一个引导组件吗?如果是这样,它不期望一个字符串或一个函数,而你正在传递一个元素 (compiled)
  • 这是引导弹出框,是的。并且编译函​​数似乎返回一个 DOM 对象,女巫被 popover.content 接受。我的代码正在运行,但弹出框是使用未编译的内容创建的,然后内容编译并按预期替换弹出框内的文本,但由于弹出框内容的长度发生了变化,我有视觉错误。这就是为什么我想用编译后的内容而不是模板来创建弹出框
  • @kyori,您能提供示例plunker 与您的代码吗?

标签: javascript angularjs


【解决方案1】:

$compile 允许您使用所谓的克隆附加功能,该功能允许您将元素附加到文档。这是一个您可以使用的示例:

var template = "<div> .. {{someCompilingStuff}} ..</div>";
var compiled = $compile(template)(cellScope, function (clonedElement) {
  cellElement.popover({
    html: true,
    placement: "bottom",
    trigger: "manual",
    content: clonedElement
  });
});

Reference to Angular documentation about $compile usage

【讨论】:

  • 它允许您在链接之前附加克隆节点 - 这究竟如何解决 OP 的问题或回答 OP 的问题?
  • 我认为重要的是要注意(考虑到语法),$compile(arg) 返回一个函数。这就是为什么您可以在超时期间依赖这种类型的执行...回调仅在 $compile 函数完成后执行。但是,没有任何承诺(没有双关语)DOM 已经完成了模板的绘制。
  • 虽然在这种情况下直接回答了这个问题,但它不会起作用(阅读 Simon Groenewolt 的回答)。这是您的示例:jsfiddle.net/q47jbnq4
  • @JoeJohnson,不清楚你在说什么。 cloneAttach(回调函数,正如你所说的那样)执行 prior 到返回链接 DOM 元素的链接函数。 $compile函数返回一个函数,没错——就是上面提到的链接函数。无论如何,我看不出这个答案实际上是如何回答这个问题的,所以我对投票感到困惑
  • 我遇到了与 OP 的问题类似的问题。在我的例子中,我在打开它之前将编译指令附加到隐藏的 div #modal,但有时 #modal 会打开为空,因为指令尚未完成编译。使用此方法通过确保元素在打开模态之前实际上已准备好来解决问题。
【解决方案2】:

在这些情况下,您可能希望使用$timeout 来解决问题。

类似这样的:

var template = "<div> .. {{someCompilingStuff}} ..</div>";
var compiled = $compile(template)(cellScope);
cellElement.popover({
   html: true,
   placement: "bottom",
   trigger: "manual",
   content: compiled
 });

$timeout(function(){
    cellElement.popover("show");
}, 0);

这是我为您创建的示例JSFIDDLE。看看我是如何使用$timeout 显示和隐藏弹出框的。

【讨论】:

    【解决方案3】:

    即使当编译/链接功能完全呈现模板时可能会收到通知,您仍然无法确定浏览器是否完成了对页面布局的更改作为响应。您可以通过在触发弹出窗口之前使用$timeout (setTimeout) 引入一个小的延迟来解决您的问题。通过阅读is there a post render callback for Angular JS directive? 上的答案,我认为这可以解决您的问题。

    【讨论】:

    • 除非您要延迟某种类型的动画,否则请始终避免使用任何超时功能。 $timeout(如 window.setTimeout)依赖于系统的时钟“速度”(处理器)。 500 毫秒(毫秒是 JS / 大多数代码中超时的度量单位)。简而言之,根据当前加载到内存中并在用户计算机上运行(尤其包括浏览器中的选项卡)的应用程序的数量,超时 500 毫秒的变化通常是不可预测的。因此,回调和承诺。
    • @JoeJohnson - 使用超时没问题。有些地方(比如这里) $timeout(fn,0) 是一个很好的解决方案。阅读:stackoverflow.com/questions/779379/…
    • 这是一个非常非常古老的帖子。我不同意,不管。超时是不可预测的。
    【解决方案4】:

    我将提供一个非代码答案(这样您就可以深入挖掘并了解原因——而且我在这个时间感到很懒惰):

    我建议将事件委托与另一个父 HTML 元素一起用作可以调用 popover 方法的委托。只需在任何 [父] 元素上包含 class="popover" 并在其中编译模板。您可能能够在该父元素上执行/调用 popover 方法。但是,我不完全确定您不需要子元素(来自模板),因为我不知道该插件。但是,我会尝试超时以外的任何方法。

    我希望这个答案(虽然可能不正确)从作者那里促成一个创造性的解决方案(产生干净、可靠的代码)。

    【讨论】:

      【解决方案5】:

      作为建议,您可以创建一个编译器服务,在其中注入 $compile 并创建一个带有接受 html 和范围的参数的方法。

      在该方法中使用 $deferred 并从您的控制器调用该方法,resolve 会给您一个回调,这是一个编译完成的承诺。

      如果它不适合你,请告诉我,我会为你提供代码示例。

      【讨论】:

        【解决方案6】:
            var template = "<div> .. {{someCompilingStuff}} ..</div>";
        
        cellElement.popover({
          html: true,
          placement: "bottom",
          trigger: "manual",
          content: function () {
            var html = "";
            $compile(template)(cellScope, function (clonedElement) {
              html = clonedElement;
            });
            return html;
          }
        
        });
        

        【讨论】:

          【解决方案7】:

          我会尝试将模板的编译封装在一个返回承诺的函数中。

          类似这样的:

          function compile () {
            var deferred = $q.defer();
          
            /** simulate something sloooow (remove the setTimeout in your implementation) **/
            setTimeout(function () {
              deferred.resolve($compile('content')(scope));
            }, 2000);
          
            return deferred.promise;
          }
          
          // and then ...
          compile().then(function (content) {
            element.popover({
              content: content
            });
          });
          

          'naive' jsbin && jsfiddle (modified @Amir's)

          我不能保证它适用于您的具体情况,但值得一试。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-03-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-08
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多