angularjs function in parent directive not getting called from transcluded html - javascript

I have created a dropdown list like feature using angualrjs directive, The directive is working somewhat but not in correct way I expected.
Following are the issues which I am facing.
The drop-down list alignment is correct for static but not for dynamic
I am not able to select any of the option list since getValue function which I have defined in the parent directive is not been invoked from the trancluded directive
Can anyone please tell me some solution for this
My code is as given below
PLUNKER
<div ng-controller="MainCtrl">
Static
<grant-parent ng-model="grand1">
<parent label="Parent1" value="12">
<child value="56" label="Child1">Child1</child>
<child value="57" label="Child2">Child2</child>
</parent>
<parent label="Parent1" value="13">
<child value="58" label="Child3">Child3</child>
<child value="59" label="Child4">Child4</child>
</parent>
</grant-parent>
Dynamic
<grant-parent ng-model="grand2">
<parent ng-repeat="parent in data" label="{{parent.parentName}}" value="{{parent.parentId}}">
<child ng-repeat="child in parent.childrens" label="{{child.name}}" value="{{child.id}}">{{child.name}}</child>
</parent>
</grant-parent>
</div>

Transclusion and ng-repeat have caused me headaches, and I thought it would be challenging, but the solution proves quite simple:
Remove the DOM manipulation from your link function and do the transclusion in the template!
I.e. <div ng-transclude></div> in the template of the parent and remove this line: elm.find('div').replaceWith(transclude()).
Forked plunk: http://plnkr.co/edit/UGp6D29yxnu0uJwD1BM2?p=preview
Now the markup comes out a bit different, the wrapper <div> still exists. Although there seems to be no visual difference, this may not be what you want. I do not think there is a sane way to get around this, so I would suggest altering the layout a bit: Why don't you place the children inside the parent <li>, e.g. as:
<li>
<b><a href='#' ng-click='getValue(optGroupLabel,optGroupValue)'>{{optGroupLabel}}<span class='value'>{{optGroupValue}}</span></a></b>
<div ng-transclude></div><!-- the div is now inside the li -->
</li>
This works in the plunker, but the markup is still invalid (<li> within <div>).
The best solution is to wrap the children in their own <ul>, i.e.:
<li>
<b><a href='#' ng-click='getValue(optGroupLabel,optGroupValue)'>{{optGroupLabel}}<span class='value'>{{optGroupValue}}</span></a></b>
<ul ng-transclude></ul><!-- The div is replaced with ul -->
</li>
This does not work in the plunk as it is, but should work with a little CSS tweaking.
Concerning getValue You have gotten wrong how isolated scopes and transclusion work. The grandParent directive defines the getValue method in its isolated scope. The transcluded things (the parent and child directives) get the outer scope, i.e. the scope of the MainCtrl. A solution is to move getValue() to the MainCtrl.
A better solution would be to pass a callback to the descendants of the grandparent, e.g. as scope: { assignValue: '&' }. But this solution cannot be implemented for the code in its current form because the grandparent does not directly include its children, so it cannot pass arguments to them.
The final solution - copied from the comments: move getValue to the controller of grandParent, have the parent and children require the grandparent and call that function. See http://plnkr.co/edit/pS9SspLaoPlqoWMYr8I0?p=preview

Related

#Angular2 How i can count numbers of custom attribute directive?

I made a custom attr directive and i will use it in siblings elements like:
<div>
<div [customAttrDirective]="'value'">1</div>
<div [customAttrDirective]="'value'">2</div>
<div [customAttrDirective]="'value'">3</div>
<div [customAttrDirective]="'value'">4</div>
</div>
I olso made a service that control all of my directives. Inside this it I want to know the count of my directives customAttrDirective.
PS: I can't do it by searching by class name(because i add classes inside the directive) and i can't do it by searching by attribute (directive name) because angular change.
Edit: replaced wrong sintax customAttrDirective="'value'" to [customAttrDirective]="'value'"
Many thanks.
Assuming your custom attribute directive's class name is CustomAttrDirective, in the component that you are using your custom directives, add this:
#ViewChildren(CustomAttrDirective) dirs: QueryList<CustomAttrDirective>
Then in life circle ngAfterViewInit, get the length of variable dirs.

Angular - check if class is odd or even on ng-click

I have the following ng-repeat that gives an element a className based on whether it is even or odd...
<div ng-click="displayHTML(content)" ng-class-odd="'title'" ng-class-even="'html'" ng-repeat="content in name.name">
{{content}}
</div>
On ng-click I am calling displayHTML() and passing a parameter content so that only that particular div that is clicked calls the function.
However on ng-click I'm attempting to see whether the clicked element is ng-class-odd or ng-class-even and I want the function to only be called if the element is ng-class-odd.
But I do not know an easy way to do this. Is there an easy "angular" way of doing it. If not, what should I put here...
$scope.displayHTML = function(obj){
////
}
ngRepeat exposes several local variables to the scope, specifically $even and $odd. Just use those:
<div ng-click="displayHTML(content, $even)" ng-class-odd="'title'" ng-class-even="'html'" ng-repeat="content in name.name">
{{content}}
</div>
js:
$scope.displayHTML = function(obj, $even) {
if($even) {/* even code*/}
else {/* odd code */}
}

Data binding (AngularJS) inside JS

I'm trying to use data binding inside a <script>.
<ol class="breadcrumb"></ol>
<div class=heading><h2>{{current.name}}</h2>
...
<script>
$(function(){
$(".breadcrumb").append('<li> Ledige stillinger</li>');
$(".breadcrumb").append('<li><a href=#!/categories/{{current.keyname}}>{{current.name}}</a></li>');
});
</script>
</div>
My result is:
Ledige stillinger (this is ok!) / {{current.name}} (here should it be the name, it works inside h2)
What am I doing wrong?
my answer would be to use AngularJS as it is intended and 1-way bind your DOM to the model values.
if there are multiple elements with the "breadcrumb" class then add these to a collection in your controller's scope and use ng-repeat directive to render them all out then append the "li" tags to this template.
Please see this plunkr example: http://plnkr.co/edit/0T6ldRzSTCnVIKnn3WRh
look at app.js and the following markup:
<ul class="breadcrumb">
<li>{{current.name}}</li>
</ul>

accessing parent controller from ng-repeat

I have been learning angular and found this when trying to access the parent controller
http://jsfiddle.net/eqb23s8t/
I was expecting to access the same variable from the parent controller from inside the ng-repeat using the $parent so when one of the checkbox is pressed, all should be updated, but this is not true. Why ?.
<div ng-app ng-controller="ParentCtrl">
<ul>
<li ng-repeat="city in cities">{{city}}<input type="checkbox" ng-checked="$parent.somevar" /></li>
</ul>
</div>
First, your jsFiddle has a ChildCtrl defined but it will have no effect because you never use it. You can delete it.
Second, as described in the ngChecked documentation, there is a difference between ngChecked and ngModel:
https://docs.angularjs.org/api/ng/directive/ngChecked
If what you're expecting to happen is have all the checkboxes check/uncheck together, you probably want ngModel rather than ngChecked.
It's not clear from your question what you're actually trying to do, but here's a fork of your jsFiddle illustrating data sharing through a $parent variable:
http://jsfiddle.net/7jzyk7f6/
It just does the following:
<li ng-repeat="city in cities">{{city}}<input type="checkbox" ng-model="$parent.somevar" /></li>
to illustrate both concepts.
You are not bind a model for the view, which can reflect the changes. The current code just reads the model (in this case the somevar) state. Use ng-model instead of ng-checked. The angular will handle the rest:
HTML
<div ng-app ng-controller="ParentCtrl">
<ul>
<li ng-repeat="city in cities">{{city}}<input type="checkbox" ng-model="$parent.somevar" /></li>
</ul>
</div>
JS
function ParentCtrl($scope) {
$scope.cities = ["NY", "Amsterdam", "Barcelona"];
$scope.somevar = true;
}
http://jsfiddle.net/eqb23s8t/4/
In this case, you need to use ngModel (two-way binding) instead of ngChecked (one-way binding):
ng-model="$parent.somevar"
See JSFiddle
I'm also totally newbie in Angular so I can be wrong. But I see few... things in your code. First of all ChildCtrl is not used at all. Second, it looks like only ng-model directive applied two-way binding to checkboxes. Yet ng-checked used just to add|remove checked attribute.
And js-fiddle
Sir please use ng-model to refer scope of the parent.
here is what i have created demo for you [demo][1]
[1]: http://jsfiddle.net/nwg7bwLx/

Conditional angularjs directive nesting

Let's say I have a directive on the page like so:
<outer inner-type="custom" ng-model="model" options="options text"></outer>
Does anyone know of an effective way to have it output, without re-compiling and with the ng-model reference preserved, something to the effect of:
<outer>
<!-- OTHER WRAPPER STUFF -->
<input ng-model="model" />
<!-- CONTROL TYPE SELECTED WITH NG-SWITCH OR NG-IF -->
<custom wrap-type="custom" ng-model="model" options="options text"></custom>
</outer>
I don't want to just transclude a bunch of stuff into the directive.
EDIT:
Transclusion messiness:
<outer ng-model="model.properties.property">
<custom wrap-type="custom" ng-model="model.properties.property" options="options text"></custom>
</outer>
The ng-model reference in outer is necessary for the input, and is repeated again in the inner part. In any case, I'm pretty sure this would have problems when isolate scopes become involved.
EDIT:
Here's a plunker with code that creates a direct edit option as an example: http://plnkr.co/edit/rXaMrL?p=preview.

Categories

Resources