Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Plugins Doesn't Work Well with Angularjs

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

like image 801
Idrees Khan Avatar asked Jun 03 '13 14:06

Idrees Khan


1 Answers

 $(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.

like image 107
Fresheyeball Avatar answered Nov 11 '22 22:11

Fresheyeball