angular / angular.js

AngularJS - HTML enhanced for web apps!
https://angularjs.org
MIT License
58.83k stars 27.51k forks source link

Expressions(in templates) are not evaluated in $watch of custom directive of angularjs #1441

Closed abdulazeezsk closed 12 years ago

abdulazeezsk commented 12 years ago

This can be found here as well, http://stackoverflow.com/questions/12748392/expressions-are-not-evaluated-in-watch-of-custom-directive-of-angularjs

I have a below custom directive in angularjs which uses model thats gets updated from server, I have added a watch listener to watch the changes of that model,

var linkFn; linkFn = function(scope, element, attrs) { scope.$watch('$parent.photogallery', function(newValue, oldValue) { if(angular.isUndefined(newValue)) { return; } var $container = element; alert($container.element); $container.imagesLoaded(function() { $container.masonry({ itemSelector : '.box' }); }); }); }; return { templateUrl:'templates/Photos_Masonry.htm', replace: false, transclude:true, scope: { photogallery: '=photoGallery', }, restrict: 'A', link: linkFn However, when i debug in my watch directive, i still see that expressions in templates are still unresolved.i.e. photo.label, ng-src all are still unresolved. AFIK, $digest would be called only after $eval. Is this intended behavior? My jQuery calls are not working due to this? Is there any other event where i get the result element with evaluated expressions?

Here is my template, which has ng-repeat in it,

Stanley

{{galleryname}}

{{photo.seasonname}}

photogallery is initialized in parent controller,

function MyCtrlCampaign($scope, srvgallery, mygallery) {

$scope.updatedata = function() {
    $scope.photogallery     = srvgallery.getphotos($routeParams);
};

$scope.getphotos = function() {
    srvgallery.photos().success(function(data) {
        $scope.updatedata();
    }).error(function(data) {

    });
};

Directive is used in below way,

Kindly let me know your views on this.

kstep commented 12 years ago

At first I noticed you pass photoGallery var from main scope into directive scope under the name of photogallery, but you set scope.$watch on $parent.photogallery. Which var name is valid? You should do scope.$watch on photogallery (no $parent), or maybe you mistyped your var name and you should scope.$watch photoGallery?

kstep commented 12 years ago

Second, it's not clear for me how do you name your directive. Is it really masonry only, or has some prefix? Do you spell your directive name consistently both in your HTML and JS code?

kstep commented 12 years ago

Third I noticed you call masonry in imagesLoaded callback, thus out of digest run. Try wrapping this call into scope.$apply(function () {}).

abdulazeezsk commented 12 years ago

Hi, Thanks for the reply. Listener is not being called if i do watch on local scope(.i.e.photogallery). So, i had to watch on parent.photogallery I am not sure about the reason for this, may be because of isolated scope.

I have named directive just masonry and call to directive is working fine. The main issue is expressions in directive's template are not being evaluated by the time my watch listener gets called. Actual problem lies with the element tag which is not completely evaluated yet.

I need a place where i get complete evaluated element tag of directive.

kstep commented 12 years ago

So, your problem is you can't handle the event of DOM elements creation by ng-repeat directive. You need to apply directive to ng-repeat'ed element to do it. Please see the working example here: http://jsfiddle.net/kstep/j25aj/9/

abdulazeezsk commented 12 years ago

Hi, Thanks for providing the fiddle. I tried to debug the code in fiddle and added following alert in masonry-item directive. alert(elem.html()). It still gives me unevaluated image tag,

Jquery imageloaded function expects something like < img src=" http ://..."> This required input even this tag gets evaluated.

Any help on that? (where item.media.m is evaluated)

kstep commented 12 years ago

My debug shows me <img src="http://farm9.staticflickr.com/8042/8066371085_942617d509_m.jpg" ng-src="http://farm9.staticflickr.com/8042/8066371085_942617d509_m.jpg">, and it renders all fine consistently.

You can also try this version if you are still unsure of results (I use $compile to force nodes compilation before .imagesLoaded() call).

If this doesn't satisfy your needs, I can't help you further, sorry.

abdulazeezsk commented 12 years ago

I just added console.log(elem.html()); gives . Also, why is there only one log? Shouldn't post link function get called for all the items in ng-repeat? Here, is the fiddle, http://jsfiddle.net/j25aj/12/

However functionality is working like champ. Will try it out in my code. Thanks for all the help you have provided since last two days. It really helped me a lot.

btford commented 12 years ago

@kstep, thanks for the help answering this! I'm going to tentatively close the issue. If needed, I can reopen it. Just let me know. :)