directive : ng-repeat before call jquery plugin (using transclude ?)

3,786 views
Skip to first unread message

war...@gmail.com

unread,
Aug 28, 2012, 7:27:08 AM8/28/12
to ang...@googlegroups.com
Hi,

Short description :
I would like to apply a jQuery plugin after ng-repeat apply on a directive.

Long description : 

HTML : 
<select data-placeholder="Choose..." ng-model="groups" multiple chosen>
     <option value="{{group.id}}" ng-repeat="group in groups">{{group.name}}</option> 
</select>

I tried by compiling myself and using $apply() before I call the plugin. It works but angularjs thow an exception on $apply() saying that apply is already under processing. Regarding documentation it seems normal.
directives.directive('chosen', function($compile){
return {
        restrict:'A',
        link: function(scope, element, attrs)
        {
        //First we need to compile inside the <select/> tag to ensure that <option ng-repeat /> is compiled
        $compile(element.contents())(scope);
        //Then we tell AngularJS to reflect it in the DOM
        scope.$apply(); //This thow an exception (how to do in an other way?)
        //Then we apply our Chosen jQuery plugin
        $(element).chosen();
        }
    }
});

So I tried using transclude property (without $compile()and without $apply()) but it doens't work : options elements are not visible for the plugin 'chosen'. So the result is an empty list.


I would like to tell angularjs to compile ng-repeat before I call the jQuery plugin. I was thinking that transclude would be the solution but it seems that I missed something here...

Any good tips on this? 

Thank you,

war...@gmail.com

unread,
Aug 28, 2012, 9:03:25 AM8/28/12
to ang...@googlegroups.com, war...@gmail.com
I found a way to do it without any exception. However, I don't know if it's a the easiest way to do.


I implement the 'link' of my directive this way (I do not used transclude property for the directive) :

        link: function(scope, element, attrs)
        {
var promise = applyChosen(scope, element, $q);
  promise.then(function() {
    // alert('Success');
  }, function(reason) {
    // alert('Failed: ' + reason);
});
         }

Here is the implementation of applyChosen() :

function applyChosen(scope, element, $q) {
  var deferred = $q.defer();
  setTimeout(function() {
    // since this fn executes async in a future turn of the event loop, we need to wrap
    // our code into an $apply call so that the model changes are properly observed.
    // (Btw it works without...)
    scope.$apply(function() {
    $(element).chosen();
    });
  });
  return deferred.promise;
}

Any body know if it's the good way to do? If not what do you recommend?

I would be happy to get feedback on this because I'm not sure to understand everything yet.

Max


Thank you,

Maxence Warzecha

unread,
Aug 29, 2012, 11:28:05 AM8/29/12
to ang...@googlegroups.com, war...@gmail.com
Solution is tricky :/ it's work only because of the delay... arg...

Any advice?

Max

Andy Joslin

unread,
Aug 29, 2012, 11:31:59 AM8/29/12
to ang...@googlegroups.com
Try $watching the model that holds the list, then re-apply the jquery plugin when it changes.

scope.$watch(attrs.list, function() {
  //I've changed! $.dostuff()
})

Maxence Warzecha

unread,
Aug 29, 2012, 11:39:16 AM8/29/12
to ang...@googlegroups.com
Thanks for reply.  I test right know.  

Maxence Warzecha

unread,
Aug 29, 2012, 12:05:11 PM8/29/12
to ang...@googlegroups.com
Unfortunately I'm not able to make it work.

hummm... I keep thinking...



On Wednesday, August 29, 2012 5:31:59 PM UTC+2, Andy Joslin wrote:

Godmar Back

unread,
Aug 29, 2012, 12:11:37 PM8/29/12
to ang...@googlegroups.com
My understanding is that $watcher are fired on model changes. When
the model changes, the view update may or may not have completed. I
encountered a similar/same issue.

Angular doesn't have a way to tell when the view update that follows a
model update has completed, and they're not willing to provide one,
see https://github.com/angular/angular.js/issues/1306

So, you need to wrap your jQuery plugin in a directive, so it's
invoked when Angular updates the view.

- Godmar
> --
> You received this message because you are subscribed to the Google Groups
> "AngularJS" group.
> To post to this group, send email to ang...@googlegroups.com.
> To unsubscribe from this group, send email to
> angular+u...@googlegroups.com.
> Visit this group at http://groups.google.com/group/angular?hl=en.
>
>

Roy Choo

unread,
Aug 29, 2012, 12:19:48 PM8/29/12
to ang...@googlegroups.com
Hi,

how about a checkLast directive?

in the below example, i am applying the jquery only after the last element

http://jsfiddle.net/roychoo/XVzUW/3/

http://docs.angularjs.org/api/ng.directive:ngRepeat

Regards
Roy

Maxence Warzecha

unread,
Aug 30, 2012, 4:49:48 AM8/30/12
to ang...@googlegroups.com
Initial idea was to use the jQuery Plugin Chosen.

I do not use ng-repeat anymore but I use the standard ng-options.

I found an integration made by simpulton : https://github.com/simpulton/angular-chosen

This is my current forked version : https://github.com/laguiz/angular-chosen

Let me know if you see something wrong.

Thanks for help. 

Max

f.lek...@googlemail.com

unread,
Sep 7, 2012, 1:00:47 PM9/7/12
to ang...@googlegroups.com
It seems that the outer directive, the one you apply chosen, does not wait till the DOM has been rendered by the inner directive (ng-repeat).
If you need to know when it is ready you can apply an extra directive on the <li ng-repeat="..." my-directive>...</li>
This "my-directive" could for example broadcast an event so that chosen or any other jQuery plugin knows that the ng-repeat is ready.


I hope they introduce an event so that the outer directive knows when the ng-repeat is done but so far this seems to be the best way to handle this issue.

Best Fritz

Jared Jensen

unread,
Feb 17, 2013, 5:15:49 PM2/17/13
to ang...@googlegroups.com
I've been fighting with this all day and can't seem to make it work.  I'm using a variation of https://github.com/simpulton/angular-chosen where I added a "watch" attribute that lets me specify what the directive should watch to trigger the "liszt:updated" event.

In my actual app, it doesn't throw errors, but the index is off (i.e. the chosen-ized element shows the option I selected, but the model gets set to the next higher element in the array).  When I tried to repro in a fiddle, I get a "cannot set property 'nodeValue' of undefined" error: http://jsfiddle.net/jaredjensen/mzabB/

I think I've been staring at this too long.  Can anyone see what I'm doing wrong?

mohamed ame

unread,
Dec 10, 2014, 2:07:29 PM12/10/14
to ang...@googlegroups.com
Hello,
Did you try
scope.$applyAsync(function(){
$(element).chosen();
}); 

 
 
 
Reply all
Reply to author
Forward
0 new messages