applying class using ng-class for nested items in Angularjs - angularjs

I am displaying the menu items in the below format. The data contains list of items and for each item there is a subitem. I need to apply the selected class for the subitem selected and all other subitems for all the items should be deselected. How to do this inside the controller. I tried by adding the ng-click event inside the html and toggling the class inside the controller but it is not applying for all the other subitems inside other items. Both html and controller code is shown below for more details.
<ol ng-model="data">
<li ng-repeat="item in data" collapsed="true">
<div ng-click="toggle(this)">
<a class="btn btn-success btn-xs" ng-if="item.children && item.children.length > 0">{{item.name}}</a>
</div>
<ol ng-model="item.children" ng-class="{hidden: collapsed}">
<li ng-repeat="subItem in item.children" ng-model="subItem.name" collapsed="true" ng-click="handleClick(subItem)">
<div ng-class="{'selected-li': subItem.value, 'deselected-li': false}">
{{subItem.name}}
</div>
</li>
</ol>
</li>
</ol>
Inside my controller I am having the code as below:
$scope.toggle = function (scope) {
scope.toggle();
};
$scope.handleClick=function(subitem){
subitem.value = subitem.value ? !subitem.value: true;
}
The data object used inside the UI contains the children also. Please let me know where I am going wrong.

HTML
<li ng-repeat="subItem in item.children" ng-model="subItem.name" collapsed="true" ng-click="handleClick($index, item.children)">
<div ng-class="{'selected-li': subItem.value, 'deselected-li': false}">
{{subItem.name}}
</div>
</li>
JS
$scope.handleClick = function(index, subItems) {
for(var i = 0; i < subItems.length; i++) {
if(i == index) {
subItems[i].value = true;
} else {
subItems[i].value = false;
}
}
}
What I'm doing here is, the index of the sub item and the entire item.children array are sent to the ng-click handler method and then in a for loop I am updating the value of all the sub items in that list.

Related

Refreshing ng-repeat list after adding an element

I have a list of orders that I sort based on status key. Then I display it using ng-repeat in bars. I can click Accept button to move one order from submitted to accepted. The question is: How do I refresh the bar displaying accepted orders?
HTML
<div class="bar" ng-controller="AdminCtrl">
<li ng-repeat="order in submitted">
<div >
<p >{{order.name}} </p>
<p>{{order.total}}</p>
<button class="btn" ng-click="acceptOrder(order)">Akceptuj</button>
</div>
</li>
</div>
<div class="bar" ng-controller="AdminCtrl" >
<li ng-repeat="order in delivery">
<div >
<p >{{order.name}} </p>
<p>{{order.total}}</p>
<button class="btn" ng-click="addOrderToDeliveryQueue(order)">Dodaj do kolejki dostawy</button>
</div>
</li>
</div>
</div>
JS
$scope.submitted = [];
$scope.accepted = [];
$scope.delivery = [];
angular.forEach($scope.orders, function(value, key) {
if (value.status == 'submitted')
$scope.submitted.push(value);
if (value.status == 'accepted')
$scope.accepted.push(value);
if (value.status == 'delivery')
$scope.delivery.push(value);
});
$scope.acceptOrder = function(order) {
var index = $scope.submitted.indexOf(order);
order.status = 'accepted';
$scope.accepted.push(order);
$scope.submitted.splice(index, 1);
AngularJS handles refreshing ng-repeat directives automatically when it sees a change in the collection. You are not seeing this behavior because you are actually creating multiple independent instances of your AdminCtrl controller. Each of your divs has this: ng-controller="AdminCtrl". This creates a new instance of the AdminCtrl scoped to that div. What you really want is one instance of that AdminCtrl. You can achieve this by moving the ng-controller directive to the outermost container element.
<div ng-controller="AdminCtrl">
<div class="bar">
<li ng-repeat="order in submitted">
// your markup
</li>
</div>
<div class="bar">
<li ng-repeat="order in accepted">
// your markup
</li>
</div>
</div>
// etc.

how to bind $index from ng-repeat to controller

In Angular I wanted to bind $index to controller. How can I send $index value in to my controller. Here is my html code.
<body>
<div class="container">
<div class="row row-content" ng-controller="demoController as demoCtrl">
<ul>
<li ng-repeat="val in demoCtrl.list" >Hello {{$index}}</li>
</ul>
</div>
</div>
Here is my controller code
var app = angular.module('confusionApp',[])
app.controller('demoController', function(){
var list = [1,2,3,4,5];
this.list = list;
var array = ['abc','def','ghi','jkl','mno']
this.array = array
console.log(this.array[index]);
});
I need to use ng-modal in HTML and bind that value to some variable in my controller.
Based on the selection of index, it should check in array and respective array should have to print.
Can any of you please help
To get your current iteration position in your controller you have define a function.
So your html code like this.
<body>
<div class="container">
<div class="row row-content" ng-controller="demoController as demoCtrl">
<ul>
<li ng-repeat="val in demoCtrl.list" ng-click="dispArray($index)">Hello {{$index}}</li>
</ul>
</div>
</div>
And your controller code
var app = angular.module('confusionApp',[])
app.controller('demoController', function($scope){
$scope.dispArray = function(index){
// console.log(index);
// your code
}
});
Depending on what you're trying to accomplish you might be better served creating a custom iterator.
function makeIterator(array){
var nextIndex = 0;
return {
next: function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
Angular is going to iterate over everything in the list when you use ngRepeat. If you're trying to track which list item a user clicks then you'll just add that in there using $index.
<li ng-repeat="val in demoCtrl.list" >
<span ng-click="demoCtrl.userClicked($index)"> Hello {{$index}}</span>
</li>
If you're just trying to print the data in each item, ng-repeat is already iterating everything for you.
<li ng-repeat="val in demoCtrl.list" >
<span ng-click="demoCtrl.userClicked($index)"> Hello {{val}}</span>
</li>
It all depends on what you're trying to do.
i dont konw what u want to do. if u want to use event. you can pass $index to your controller function like:
<li ng-repeat="val in demoCtrl.list" ng-click="getIndex($index)">Hello {{$index}}
$scope.getIndex = function($index) {
console.log($index)
}
hope to help u.

How to create multiple elements drag and drop in angularjs

Anyone knows or can point me to an example in which multiple draggable elements are being dragged into a container ?
I need to achieve this behavior using Angular JS.
So far I've tried this : http://codef0rmer.github.io/angular-dragdrop/#/ but it only seems to work for 1 element at a time.
Thansk
That plugin you mentioned doesn't support multi drag&drop out of box.
Here is a working method to support multi drag&drop using the same plugin:
http://embed.plnkr.co/lyCnU3gNeGRrTk1D9hh0/
After you open the link, click on any area to get it to focus and detect your keyboard presses, then hit ctrl and click on the items you want to drag them to make them selected. Finally, drag them.
How it works:
<div class="container form-inline" style="text-align: center;">
<div class="btn btn-droppable" ng-repeat="item in list5" data-drop="true" ng-model='list5' data-jqyoui-options="{accept:'.btn-draggable:not([ng-model=list5])'}" jqyoui-droppable="{index: {{$index}}}">
<div class="btn btn-info btn-draggable"
ng-class="{'selected':(multiSelectedDataColumnsIndecies.indexOf($index) > -1)}"
data-html="true"
data-drag="true"
data-jqyoui-options="draggableOptionsList"
ng-model="list5"
jqyoui-draggable="{index: {{$index}},animate:false,placeholder: 'keep'}"
ng-click="dataItemClick($index,$event,item)">
{{item.title}}
</div>
</div>
</div>
.
$scope.draggableOptionsList = {
appendTo: 'body',
snap: true,
cursor: 'move',
revert: 'invalid',
helper: function() {
console.log('Im in helper');
var selected = $('.selected');
if (selected.length === 0) {
selected = $(this);
}
var container = $('<div/>').attr('id', 'draggingContainer');
container.append(selected.clone());
return container;
}
};
Using jquery UI's helper method, I select all selected items and return them to show dragging effect. And then on click, if ctrl is pressed I save the selected items in a gloabl list array.
<div class="row-fluid">
<ul class="thumbnails">
<li class="span3" style='margin:10px;width: 100%; '>
<div class="thumbnail"
data-drop="true"
ng-model='list1'
data-jqyoui-options
jqyoui-droppable="{onDrop:'dropCallback(list1,$index)',beforeDrop: 'beforeDrop(list1)', multiple:true}">
<div class="caption">
<div class="btn btn-info btn-draggable" ng-repeat="item in list1" ng-show="item.title" data-drag="{{item.drag}}" data-jqyoui-options="{revert: 'invalid'}" ng-model="list1" jqyoui-draggable="{index: {{$index}},animate:true}">{{item.title}}</div>
</div>
</div>
</li>
</ul>
</div>
.
$scope.beforeDrop = function(event, ui, dataModel) {
//In case of multi drop
for (var i = 0; i < $scope.multiSelectedDataColumnsForDrop.length; i++) {
var isExisting = false;
for (var j = 0; j < dataModel.length; j++) {
if (dataModel[j].title == $scope.multiSelectedDataColumnsForDrop[i].title) {
isExisting = true;
break;
}
}
if (!isExisting) {
dataModel.push(angular.copy($scope.multiSelectedDataColumnsForDrop[i]));
}
}
var deferred = $q.defer();
deferred.resolve();
return deferred.promise;
};
In beforeDrop method I select set the model value using the global list of selected items.
If you are talking about nested dropzones check out one of these:
http://marceljuenemann.github.io/angular-drag-and-drop-lists/ (HTML5)
https://github.com/JimLiu/angular-ui-tree (pure JavaScript)
If you just want to drop two elements into the container, then the library you mentioned also supports that, see this example:
http://codef0rmer.github.io/angular-dragdrop/#/list

ng-repeat next and previous navigation

I am looking for a way to implement ng-repeat next-prevous navigation. Navigation is inside repeating area, so the navigation arrows are shown if next or previous items exists.
But I need a way to add an active class to repeater on ng-click, so if I navigate to next item, it receives active class (and same with previous), so i can make that item visible and all other hidden.
<li ng-class="{active: ?}" ng-repeat="page in pages">
<p ng-bind-html-unsafe="page.content"></p>
<a ng-show="pages[$index - 1]" ng-click="?" class="previous" href="#">Previous</a>
<a ng-show="pages[$index + 1]" ng-click="?" class="next" href="#">Next</a>
</li>
Also if there is another way around this, please advise.
HTML:
<div ng-controller="MyCtrl">
<li ng-class="{active: activePage.page == $index,
inactive: activePage.page != $index}" ng-repeat="page in pages">
<p ng-bind-html-unsafe="page.content"></p>
<a ng-show="pages[$index - 1]" ng-click="activePage.page = $index-1"
class="previous" href="#">Previous</a>
<a ng-show="pages[$index + 1]" ng-click="activePage.page = $index+1"
class="next" href="#">Next</a>
</li>
</div>
CSS:
.active{
display:block;
}
.inactive{
display:none;
}
JS:
function MyCtrl($scope, $rootScope) {
/* Dont use a primitive but an object as ng-repeat creates
a scope of its own */
$scope.activePage = {
page:0
};
$scope.pages = [{content:"a"},{content:"b"},{content:"c"}];
}

Angular filter and order elements on click

I'm trying to filter a list of items (grabbed from JSON) onclick. I pull the data once from the server then would like to filter/order the elements using Angular.
Here is my plunker: http://plnkr.co/edit/glSz1qytmdZ9BQfGbmVo?p=preview
Tabs -- How could I filter/sort the items onclick? "Recent" would be sorted by date and "Popular" would be sorted by views.
Categories -- I'm using ng-click to grab the category value although not sure how to update the filter dynamically (using the value passed onclick).
Thanks
I would wrap the entire functionality inside a parent controller with the tab change and category select functions inside that parent controller (the child scopes will inherit this) so that the scope variables can be shared down for the filters and order By:
Reading Materials on Controller Inheritance: http://docs.angularjs.org/guide/dev_guide.mvc.understanding_controller
Demo: http://plnkr.co/edit/rh3wGYhuoHSHJEa4PoQi?p=preview
HTML:
<div ng-controller="ListController">
<div class="categories" ng-controller="CategoryController">
<ul ng-repeat="category in categories">
<li ng-click="sendCategory(category)">{{category.name}}</li>
</ul>
</div>
<div class="tabs" ng-controller="tabsController">
<ul>
<li ng-click="tab(1)">Recent items</li>
<li ng-click="tab(2)">Popular items</li>
</ul>
</div>
<div class="container">
<div class="left" ng-controller="ItemController">
<div class="itemList">
<div class="item" ng-repeat="item in items | filter:search | orderBy:sort">
<h3 ng-click="viewDetail(item)">{{item.title}} - {{item.date}}</h3>
<p>{{item.description}}</p>
<a ng-click="viewDetail(item)">View full item details</a>
</div>
</div>
</div>
</div>
</div>
Here is the parent controller:
myApp.controller('ListController', function($scope, $route, $location, $http, Categories){
$scope.sort = function(item) {
if ( $scope.orderProp == 'date') {
return new Date(item.date);
}
return item[$scope.orderProp];
}
$scope.sendCategory = function(category) {
// How can I pass this value to ItemController?
$scope.search =category.name;
};
$scope.orderProp='date';
$scope.tab = function (tabIndex) {
//Sort by date
if (tabIndex == 1){
//alert(tabIndex);
$scope.orderProp='date';
}
//Sort by views
if (tabIndex == 2){
$scope.orderProp = 'views';
}
};
})
** Update **
I've updated the controller to sort the dates correctly since they need to be parsed first.

Resources