Reputation: 7752
i have used jQuery slider in my project in which i am loading images using angular. My current view looks like this;
<div id="slides">
<div class="slides_container">
<a href="" data-ng-repeat="image in gallery">
<img data-ng-src="{{image.imageUrl}}" width="919" height="326" alt="" />
</a>
</div>
</div>
the controller;
blogApp.controller("HomeController", ['$scope', '$resource', function ($scope, $resource) {
var basePath = '/api/',
FrontGallery = $resource(basePath + 'gallery?culture=en-US'),
$scope.gallery = FrontGallery.query();
}]);
And the jQuery slider code (to make it a slider. I'm using this plugin http://archive.slidesjs.com/)
$(document).ready(function () {
$('#slides').slides({
preload: true,
preloadImage: '/content/images/theme/loading.gif',
play: 5000,
pause: 2500,
hoverPause: true
});
});
When, i try this code, my all images are loaded from database (debugged it through firebug) but jQuery slider isn't applying the animation or sliding effect to it
And when i remove the data-ng-repeat="image in gallery
and use Some static content i.e images, i get the sliding effect back.
What's the problem here. I think Angular is manipulating some how my DOM. That's why i'm getting this problem whenever i put i.e use some angular attributes on my slider.
Note: i have the same issue with jQuery news i.e jQuery InnerFade
plugin http://medienfreunde.com/lab/innerfade/
Here is how the innerFade
is used;
<h1>
<img src="/content/images/theme/hotnews.png" alt="" />Hot News</h1>
<ul id="news">
<li class="ng-repeat:headline in news">
<span class="ng-bind:headline.description"></span>
<a href="#" title="Read More">» more</a>
</li>
</ul>
and the controller;
var HotNews = $resource(basePath + 'article/hotnews?culture=en-US');
$scope.news = HotNews.query();
How do i fix these problems?
Update 2:
Here is my routes;
// declare a module
var blogApp = angular
.module('blogApp', ['ngResource', 'ngSanitize'])
.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
//$locationProvider.html5Mode(true);
//configure the routes
$routeProvider
.when('/', {
// list the home page
templateUrl: "tmpl/home.html",
controller: "HomeController"
})
.when('/article/:id', {
// access custom param
foo: "hello world",
// list the home page
templateUrl: "tmpl/article.html",
controller: "ArticleController"
})
.when('/404', {
template: '<h1>404 Not Found!</h1>'
})
.otherwise({ redirectTo: '/404' });
}]);
Solution #1:
Temporary, (As @Jason Goemaat answered) works for me. So, here is what i have done. I didn't create any directive
but straightly i injected the $timeout
to my controller and then i did the following;
$timeout(function () {
jQuery('#news').innerfade({
animationtype: 'slide',
speed: 750,
timeout: 2000,
type: 'random',
containerheight: '1em'
});
jQuery('#slides').slides({
preload: true,
preloadImage: 'image/theme/loading.gif',
play: 5000,
pause: 2500,
hoverPause: true
});
}, 100);
And it did work for both i.e for Slider
and for InnerFade
Upvotes: 8
Views: 13609
Reputation: 559
as it was said: "The jQuery slider script should only be activated after angular has loaded the content" So you can wait before it will be loaded, and then your jQuery code will start running.
$(document).ready(function () {
setTimeout(function(){
$('#slides').slides({
preload: true,
preloadImage: '/content/images/theme/loading.gif',
play: 5000,
pause: 2500,
hoverPause: true
});
}, 10);
});
Upvotes: 1
Reputation: 29234
Angular IS manipulating your dom, the ng-repeat directive is creating the elements when it has a list to work from. Because of that you need to call .slides
after angular is done creating the elements because that plugin is altering the DOM itself.
Here's a directive you can use to call $.slides
on an element based on when an array has length > 0. It shows using extra attributes like 'start' to modify the call to slides too. Here it checks an array on your $scope called 'images' and calls $timeout()
during the link phase to call .slidesjs()
when angular is done creating the DOM. I didn't know what plugin you used so I found one called 'slidesjs that looked similar. 'Here's a plunker:
http://plnkr.co/edit/4qdUctYMIpd8WqEg0OiO?p=preview
Html:
<div my-slides="images" start="4">
<img ng-repeat="image in images" ng-src="{{image.url}}" />
</div>
Directive:
app.directive('mySlides', function() {
var directive = {
restrict: 'A',
link: function(scope, element, attrs, ctrl) {
scope.$watch(attrs.mySlides, function(value) {
setTimeout(function() {
// only if we have images since .slidesjs() can't
// be called more than once
if (value.length > 0) {
$(element[0]).slidesjs({
preload: true,
preloadImage: '/content/images/theme/loading.gif',
play: attrs.play || 5000,
pause: attrs.pause || 2500,
start: attrs.start || 1,
hoverPause: attrs.hoverPause || true,
navigation: { active: true, effect: "slide" }
});
}
}, 1);
});
}
};
return directive;
});
One thing to note is that it still can only be called once, so if your image list gets updated it won't work. To do that you could create the content in the directive...
Upvotes: 6
Reputation: 30015
$(document).ready(function () {
is firing before angular has loaded the content onto the page. The jQuery slider script should only be activated after angular has loaded the content. Part of the problem here is that angular does not provide a callback for $digest
so you don't have an event to listen for.
The content load -> event callback -> ui build, while common in jQuery and standard javascript thinking, its not part of the angular mentality. Luckily angular has an insanely powerful method for handling this problem.
What you need is to turn the jQuery slideshow script into an angular directive. Then it will become part of the angular process space and get instantiated as a part of the angular digest cycle.
Something like
<div id="slides" my-slideshow >
<div class="slides_container">
<a href="" data-ng-repeat="image in gallery">
<img data-ng-src="{{image.imageUrl}}" width="919" height="326" alt="" />
</a>
</div>
</div>
Good luck!
Happy example time using innerfade (I have not tested this yet, will do ASAP). First your application must declare an angular module if it doesn't already. ng-app="myModule"
. http://docs.angularjs.org/api/angular.module
(make sure your controller is attached as well!)
Now you can declare a directive on that module. Which is super cool.
angular.module('myModule').directive("innerFade", function () {
var res = {
restrict : 'C',
link : function (scope, element, attrs) {
scope.$watch(attrs.innerFade, function(){
element.innerfade({
speed: 'slow',
timeout: 1000,
type: 'sequence',
containerheight: '1.5em'
});
});
}
};
return res;
});
The way this works is pretty simple. The $watch
function will monitor the part of scope containing your data. When that changes (including initialization), it will fire the innerfade
jQuery function on the element
with the directive. We are also passing 'C' to the restrict argument so this custom directive will be a class only directive (I noticed you seem to like that).
<ul class="inner-fade:innerData" >
<li class="ng-repeat:fadeItem in innerData">{{fadeItem}}</li>
</ul>
Now all you have to do is bind the data to $scope.innerData
in your controller (bind it any way you like including ajax), and it will just work. You can even change the data on $scope.innerData
and it will update with full jQuery glory.
Upvotes: 9
Reputation: 8508
Add a directive to #slides
app.directive("slideDirective", function () {
return function (scope, element, attrs) {
// Dom
element.slides({
preload: true,
preloadImage: '/content/images/theme/loading.gif',
play: 5000,
pause: 2500,
hoverPause: true
});
}
}
Upvotes: 1
Reputation: 27
A few thoughts
1) My guess is that there is something sequentially wrong with your main app page. Do you have jQuery include after angularjs? I assume you are using ng-repeat directive?
2) change $ to jQuery
3) place document.ready script in main page ... also consider replacing it with
window.onload=function(){}
I am sure I can debug if you can show code for main page as well as the view.
Upvotes: 1