2014-02-27 70 views
24

我创建了一个生成Twitter按钮的指令。由于这些按钮上的范围变量可能会更改,所以我需要在发生按钮时重新生成按钮。目前,我使用jQuery来链接元素empty()并重建按钮。如何在Angular指令中重新呈现模板?

app.directive 'twitterShare', ($timeout, $window) -> 
    restrict: 'E' 
    template: '<a href="https://twitter.com/share" class="twitter-share-button" data-text="{{ text }}" data-url="{{ url }}">Twitter</a>' 
    scope: 
     text: '@' 
     url: '@' 
    link: (scope, el, attrs) -> 
     scope.$watch 'text', -> rebuild() 
     scope.$watch 'url' , -> rebuild() 

     rebuild = -> 
      $(".twitter-share-button").remove() 
      tweet = $ '<a>' 
      .attr 'href', 'https://twitter.com/share' 
      .attr 'id', 'tweet' 
      .attr 'class', 'twitter-share-button' 
      .attr 'data-lang', 'en' 
      .attr 'data-count', 'none' 
      .text 'Tweet' 

      el.prepend tweet 
      tweet.attr 'data-text', scope.text 
      tweet.attr 'data-url', scope.url 
      $window.twttr.widgets.load() 

有什么办法让指令完全重新渲染模板吗?

回答

45

这里是你可以使用,将重建transcluded内容的可重复使用的指令时发送的事件:

app.directive('relinkEvent', function($rootScope) { 
    return { 
     transclude: 'element', 
     restrict: 'A', 
     link: function(scope, element, attr, ctrl, transclude) { 
      var previousContent = null; 

      var triggerRelink = function() { 
       if (previousContent) { 
        previousContent.remove(); 
        previousContent = null; 
       } 

       transclude(function (clone) { 
        element.parent().append(clone); 
        previousContent = clone; 
       }); 

      }; 

      triggerRelink();     
      $rootScope.$on(attr.relinkEvent, triggerRelink); 

     } 
    }; 

}); 

这里是一个的jsfiddle demoing它是如何工作:http://jsfiddle.net/robianmcd/ZQeU5/

请注意,每次单击“触发器重新链接”按钮时,输入框的内容会被重置。这是因为每当触发事件时,输入框都将被删除并添加到DOM。

您可以按原样使用此指令或对其进行修改,使其由scope.$watch()而不是事件触发。

+1

按照OP的例子,在使用模板的情况下应如何使用transclude功能?当我尝试为这个例子添加一个模板时,它似乎没有被使用 - 我猜是因为克隆。 – StephenT

+0

伟大的东西伙伴,我真的需要这样的东西。我已经添加了一个$编译选项,以便我可以重新编译一个组件。我将在底部发布这些更改。 – Mattijs

5

几个建议:

  1. 使用指令模板,并绑定变量的范围,而不是手动创建HTML。在这种情况下,您不需要重新渲染模板。当范围属性更改时,Angular会自行更新它。

  2. 使用attrs.$observe功能上运行的属性值变化部分代码

+0

你会注意到我已经在使用模板并绑定了范围变量。但是,这并没有重建Like按钮,因为如果iframe已经存在,它不会重建iframe。除非该twitter-share-button元素被删除并重新创建,否则$ window.twttr.widgets.load()什么也不做。 – Soviut

-1

使用ng-bind =“value”而不是{{value}}为我刷新了我的指令模板缓存。

<myDirective><span ng-bind="searchResults.leads.results.length"></span></myDirective> 

代替

<myDirective><span>{{searchResults.leads.results.length}}</span></myDirective> 
+0

似乎并不是一个可靠的方法来实现这个 – Batavia

1

另一种方式实现这一目标是利用NG-IF的。

例如: <myDirective ng-if="renderdirective"></myDirective>

该指令将不会被创建,直到你renderdirective是不正确的。如果您希望删除该指令并使用新的属性值重新创建它,这也可以用其他方式工作。

0

上@rob答案小的变化:

import * as angular from 'angular'; 

class ReRenderDirective implements angular.IDirective { 

    public restrict = 'A'; 
    public replace = false; 
    public transclude = true; 
    constructor(private $rootScope: angular.IRootScopeService, private $compile: angular.ICompileService) { 

    } 

    public link = (
    scope: angular.IScope, 
    element: angular.IAugmentedJQuery, 
    attr: any, 
    modelCtrl: any, 
    transclude: angular.ITranscludeFunction) => { 

    let previousContent = null; 

    let triggerRelink =() => { 
     if (previousContent) { 
     previousContent.remove(); 
     previousContent = null; 
     } 

     transclude((clone) => { 
     element.append(clone); 
     previousContent = clone; 

     element.html(attr.compile); 
     this.$compile(element.contents())(scope); 
     }); 

    }; 

    triggerRelink(); 
    this.$rootScope.$on(attr.reRender, triggerRelink); 

    } 

} 

export function reRenderFactory(): angular.IDirectiveFactory { 

    var directive = ($rootScope: angular.IRootScopeService, $compile: angular.ICompileService) => new ReRenderDirective($rootScope, $compile); 
    directive.$inject = [ '$rootScope', '$compile' ]; 
    return directive; 
} 

使用此搭配:

<div re-render="responsive"> 
    <header-component/> 
</div> 

,并以$广播的地方在你的代码结合起来:

this.$rootScope.$broadcast('responsive'); 

我确实,是听取页面大小调整,然后触发广播。 基于此,我可以将组件的模板从桌面更改为移动。由于该示例中的header-component已被截断,因此它会被重新编译并重新编译。

这对我来说就像一个魅力。

感谢Rob让我走上正轨。

+0

其实我发现我可以为这个名为'ng-if'的本地指令。我只需确保具有ng-if的标签被呈现,并且当它需要重新渲染时,布尔值应该为false,然后添加一个$ timeout为0以将其设置为true。这样它重新渲染组件:) :) – Mattijs

相关问题