Run code after transcluded code is linked in Angular - javascript

I have directive with transclude and when link is executed I always have {{ }} when I try to do jQuery with $element. I have html like this:
<outter>
<inner ng-repeat="item in items" value="{{item.id}}">
{{item.name}}
</inner>
</outter>
and inside inner link function when I run
console.log($element.html());
I've got <li ng-repeat="item in items"><a>{{item.name}}</a></li> (my template is <li><a>).
inside outter $element in link function there is one ng-repeat
I need to initialize my directive when everything is in place. Is there there a way to do this in Angular? I've try post link (but I think is the same as just link) also transclude using a function. and everytime I got template that's not interpolated even that scope is updated, they are never in sync.
In my code (not in demo) I'm using ngModelController and $render is also rendered before everything is updated.
plunker

Related

can element using ng-repeat access variable created by ng-repeat?

is this valid for ng-repeat in angularjs 1.7.x
<div
ng-repeat="item in items"
ng-class="item.id">
{{tab.label}}
</div>
I am confused with the usage of variable created by ng-repeat ie item in the element which it is attached to. I thought we can use it inside that element only.
I have checked that this works but wanted to understand if there is any example in documentation for this case.
As an extension to this , does ng-controller works the same way for keys attached to $scope.
Kindly give some reference as i have checked for ng-repeat that it works, i just want to understand why( or that it is the expected behavior)

Ng-if on directives with two way bindings that override functions

I've set up a directive that will take in a function from the parent controller as one of it's attributes. This function will be replaced by the directives controller and will be accessible by the parent controller by using the passed function. The issue I'm running into is when placing an ng-if attribute on the directive the passed in function is not being replaced anymore. What causes this and how would I go about fixing this issue? I've attached an example
https://jsfiddle.net/dh7jt1zg/1/
<div class="parent" ng-controller="pCtrl">
<h3>Parent - with ng-if</h3>
<div>{{parentHelloWorld()}}</div>
<child ng-if="testBool" rep-fun="parentHelloWorld"></child>
</div>
<br/>
<div class="parent" ng-controller="pCtrl2">
<h3>Parent2 - without ng-if</h3>
<div>{{parentHelloWorld()}}</div>
<child rep-fun="parentHelloWorld"></child>
</div>
Use ng-show instead of ng-if.
ng-if causes element to remove from the DOM.
I think you'd be better off to create a service instead of replacing the function in the child controller. That seems kind of messy to me.
Personally, I'd use a service to register the function and then you can use that same service from the parent controller to call it.

ng-repeat always rendering as last in directive template

I have a directive (<my-directive>) and child directives (<my-child-directive>) as below structure:
<my-directive>
<my-child-directive caption="{{student}}" ng-repeat="student in students"></my-child-directive>
<my-child-directive caption="static content1"></my-child-directive>
</my-directive>
The first child directive repeated using ng-repeat and The last child directive is a static item.
Now I have two questions here:
Question1:
In the final output, the last directive is rendering as first <li>. is there any way to render the <li>s in the same order of child directives?
Question2:
I have used a hidden div in <my-directive>'s template to render the transclude for temporary purpose. Is there any way to avoid this unwanted div?
here is my java script code:
app=angular.module('myApp', [])
app.controller("MyController",function($scope){
$scope.students=["Alex","George","Phillip"];
});
app.directive('myDirective',function(){
return{
restrict:'E',
transclude:true,
template:"<ul><li ng-repeat='item in items'>{{item.caption}}</li></ul> <div ng-transclude ng-hide='true'></div>",
controller:function($scope){
$scope.items=[];
this.addItem=function(subScope){
$scope.items.push(subScope);
}
},
link:function(scope,element,attrs){
}
};
});
app.directive('myChildDirective',function () {
return {
restrict: 'E',
require:"^myDirective",
scope:{
caption:"#"
},
link:function(scope,element,attrs,parentCtrl){
parentCtrl.addItem(scope);
}
}
})
fiddle: http://jsfiddle.net/fyds082s/5/
Can anybody help on this?
The link function of the second directive is executed before the directives that come before him. When you check the ng-repeat state while the static directive is executed it shows that the index is 0. it hasn't finished compiling the ng-repeat yet.
My guess is that angular links sibling element from last to first, the same way it links from child elements first
Update:
My guess is wrong. so my new guess it has something to do with child scopes. For example, when adding ng-if to the second directive it is indeed executed second: http://jsfiddle.net/fyds082s/7/
<my-directive>
<my-child-directive caption="{{student}}" ng-repeat="student in students"></my-child-directive>
<my-child-directive caption="static content1" ng-if="true"></my-child-directive>
</my-directive>
What order do you think the following would produce?
<my-directive>
<my-child-directive caption="one" ng-if="true"></my-child-directive>
<my-child-directive caption="two"></my-child-directive>
</my-directive>
If you answered two, one then hat's off to you.
The reason behind this somewhat unintuitive result is a "conditional rendering" directive like ng-if and ng-repeat. They both transclude their hosting element, but render it later - when $scope.$watch or $scope.$watchCollection fire an event, respectively - at which time the link function of myChildDirective is called.
The best approach is not to rely on the order of called link functions to determine the order of rendering.

Where and how to modify transcluded content?

I want to buid a directive (let's call it "A") that accepts HTML for transcluded content and modify its transcluded content by adding ng-click handlers on it using a custom logic.
I thought that the pre-link would be a good place to do this, but apparently I was very wrong (it seems that the docs suggest against it).
Every "A" directive will accept its own (unique) content, so I cannot do this in the compile phase.
In the link function I am not sure what I can do...
So, has anyone done anything similar?
EDIT:
I forgot to mention this: The handlers for ngClick should be defined on the directive's scope, not the parent scope. I don't know if Angular allows this, but that's what I need.
In your template you should add ng-transclude on the element want to add your custom html to.
your use of the directive:
<attribute ng-click="clickMe()">
<div>
transcluded data
</div>
</attribute >
and in your template:
<span ng-transclude>
</span>
Hope it makes sense :)

Angularjs - ng-model undefined

I am building a rather complex directive in which I need access to ng-model on a specific element in the template which is enclosed into ng-if directive... I have a plunker and the explanation on how to see the issue is below.
In the .compile function of the directive I have a line of code that looks like this
ngModel = elm.find('textarea').controller('ngModel');
console.log(ngModel);
In my template, I have a something like this:
<div ng-if="views.view">
<textarea ng-model="exp.val"></textarea>
</div>
When I use ng-show my console.log gets an object of ng-model, no problem ...
The requirement is very strict however and I have to use ng-if. When I use ng-if my console log gets undefined
The actual working version of the problem exists in this plunker
If you change the line 6 in template.html into ng-if you can see the behavior.
How do I have to write this line to retrieve the model when inclosed in ng-if.
ngModel = elm.find('textarea').controller('ngModel');
I also tried using attach-if directive by Simon Sparks. This directive is pretty cool, it preserves the scope unlike ng-if so if you specifically need to not render HTML but you need to preserve scope it works great.
I still have the same problem with invoking ngModel as I am doing it but because of applying custom filters in the directive I have to update ng-model in this way.
I am this one step away from finishing this directive. Hoping someone can help.

Categories