【问题标题】:How can I get directive to fire after view loaded?加载视图后如何获得指令触发?
【发布时间】:2013-05-13 18:13:08
【问题描述】:

我知道这已经被问了一千次了,但我想我已经尝试了我读过的每一个解决方案,但我似乎无法让它发挥作用。

我有一个 API 从中获取图像,在将图像拉入视图后,我希望它们使用 photoswipe 在移动设备上显示。

我有一个指令:

'use strict';

App.directive('photoswipe', function () {
return {
    replace: false,
    restrict: 'A',
    link: function photoSwipeLink(scope, element, attr) {
      scope.$watch(attr.photoswipe, function(value){
        angular.element('#gallery a').photoSwipe({
          enableMouseWheel: false,
          enableKeyboard: false
        });
      });
    }
  };
});

我在控制台中收到此错误:

Code.PhotoSwipe.createInstance: No images to passed.

我猜这是因为指令在视图渲染之前运行。

如果我添加一个 $timeout 而不是 watch,那么代码就可以工作。不幸的是,这个解决方案并不好,因为从 API 获取数据可能会有延迟。此外,代码在超时内不起作用。

我试过了,上面的代码,我试过使用$viewcontentloaded,试过在ng-repeat的最后一个元素之后触发函数,但都不管用。

任何帮助将不胜感激。

编辑:

这是 HTML。

<h1>{{ gallery.headline }}</h1>
<ul id="gallery" photoswipe>
  <li class="gallery" ng-repeat="image in gallery.images">
    <a href="{{ image.url }}" alt="image.caption">
      <img ng-src="{{ image.thumb_url }}" class="thumb" alt="{{ image.caption }}" style="display: block;">
      <h3 class="headline">{{ image.caption }}</h3>
    </a>
  </li>
</ul>

【问题讨论】:

  • #gallery a 是什么?
  • 这个指令是在哪里添加的?你能用指令发布你的 HTML 吗?

标签: angularjs angularjs-directive photoswipe


【解决方案1】:

我认为这是因为 Angular 在结果绑定到列表之前处理您的指令。这可能是一种竞争条件。解决这个问题的一种方法是这样做

$scope.$broadcast("picsDownloaded" ... 

在你得到结果后在你的控制器中发生事件。 在指令上,而不是

scope.$watch(attr.photoswipe ....

这样做

scope.$on("picsDownloaded" ....

并在该处理程序中应用 Jquery 插件。

【讨论】:

  • 尝试了上述方法,我得到了同样的错误。我将 $broadcast 放在 $resource 回调上,这样数据就在那里。我认为这可能是插件的工作方式,在指令运行之前项目必须在 DOM 中。我会试着把它放在小提琴里然后贴出来。
  • 只是为了确定...为了使$broadcast 工作,您的指令需要位于制作$broadcast 的父控制器范围内的元素中,除非您使用$rootScope.$broadcast我不推荐。
【解决方案2】:

是的,您可以使用事件在数据存在时发出信号。尽管您可能必须使用 $rootScope,但这取决于用例。

但我认为您的错误最可能的原因是,AngularJS 第一次使用未定义的值初始化它们时调用了所有 $watchers。

您应该检查一下您的 $watch 函数是否可以立即解决您的问题。

【讨论】:

    【解决方案3】:

    正如其他人指出的那样,您需要等到所有这些东西都被渲染出来,这只有在您的 api 调用返回结果后才会发生。您的指令的信号将是 gallery.images 数组的更改。所以,让你的指令像下面这样监视它。

    请注意新引入的隔离作用域 - 对我来说,它听起来应该是隔离的,但我不能肯定地说,因为我不知道你的应用程序代码的其余部分。

    无论如何,它告诉 Angular,模板中 photoswipe 属性中使用的任何值(见下文)都应绑定到指令范围的 images 属性。使用这样的构造可确保在 gallery.images 的每一次更改上都会发生这种情况,无论何时以及如何发生。您需要在外面做的只是在 api 调用完成时更改集合,其余的就可以了。没有事件(对我来说,它们在 Angular 1.x 中非常麻烦),不同组件之间没有联系,没有混合关注点。非常干净的解决方案。但是,您需要了解$watchCollection() 的工作原理,它与常规的$watch 有点不同,它执行浅集合扫描并且不比较集合中的对象本身,而只比较它们的引用。

    另一个重要的时刻是清理。您必须确保从集合中删除某些内容时,相应的事件以及插件绑定到元素的任何其他内容都被正确销毁,否则您最终会遇到内存泄漏、意外事件和性能不佳。

    App.directive('photoswipe', function ($timeout) {
    return {
        replace: false,
        restrict: 'A',
        scope: {
            "images": "=photoswipe"
        },
        link: function photoSwipeLink(scope, element, attr) {
            scope.$watchCollection('images', function(value){
                // here $timeout() is necessary because this event will be fired
                // immediately after collection change
                // thus not giving angular time to render it
                // so, jquery plugin will be fired on the next angular digest
                // and everything will be rendered by then.
                $timeout(function () {
                    angular.element('#gallery a').photoSwipe({
                        enableMouseWheel: false,
                        enableKeyboard: false
                    });
                    // and now figure out how to clean it up!
                });
            });
        }
      };
    });
    

    现在到模板。请注意,我第一次使用photoswipe="gallery.images" 属性。这就是告诉 Angular 将 gallery.images 绑定到 photoswipe 指令的范围到 images 属性的原因。

    由于指令现在引入了自己的隔离范围,因此它内部的所有内容都应考虑到这一事实。这就是为什么ng-repeat="image in images"

    <h1>{{ gallery.headline }}</h1>
    <ul id="gallery" photoswipe="gallery.images">
      <li class="gallery" ng-repeat="image in images">
        <a href="{{ image.url }}" alt="image.caption">
          <img ng-src="{{ image.thumb_url }}" class="thumb" alt="{{ image.caption }}" style="display: block;">
          <h3 class="headline">{{ image.caption }}</h3>
        </a>
      </li>
    </ul>
    

    老实说,我没有测试这段代码,但除了可能的语法错误之外,它应该可以工作。另外,我想再强调一次,我不知道你的应用程序其余部分的结构,所以如果你的指令中的某些东西被绑定到更高的范围,那么引入隔离范围可能会破坏它 - 但对我来说这是个坏主意因为它在组件之间引入了隐藏的互连。

    【讨论】:

      猜你喜欢
      • 2014-06-12
      • 2016-05-30
      • 2017-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      相关资源
      最近更新 更多