Nested elements and directives - javascript

I got an workaround here and need some help. It is a tree of categories. Some categores can be chosen by a checkbox.
I thougt the cleanest way to do that is via direction. On a <li kw-category-node> element put a on('click', function()) handler, which then does the choosing work (add object to data etc.).
So I came up with this HTML
<script type="text/ng-template" id="category_renderer.html">
<div ng-if="true == true" ng-mouseenter="over = true" ng-mouseleave="over = false">
<input type="checkbox"
ng-model="assignedCategories[category.category_id]"
ng-if="category.childs.length == 0"
ng-click="toggleCategory(category)">
</input> {{ category.name }}
<a href ng-if="over" ng-click="categories.remove(category)">
<small> <i class="fa fa-times"></i> Entf </small>
</a>
</div>
<ul class="list-unstyled">
<li ng-repeat="category in category.childs"
ng-include="'category_renderer.html'"
kw-category-node>
</li>
</ul>
</script>
<ul class="list-unstyled" kw-category-tree>
<li ng-repeat="category in categories.tree"
ng-include="'category_renderer.html'"
kw-category-node>
</li>
</ul>
And a directive like that
admin.directive('kwCategoryNode', ['$interval', 'dateFilter', function($interval, dateFilter) {
function link(scope, element, attrs) {
element.find('input').on('click', function() {
alert("wow, what a click!");
});
}
But element.find("input") wont give me that input element. Maybe the DOM is not loaded completly or I'm just in tilt.
Thanks

Related

Ratchet Toggle - Setting Variable through Angular Directive and Accessing from Template

I am new to Angular and want to set the value of scope variable from directive and access it from the template file, but it's not working.
I am using Ratchet Toggle, and want to get all toggles that the user has turned off. I was able to write to the console but was not able to read from the template file.
Here's my directive:
mobileApp.directive('whenToggled', [function() {
function linkFunction(scope, element, attr) {
scope.$watch(function() {
setTimeout(function(){
var has_class = element.hasClass('active');
var id = element.attr('id');
if(has_class==false){
scope.unwanted_ingredients += id;
}
else
scope.unwanted_ingredients = "none";
},0)
}, function(value) {
//
});
}
return {
restrict: 'A',
scope: true,
link: linkFunction,
};
}]);
and here's my template code:
Ingredients: {{unwanted_ingredients}}
<ul class="table-view">
<li class="table-view-cell">
Item 1
<div id="item1" class="toggle" when-toggled ng-click="">
<div class="toggle-handle"></div>
</div>
</li>
<li class="table-view-cell">
Item 2
<div id="item2" class="toggle active" when-toggled ng-click="">
<div class="toggle-handle"></div>
</div>
</li>
<li class="table-view-cell">
Item 3
<div id="item3" class="toggle" when-toggled ng-click="">
<div class="toggle-handle active"></div>
</div>
</li>
<li class="table-view-cell">
Item 4
<div id="item4" class="toggle" when-toggled ng-click="">
<div class="toggle-handle"></div>
</div>
</li>
</ul>
unwanted_ingredients is being populated on initial load as I set it on the controller as:
$scope.unwanted_ingredients = "abc";
but the value is not being changed through the directive link. I appreciate your input on this as I don't understand well how scopes works with Angular.

AngularJS: How to toggle element from controller

How can I use the following controller to toggle the content inside li tag?
Right now the content is rendered only after that span is clicked, but it won't hide if I click again the span.
Here's my code:
<span ng-click="get_menu_items(folder)>
<i class="fa fa-folder-o"></i>
{{ folder.name }}
</span>
<ul>
<li class="item" ng-repeat="file in folder.files">
<label>
<input type="checkbox" name="file_map[]" value="{{ file.id }}" ng-model="file_map[file.id]" ng-click="update_selection(file.id)"/>
<i class="fa fa-file-o"></i>
<span>{{ file.name }}</span>
</label>
</li>
<li menuitem ng-repeat="folder in folder.folders" ng-model="folder"></li>
</ul>
Controller:
scope.get_menu_items = function(folder){
http.get("/api/folders/" + folder.id).success(function(data){
folder.folders = data.data.folders;
folder.files= data.data.files;
})
}
You can simply create a boolean for show/hide and toggle it on your click method like.
scope.get_menu_items = function(folder){
//if folder.folder exist means we don't need to make $http req again
if(folder.folders){
$scope.showFolder = !$scope.showFolder
}
else{
http.get("/api/folders/" + folder.id).success(function(data){
folder.folders = data.data.folders;
folder.files= data.data.files;
$scope.showFolder = true;
})
}
}
and add ng-if on your view like.
<span ng-click="get_menu_items(folder)>
<i class="fa fa-folder-o"></i>
{{ folder.name }}
</span>
<ul ng-if="showFolder">
<li class="item" ng-repeat="file in folder.files">
<label>
<input type="checkbox" name="file_map[]" value="{{ file.id }}" ng-model="file_map[file.id]" ng-click="update_selection(file.id)"/>
<i class="fa fa-file-o"></i>
<span>{{ file.name }}</span>
</label>
</li>
<li menuitem ng-repeat="folder in folder.folders" ng-model="folder"></li>
</ul>
Hope it helps.
Add a global variable in controller as scope.
Outside controller, add a variable (for example called: toggleVariable) and assign it to false.
Inside controller put this:
scope.toggleVariable = !scope.toggleVariable;
In HTML, add to ul tag: ng-show="toggleVariable".
Give it a try

Need an element's parent index using jquery or javascript

I have three <ul>s that expand when their buttons are clicked. Not all three <ul>s will show up - only when there is a notification to show. I hard-coded the values for now, but I can instantiate them on an as-needed basis.
Right now, they cover each other when they expand. I would like the others to move when a list is expanded so they don't cover each other. I was thinking of getting the index of the one whose button is clicked and then resetting the bottom style of the others. I need to get the index of the <ul> parent of the button that was clicked, probably using jQuery but straight JavaScript is fine as well. Can anyone help?
Here is my code:
<div id="NotificationDiv">
<ul id="noticeLead" class="notification_base notification_Lead"><button id="notification_button">Lead Notice</button>
<div>
<li id="urlLead" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Lead #1</a>
</li>
<li id="urlLead" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Lead #2</a>
</li>
</div>
</ul>
<ul id="noticeTask" class="notification_base notification_Task"><button id="notification_button">Task Notice</button>
<div>
<li id="urlTask" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Task #5</a>
</li>
<li id="urlTask" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Task #6</a>
</li>
<div>
</ul>
<ul id="noticePolicy" class="notification_base notification_Policy"><button id="notification_button">Policy Notice</button>
<div>
<li id="urlPolicy" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Policy #3</a>
</li>
<li id="urlPolicy" class="notification_urlNotice notification_notice">
<a target="_blank" >Check Policy #4</a>
</li>
</div>
</ul>
</div>
And in the $(document).ready, I have:
$('.notification_base').on('click', 'button', function(){
$(this).closest('.notification_base').find('.notification_urlNotice').slideToggle();
});
Try this:
var myParentId; //Here you'll store the id of the clicked element
$('.notification_base').on('click', 'button', function(){
$(this).closest('.notification_base').find('.notification_urlNotice').slideToggle();
myParentId = $(this).attr("id");
});
Thank you everyone for your input. I changed my structure to a table assigning .parent class to the header row and .child class to the data row and put this code in the jQuery ready function and it works great.
function getChildren($row) {
var children = [];
while($row.next().hasClass('child')) {
children.push($row.next());
$row = $row.next();
}
return children;
}
$('.parent').on('click', function() {
var children = getChildren($(this));
$.each(children, function() {
$(this).toggle();
})
});

Access the component ID in AngularJS

How can I get the id of a component in AngularJS ?
HTML
<li class="list-group-item" id="person_2" ng-click="invitePerson(this)">
<span class="label label-primary">A</span> Alexandre Dolabella Resende
</li>
JS
$scope.invitePerson = function(id) {
alert(id);
};
The alert returns [Object object], how can I access my component ID ? (in my case, should be person_2)
Console.log
Use $event to get the eventhandler param. From that param we can get the target element and its attributes
<li class="list-group-item" id="person_2" ng-click="invitePerson($event)">
<span class="label label-primary">A</span> Alexandre Dolabella Resende
$scope.invitePerson = function(e){
alert(e.target.id);
}
You can use ng-init or your controller to initialize the value. Then define a model, and you can then pass that model into a controller function, such as invitePerson
Working Plunker
HTML:
<ul>
<li class="list-group-item" id="person_2"
ng-init="person_2=5"
ng-model="person_2"
ng-click="invitePerson(person_2)">
<span class="label label-primary">A</span> Alexandre Dolabella Resende
</li>
</ul>
JS:
app.controller('MainCtrl', function($scope) {
$scope.invitePerson = function(id){
alert(id);
}
When I see "person_2" I immediately think of ng-repeat and maybe you should too if you want to iterate over object in your partial, http://plnkr.co/edit/b6ZePD826FauaY9x8b9p?p=preview
<label for="list">List</label>
<ul id="list">
<li class="list-group-item" id="person{{$index}}" ng-click="invitePerson(person)" ng-repeat="person in persons">
<span class="label label-primary">{{person.label}}</span> {{person.name}}
</li>
</ul>
<label for="invited">Invited</label>
<ul id="invited">
<li ng-repeat="invite in invited track by $index">{{invite.name}}</li>
</ul>

Dynamicly added dropdown menu in AngularJS + Bootstrap

I'm writing a module that will create a dynamic menu on the fly. How to run a directive after adding new <li> with css class dropdown which is also added by ng-class.
The code:
angular.module('myapp', ['ui.bootstrap'])
.factory("menuService", ["$rootScope", function($rootScope) {
"use strict";
return {
menu: function() {
$rootScope.globalMenu;
},
setMenu: function(menu) {
$rootScope.globalMenu = menu;
}
};
}])
.controller("MainController", ["$scope", "menuService",
function($scope, menuService){
menuService.setMenu([{href:"#", label:"Dropdown",
dropdown:[{href:"/edit", label:"Edit"}]},
{href:'/', label:'test'}]);
$scope.bodyText = "Some text";
}]);
This is the code in html
<ul class="navbar-nav nav navbar-left">
<li ng-repeat="menu_element in globalMenu" ng-class="{dropdown: menu_element.dropdown != undefined}">
<a ng-href="{{menu_element.href}}" ng-class="{'dropdown-toggle': menu_element.dropdown != undefined}">
{{menu_element.label}}
<b class="caret" ng-if="menu_element.dropdown != undefined"></b>
</a>
<ul ng-if="menu_element.dropdown != undefined" class="dropdown-menu">
<li ng-repeat="sub_element in $parent.menu_element.dropdown">
<a ng-href="{{sub_element.href}}">{{sub_element.label}}</a>
</li>
</ul>
</li>
</ul>
Link to plunker:
http://plnkr.co/edit/pgH35mmsjLJqV4yJuSYq?p=preview
So what I want to do is the same or similar as for jQuery, there I would run $("li.dropdown").dropdown() after adding whole ul>li blocks. I'm new to Angular and I want to make this in the angular way.
I read about directives, how to use them. But I couldn't find how to apply directive in runtime. I've read about transclude: element in a directive (ui.bootstrap.dropdownToggle) doesn't have it enabled. I'm sure that there is a easy way, but couldn't find it myself...
Solved!
I've finally made it with ng-if and ng-repeat-start. With help in comments, I've found that ng-class does not run directives.
<ul class="navbar-nav nav navbar-left">
<span ng-repeat-start="menu_element in globalMenu"></span>
<li ng-if="menu_element.dropdown !== undefined">
<a ng-href="{{menu_element.href}}" class="dropdown-toggle">
{{menu_element.label}}
<b class="caret" ></b>
</a>
<ul class="dropdown-menu">
<li ng-repeat="sub_element in $parent.menu_element.dropdown">
<a ng-href="{{sub_element.href}}">{{sub_element.label}}</a>
</li>
</ul>
</li>
<li ng-if="menu_element.dropdown === undefined">
<a ng-href="{{menu_element.href}}">
{{menu_element.label}}
</a>
</li>
<span ng-repeat-end></span>
</ul>
Working example on Plnkr. Something happened with the css on Plunker, yesterday it was working... but still it works.
Nice, this helped me along the way. I've a slight variation on your theme.
<ul class="nav navbar-nav">
<li ng-repeat='link in menu track by $index' ng-class='[{dropdown:link.sub}]'>
/* normal menu */
<a ng-if='!link.sub' ng-bind='link.id' ng-click='jump(link.to)'></a>
/* dropdown menu */
<a ng-if='link.sub' class="dropdown-toggle" data-toggle="dropdown">
<span ng-bind='link.id'></span>
<ul class="dropdown-menu inverse-dropdown">
/* and repeat for the submenu */
<li ng-repeat='slink in link.menu track by $index'>
<a ng-bind='slink.id' ng-click='jump(slink.to)'></a>
</li>
</ul>
</a>
</li>
</ul>
My menu array is a list of
{id:'name', to:n}
where n points to an array listing some html I push into the page. When there is a sub menu the menu array element is
{id:'name', sub:true, menu:[{id:'name', to:n}, etc.]}
I tried ui-bootstrap but never got my head around it.

Categories