我知道这已被问了一千次,但我想我已经尝试了所有我已经阅读的解决方案,而且我似乎无法让它发挥作用。
我有一个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>
答案 0 :(得分:3)
我认为这种情况正在发生,因为Angular在结果绑定到列表之前正在处理您的指令。这可能是竞争条件。解决这个问题的一种方法是做
$scope.$broadcast("picsDownloaded" ...
获得结果后,在控制器中发生事件。 在指令上,而不是
scope.$watch(attr.photoswipe ....
这样做
scope.$on("picsDownloaded" ....
并在该处理程序中应用Jquery插件。
答案 1 :(得分:0)
是的,您可以使用事件在数据存在时发出信号。虽然您可能必须使用$ rootScope,但取决于用例。
但我认为你的错误最可能的原因是,AngularJS首次使用未定义的值初始化它们时会调用所有$ watchers。
你应该检查你的$ watch功能,可以立即解决你的问题。
答案 2 :(得分:0)
正如其他人指出的那样,你需要等到所有的东西都被渲染,这只有在你的api调用返回结果后才会发生。您的指令的信号将是gallery.images
数组的更改。所以,让你的指令像下面那样注意它。
请注意新推出的隔离范围 - 对我而言,它听起来应该是孤立的,但我无法确切地说出来,因为我不知道您的其他应用代码。
无论如何,它告诉angular,模板中photoswipe
属性中使用的任何值(见下文)都应绑定到指令范围的images
属性。使用这样的构造可以确保gallery.images
的每次更改都会发生这种情况,无论何时以及如何发生。你需要在外面做的只是在api调用结束时改变集合,剩下的就行了。没有事件(对我来说,它们在角度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>
老实说,我没有测试这段代码,但除了可能的语法错误之外,它应该有效。另外,我想再强调一点,我不知道你的应用程序的其余部分的结构,因此如果你的指令中的某些东西被绑定到某个更高的范围,引入隔离的范围可能会破坏它 - 但对我来说这是个坏主意本身是因为它引入了组件之间隐藏的互连。