How to include multiple divs in a single directive? - javascript

I am trying to include multiple div's in a single directive.But the directive works on only first div and it leaves the other div's inside it.
Template code:
<div actor-check-box ng-repeat="actor in actors">
<div create-connections class="actor\{{$index}}" >
<span><input class="checkbox-actor" type="checkbox" name="actor-checkbox" id="actor-checkbox\{{$index}}">\{{actor}}</span>
</div>
<div ng-repeat="activity in activities">
<div ng-if="actor == activity.id">
<div ng-repeat = "impact in activity.text" >
<div update-connections class="impact\{{$index}}actor\{{actors.indexOf(actor)}}" actor-id="actor\{{actors.indexOf(actor)}}">
<span><input class="checkbox-activity" type="checkbox" name="impact-checkbox" id="activity-checkbox\{{$index}}actor\{{actors.indexOf(actor)}}" activity-check-box>\{{impact}}</span>
</div>
<div ng-repeat="feature in features">
<div ng-if="actor == feature.id && impact == feature.key">
<div feature-connection ng-repeat = "feature in feature.text" class="feature\{{$index}}" activity-id="impact\{{activity.text.indexOf(impact)}}actor\{{actors.indexOf(actor)}}" id="">
<span><input class="checkbox" type="checkbox" name="impact-checkbox" id="" >\{{feature}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Directive Code:
angular.module('mainModule').directive('actorCheckBox', function($interval) {
return {
restrict: 'EA',
/*transclude: true,*/
link: function (scope, element, attrs, ctrl) {
scope.$watch('ngModel', function(newValue){
/*alert(newValue);*/
console.log(element.find('input[type="checkbox"]'));
/*console.log(element.find('input[class="checkbox-actor"]'));*/
console.log(element.find('input[class="checkbox-activity"]'));
console.log(attrs);
});
}
}
});
Output In console:
[input#actor-checkbox0.checkbox-actor, prevObject: o.fn.init[1], context: div.ng-scope, selector: "input[type="checkbox"]"]
[input#actor-checkbox1.checkbox-actor, prevObject: o.fn.init[1], context: div.ng-scope, selector: "input[type="checkbox"]"]
[input#actor-checkbox2.checkbox-actor, prevObject: o.fn.init[1], context: div.ng-scope, selector: "input[type="checkbox"]"]
So the problem is I have 3 div's and directive is applied on the first div
and 2 more div is inside the main div with checkbox. When the directive is called console only shows the checkbox element in main div not of other 2 div's. Adding the console out from directive as well:
If I inlude transclude: true it removes all the earlier directives on the element and page goes blank.

It's not happening because ng-repeat creates separate scopes for itself. You need to include in on the divs as well or modify your directive to not use isolated scopes.

Related

Combine Multiple Ng-Repeats

I have an html structure where each children have different length values:
<div ng-repeat='element in treeView'>
<div ng-repeat='element1 in element.children'>
<div ng-repeat='element2 in element1.children'>
<div ng-repeat='element3 in element2.children'>
<div ng-repeat='element4 in element3.children'>
<div ng-repeat='element5 in element4.children'>
</div>
</div>
</div>
</div>
</div>
</div>
I dont like multiple ng-repeat.
How to re structure the code?
To create DOM nodes for all children of treeView recursively you can create a new component.
Example usage:
<your-directive elements="vm.elements"></your-directive>
Component code:
angular.module('yourApp')
.component('yourDirective', {
templateUrl: 'template.html',
bindings: {
elements: '='
},
bindToController: true,
controllerAs: 'vm'
});
Template code:
<div ng-repeat="element in vm.elements">
<your-directive ng-if="vm.elements.children.length > 0" elements="vm.elements"></your-directive>
</div>
Note: I haven't tested this code but with a little tinkering you should get this to work.

Angular ui-router prevent state trigger inside directive

I have a directive clickable-tag for which i am passing my data as the tag's name (tag.tag):
<a class="item item-avatar"
ui-sref="nebula.questionData({questionId: question.id})"
ng-repeat="question in questionsData.questions">
<img src="{{question.user.profile_photo || '../img/avatar.jpg'}}">
<h2 class="question-title">{{question.title}}</h2>
<p>{{question.description}}</p>
<div class="question-tags-list" ng-repeat="tag in question.tags" clickable-tag data="{{tag.tag}}">
<button type="submit" class="tag">{{tag.tag}}</button>
</div>
</a>
The directive clickable-tag is inside a ui-sref (on the outer a tag). Inside the directive, I want the outer ui-sref to be prevented and instead the user should be directed to another state (the one i am specifying in the directive below).
.directive("clickableTag", function($state) {
return {
restrict: "A",
scope: {
data: "#"
},
link: function(scope, elem, attrs) {
elem.bind('click', function(ev) {
console.log('scope.tagName: ', scope.tagName);
if (scope.data) {
$state.go('nebula.tagData', {tagName: scope.data});
}
});
}
};
})
The problem is that only the resolve of the state specified inside the directive runs. The view which is actually rendered is of the state specified by the outer ui-sref.
Any solutions as to how to prevent the outer ui-sref from being triggered. and instead trigger a state change as specified inside the directive ?
Any help would be appreciated. Thanks.
Note: I have already tried preventDefault(), stopPropagation(), return false inside my directive.
Move the ng-repeat outside and above the <a> tag and move the close of the <a> tag above the button.
<div ng-repeat="question in questionsData.questions">
<a class="item item-avatar"
ui-sref="nebula.questionData({questionId: question.id})">
<img src="{{question.user.profile_photo || '../img/avatar.jpg'}}">
<h2 class="question-title">{{question.title}}</h2>
<p>{{question.description}}</p>
</a> <!--Put close of A tag here --->
<div class="question-tags-list" ng-repeat="tag in question.tags"
ng-click="$state.go('nebula.tagData', {tagName: tag.tag})">
<button type="submit" class="tag">{{tag.tag}}</button>
</div>
</div>
For more information see the AngularJS ng-click API Docs

how to use jQuery plugin (semantic-ui) in angularJS directive?

I use semantic-ui in my project, the pulgin is checkbox
someone say if use jQ plugin, you must use it in angular directive
but it doesn't work
the checkbox of semantic-ui setting in semantic-ui API document, you must set this to init checkbox
$('.ui.checkbox').checkbox();
I try to change it to angular like this:
app.html
<div class="ui animate list">
<div class="item ui toggle checkbox" todo-checkbox ng-repeat="item in day track by $index">
<input type="checkbox">
<label ng-bind="item.content"></label>
</div>
</div>
and this is directive in angularjs file
todoApp.directive('todoCheckbox', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
$(elem).checkbox();
}
};
});
but it doesn't work in my project. Why?
You're close. elem is the element of the directive. In this case it is
<div class="item ui toggle checkbox" todo-checkbox ng-repeat="item in day track by $index">
<input type="checkbox">
<label ng-bind="item.content"></label>
</div>
Now, if we use find to help us locate the input field within the elem, then we can select the input field and run the checkbox method.
todoApp.directive('todoCheckbox', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
angular.forEach(elem.find( "input" ), function(inputField) {
inputField.checkbox();
}
}
};
});
A bit late to the party but you should be able to just move the todo-checkbox to the input tag (same with the semantic ui specific attributes)
Try
angular.element(elem).checkbox();
instead of
$(elem).checkbox();

why if I use ng-repeat, the jQ plugin doesn't work, if don't use, it work normal?

I use semantic-ui in angular
when I don't use ng-repeat in html, jQuery plugin work normal
like this
html
<div class="ui animate list">
<div class="item ui toggle checkbox" todo-checkbox>
<input type="checkbox">
<label>222</label>
</div>
</div>
directive.js
todoApp.directive('todoCheckbox', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.checkbox();
}
};
});
if my code like this, The checkbox plugin work normal
but if I use ng-repeat in html, elem.checkbox()inoperative like this
<div class="ui animate list">
<div class="item ui toggle checkbox" todo-checkbox ng-repeat="item in day track by $index">
<input type="checkbox">
<label ng-bind="item.content"></label>
</div>
</div>
the directive.js is same as abve
if use ng-repeat, app isn't work,
why?
how can I fixed this?

Directive link function does not have access to the entire template DOM

I have a directive which has a template that recursively include a template. In my directive link function, I am unable to get the complete DOM with a selector.
Here is my directive. Notice that my directive try to call dropdown() function on all .ui.dropdown divs constructed so nested dropdown will be activated.
.directive("floatingDropdown", function() {
return {
restrict: 'E',
templateUrl: "scripts/Ui/FloatingDropdown.html",
replace: true,
scope: {
uiClass: '#',
model: '=ngModel',
optionTree: '='
},
link: function(scope, elem, attrs) {
scope.elemClass = scope.uiClass || "ui floating dropdown icon button";
$(elem).dropdown();
$(elem).find(".ui.dropdown").dropdown();
}
}
})
The scripts/Ui/FloatingDropdown.html contains a nested include. This creates multiple levels of dropdowns
<div class="{{elemClass}}">
<script type="text/ng-template" id="node_template.html">
<div class="ui dropdown" ng-if="option.options">
<span ><i class="dropdown icon"></i> {{option.value}}</span>
<div class="menu" ng-if="data.options">
<div class="item" ng-repeat="option in data.options" ng-include="'node_template.html'"></div>
</div>
</div>
<span ng-if="!option.options" ng-click="model=option">{{option}}</span>
</script>
<i class="dropdown icon"></i>
<div class="menu">
<div class="item" ng-repeat="option in optionTree.options" ng-include="'node_template.html'">
</div>
</div>
</div>
My problem is $(elem).find(".ui.dropdown") will not find the recursively generated divs by ng-include
By attempting to do DOM manipulation in a directive's link() method like that, you're trying to query/modify a part of the DOM that hasn't been rendered yet.
You need to defer those jquery calls until later. You can do this using:
$scope.$evalAsync(function() {
// DOM code
});
or
$timeout(function() {
// DOM code
}, 0);
Using $evalAsync will run the expression during the next $digest cycle, will allow you to modify HTML before it's rendered in the browser. Using $timeout will wait until all $digest cycles are complete.

Categories

Resources