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.
Related
Let's say I have multiple directives with the same name "parent-elem" (on each page I can have a different number of these directives - dynamic number)
<div ng-app="app">
<div parent-elem></div>
<div parent-elem></div>
<div parent-elem></div>
</div>
Is there a way to know (inside the link function) AngularJS finished render all the directives with the same name on the page?
Inside the directive link function - how do I know this directive is the last rendered?
Note: Not using a ng-repeat
You should have had written, same directive, multiple times :P
Now, that totally depends on your directive, how you make it.
It can keep the counter in a service or rootScope may be whenever it is initialized.
If you are using ng-repeat which you should in this case, you have a bool $last that can tell you if the element rendered is last or not, which you can pass to the directive via any attribute.
So, I got the following generic structure:
<list-item ng-repeat="item in collection">
<remove-item>
<a ng-click="remove()">delete</a><!-- this is inside the view.html -->
</remove-item>
</list-item>
I need a proper way to, when triggered, the remove() function remove the full parent of the clicked .
I got this working calling scope.parent().parent()....remove() on the directive, but it is a shitty way to do that =P
Is there a better way? (sure there is).
Please, don't mind this lame question. I am new at AngularJs, and I am having a hard time trying to solve that. =(
Thank you in advance.
There are a few ways to avoid the $scope.$parent.$parent ... problem in Angular. If you are using scopes, you should put any callback or property that you want children to access in a sub-property of the scope. For example, in the parent directive, use $scope.api.remove = function() {...} rather than $scope.remove = function() {...}. Then you can call it in child directive like so:
<list-item ng-repeat="item in collection">
<remove-item>
<!-- remove() is bound to $scope.api rather than directly to $scope -->
<a ng-click="api.remove()">delete</a>
</remove-item>
</list-item>
The other way to do this would be to refactor your code to use controllers rather than scopes. This seems to have become the preferred way of doing things, and it is how Angular 2 works. This pattern is made especially easy by the new component feature in v1.5.0. I won't give a detailed example, but you can read more about this pattern here, and more about components here.
I have nested angular.js templates. Each template has it's own directive. Based of the data passed to the ParentTemplate, angular.js should call the matching directive.
<div class="parent-template">
<div class="{{childTemplate}}"></div>
<div class="template1"></div>
</div>
Lets say that $scope.childTemplate = template1. Both divs evaluate to the same content <div class="template1"></div> but only the second div calls the directive to show the template as expected.
I need a dynamic way to call the corresponding template directive
Here is the directive for template1
angular.module('myApp').directive('template1', function(){
return {
restrict: 'C',
templateUrl: 'templates/template1.html'
}
});
Directives for other templates directives work similar.
You try to set the class of the DOM element.
You can do this with ngClass.
Otherwise if you would like to set your directive as an attribute of the DOM element. Like this: <div template1> </div>
You can try this way:
var myEl = angular.element( document.querySelector( '#divID' ) );
myEl.attr('myattr',"attr val");
Try:
<div ng-class="childTemplate"><div>
Did you ever solve this? I have a similar challenge, which I currently solve by using ng-include, like so:
<div class="parent-template">
<div ng-include="'templates/template1'"></div>
<div class="template1"></div>
</div>
This works for your example, but gets more tricky when a directive does more than just wrapping a template, e.g. working with the DOM or adding a controller.
What you can do in that case is using the directive inside the template.
However, this feels all kinda hacky, i'd like a more direct approach
This was, for me, all sparked by an article on react plugins, in which you basically enumerate over a set of react component to get a feature set: https://nylas.com/blog/react-plugins
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 :)
I have a directive that contains a list of other directives. In each of these sub-directives, they could have any number of .item HTML elements. Inside of the parent directive, I would like to reference all of these .item elements using jQuery. So I have tried the following:
HTML Structure
<parent>
<div class='item'></div>
<ul>
<li ng-repeat='child in children'>
<!-- loads template that may have one or more divs with .item on them -->
<child='child' />
</li>
</ul>
</parent>
and Inside of the parent link() function I call $(".item").size(). In this case, it always returns 1. Is there a way to call a function once all of the child directives have been loaded so I can access all of the internal .item elements?
I guess, it's because you query DOM too soon, before inner directives run.
Try:
setTimeout(function(){
$(".item").size();
}, 0);
or $timeout if you need to do something related with scope in timeout callback function.
You could also try:
scope.$evalAsync(function(){
$(".item").size();
});
but it's hard to tell which one will work without code sample.
You can read more about setTimeout and $evalAsync differences here: AngularJS : $evalAsync vs $timeout .