AngularJS and ¤compiler - angularjs

I have started to study angularJs directives. I have an example that I can't understand
The full source code is in the following plunker
var detailTemplate = $compile(element.find("div.detail")
.replaceWith(replacementMarkup));;
return a function.
Here the scope is global, I mean, is the scope of controller and I can see
the collection images (the recipies), I think.....
what I can't understand is how the old div is retrieved
<div class="detail">
<img ng-src="{{recipy.img}}" />
</div>
and how the right image is shown; ng-repeat is called again?
and when I do this:
detailTemplate(scope, function(detail) {
target.replaceWith(detail);
});
Thanks in advance

Related

model is not refresh inside directive after changes

I'a got a template with a directive using objects. That directive modifys an elements in the objects list. I can see the object modification in the template but not inside the directive.
I used angularjs 1.5.8
My template :
<div>
<ul>
<li data-ng-repeat="event in vm.events">
// some html code about event object
</li>
</ul>
<event-directive data-events="vm.events"/>
</div>
The directive template :
<div>
<div data-ng-repeat="event in events" class="event">
<a data-ng-click="edit(event)">Edit</a>
// some detail about event
</div>
</div>
The directive is declared liked that :
function eventDirective(/* dependencies */) {
return {
template: eventTemplate,
scope: {
events: '='
}
}
}
If I modified and event in my directive I can see changes in the main template ng-repeat loop but the changes are not "propagated" to the directive.
I'm sure I'm doing someting wrong or forgot something as there's similar code in my project that works as expected.
I search for advises or way to solve my problem.
I try to simplify my code but if it's not clear or there's missing information, just tell me.
Thanks in advance for any help.

How to evaluate a template from a controller?

I've got this template:
<div class="container-fluid">
<div class="row">
<div class="col-xs-12" ng-repeat="product in ad.products">
<a href="{{product.link}}">
<h1>{{product.title}}</h1>
<img src="{{product.src}}">
<p>{{product.description}}</p>
<h5>{{product.price}}</h5>
</a>
</div>
</div>
</div>
From my controller I need to evaluate this template so that it checks how many products that have been selected and then it interpolates each product's values into the template. After that is done I also need to remove the ng-repeat so it doesn't fire an error in the external pages that will use this where angular is not present. However I'd figure that I'd just use a regex to look up the ng-repeat and everything in the expression and then remove it.
I've been looking at $interpolate and $compile but I can't figure out how to work with them from my controller so that it does what I want. This is because when I use these on my template and then console log the template value it's a function with a whole lot of nonsense in it.
So doing this:
ad.html = $compile(res.data, $scope);
Generates something like this:
function(b,c,d){rb(b,"scope");e&&e.needsNewScope&&(b=b.$parent.$new());d=d||{};var h=d.parentBoundTranscludeFn,k=d.transcludeControllers;d=d.futureParentElement;h&&h.$$boundTransclude&&(h=h.$$boundTr…
Can someone shed some light on how to achieve what I want?
Your are using $compile function in wrong way, you should call $compile(html) function by passing $scope parameter like below.
var compiledDOM = $compile(res.data)($scope);//then do append this DOM to wherever you want
ad.html = compiledDOM.html(); //but this HTML would not make angular binding working.

Detecting an image is fully loaded from a directive, where the directive is not applied to the image element

there are many examples in SO on how we can use an angular directive to know when an image is loaded. The examples describe a directive that is directly applied to the img element like so:
<img ng-src="myimage.jpg" my-great-directive />
And then in the directive "my-great-directive"
we can do an:
element.bind("load" , function(e){ }
And i works great.
However, what if the construct is like this:
<div my-great-directive>
<img ng-src="myimage.jpg" />
</div>
Within my-great-directive, how do I bind to the inside image loaded event?
This is not really a theoretical problem for me. I am using a 3rd party slider called angular-carousel-slider that wraps around like so:
<ul rn-carousel rn-carousel-buffered
rn-carousel-index="mycarousel.index"
rn-carousel-auto-slide="0.3" rn-carousel-pause-on-hover >
<li ng-repeat="slide in slides">
<img ng-src="{{eventBasePath}}{{slide.img}}?rand={{rand}}"/>
</li>
</ul>
I'm trying to modify its code so that it does not slide to the next image unless the current image is fully loaded (to avoid the situation of a fast slider half loading images and moving to the next). I'm stuck on how I can trap this image loaded event inside the directive. Doing element.bind("load") does not work as the directive is not applied to the image element.
Thank you!
Check this working demo: JSFiddle
Use anguler.element to find the img element and bind the event.
In your directive, it should be element.find('img').
angular.module('Joy', [])
.directive('hello', [function () {
return {
restrict: 'A',
link: function (scope, ele) {
var img = ele.find('img');
console.log(img);
img.bind('load', function () {
console.log('img is loaded');
});
}
};
}]);
HTML:
<div ng-app="Joy">
<div hello>
<img ng-src="https://www.google.com.hk/images/srpr/logo11w.png">
</div>
</div>
Update 1
If use ng-repeat, add a $timeout to wait for ng-repeat finishes first. Check working demo: JSFiddle.
Note: this demo is loading a very large image. After the image is loaded, the text img is loaded will be shown.
Update 2
If the event binding is not working, try native image.onload binding (or oncomplete to find images cached). Working demo: JSFiddle.

get ng-click, on injected element, to change the class of an element already in the view?

I have a <ul> that gets populated with the server. But in that controller there is also an iframe. When the <li>'s arrive there is some disconnect between them and the iframe even though they are in the same controller.
When you click one of the li's it should change the class on the iframe but it's not. However, If I move the iframe inside of the ng-repeat that injects the iframe it works.
View
<div class="content" ng-controller="FeedListCtrl">
<ul>
<li ng-repeat="item in items">
<div data-link="{{item.link}}" ng-click="articleShowHide='fade-in'">
<div ng-bind-html="item.title" style="font-weight:bold;"></div>
<div ng-bind-html="item.description"></div>
<!-- it works if i put the iframe here -->
</div>
</li>
</ul>
<!-- doesn't work when the iframe is here -->
<iframe id="article" ng-class="articleShowHide" src=""></iframe>
</div>
Here is the controller. It does an ajax call to get the data for each <li>
Controller
readerApp.controller('FeedListCtrl', ["$scope", "$http", "FeedListUpdate", function ($scope, $http, FeedListUpdate) {
$scope.setFeed = function (url) {
$http.get('feed?id=' + FeedListUpdate.GetCurrentFeedUrl()).success(function (data) {
$scope.items = data.currentFeed.items;
});
};
}]);
When inside of an ng-repeat you are in a different scope which means you are not setting the variable you think you are. Use $parent and that should work. The syntax is:
<div data-link="{{item.link}}" ng-click="$parent.articleShowHide='fade-in'">
Side note for others finding this - sometimes adding curly brackets helps as well. For more information on ng-class see here: http://docs.angularjs.org/api/ng/directive/ngClass
An Example
In case anyone wants to see this in action, I put together an example demonstrating a few ways to set the class as well as demonstrating the issue in scope (See: http://plnkr.co/edit/8gyZGzESWyi2aCL4mC9A?p=preview). It isn't very pretty but it should be pretty clear what is going on. By the way, the reason that methods work in this example is that the scope doesn't automatically redefine them the way it does variables so it is calling the method in the root scope rather than setting a variable in the repeater scope.
Best of luck!

Jasmine-jquery, testing generated GUI for (nested) directives

I recently started using jasmine-jquery (1.3.1) together with angular (1.0.6) and need an advice on testing GUI.
I have some view for controller, which has angular directives, like 'view.html':
<div id='main-div'>
<div my-directive objects-to-iterate='someScopeObjects'>
<span id='default-span'>some default text</span>
</div>
</div>
, and in JS a directive "myDirective" is defined, having template-by-url 'myDirective.html' which includes ng-repeat and makes some nested div (row) foreach in objectsToIterate.
I load fixtures for 'view.html' and 'myDirective.html'.
Now I would like to test that during user interaction there are really some elements (rows) in 'myDirective' repeated block.
Beginning was simple:
var div = $('div#main-div');
div = $compile(div)(scope);
scope.$digest();
expect(div).toBeVisible();
And now I'm stuck. Cannot get access to "generated" source of 'myDirective' element. If I use
div.find('whatever-selector-for-element-my-directive'),
I get
<div my-directive objects-to-iterate='someScopeObjects'>
<span id='default-span'>some default text</span>
</div>
If I try to compile+digest this html against scope, I still get same markup. How could I get "generated" source, looking like (pseudo)
<div id='my-directive-content'>
<div id='object-1'>blah</div>
<div id='object-2'>blah</div>
</div>
in order to check if there are N rows visible to user?
someScopeObjects in scope exist and are valid.
And my next step is actually testing same thing for directives nested inside of 'my-directive', so I somehow have to get access to the scope of 'my-directive'. How? :)
Thank you.

Resources