AngularJs toggling function for selected item in ng-repeat - javascript

I have a list of items, and I have enable/disable method as an option for each item in a list.
I want to toggle only one item in a list:
Current implementation toggles all items in a list, and changes class icons for all.
HTML
<div class="device" ng-repeat="item in items" ng-class="{'open': item.isOpen}">
<!-- Enable/Disable-->
<a href="#" class="m-r-20" ng-click="test.toggleMethod(item.Id)">
<span class="{{test.buttonClassIcon}}" title="{{test.title}}"></span>
</a>
</div>
Controller
model.enabled = true;
model.toggleMethod = function (deviceId) {
if (model.enabled) {
locationService.start(deviceId).then(deviceList);
} else {
locationService.stop(deviceId).then(deviceList);
}
model.enabled = !model.enabled;
model.buttonClassIcon = model.enabled ? 'fa fa-bell' : 'fa fa-bell-slash';
model.title = model.enabled ? 'Enable' : 'Disable';
};
When I click bell, it changes class to all, and toggles global variable.

You should have an enabled property for each element in the list.
model.items.map(function(item){
item.enabled = false; // or other default value
});
and the in the html :
<a href="#" class="m-r-20" ng-click="test.toggleMethod(item)">
<span ng-if="item.enabled" class="fa fa-bell" title="Enable"></span>
<span ng-if="!item.enabled" class="fa fa-bell-slash" title="Disable"></span>
</a>
or you can use ng-class or create functions like getTitle(item.enabled) which returns the corresponding title.
and the toggleMethod:
model.toggleMethod = function (device) {
var deviceId = device.Id;
if (device.enabled) {
locationService.start(deviceId).then(deviceList);
} else {
locationService.stop(deviceId).then(deviceList);
}
device.enabled = !device.enabled;
};
Here is the fiddle.
Hope this is what you were trying to achieve.

Inside your function you dont enable/disable the selected item , instead you enable/disable a model object.
I am going to make an assumption , according to your snippet.
Since you have the item id or you can pass the $index(the position into the items array) you could do :
//also pass $index into ng-click function
<span class="{{test.buttonClassIcon}}" title="{{test.title}}"></span>
and into function body check the selected item:
model.toggleAlarmMethod = function (deviceId,indx) {
if ($scope.items[indx].enabled) {
locationService.start(deviceId).then(deviceList);
} else {
locationService.stop(deviceId).then(deviceList);
}
//enable/disable selected item
$scope.items[indx].enabled = !$scope.items[indx].enabled;
$scope.items[indx].buttonClassIcon = $scope.items[indx].enabled ? 'fa fa-bell' : 'fa fa-bell-slash';
$scope.items[indx].title = $scope.items[indx].enabled ? 'Enable' : 'Disable';
};

Related

Content Editable = true, but only takes one value at a time

I'm working on a simple project where I need to make an item in a list editable and then update a JS item to store this.
I'm using Content Editable = True, and it works when I comment out my handleItemEdit function, but when I turn it on, I can only insert one character at a time, forcing me to keep clicking to edit.
Clearly this problem stems from my function, but I can't seem to figure out why.
//Responsible for listening for an edit and updating my object with the new text.
function handleEditItem() {
$('.js-shopping-item').on('input', function(event) {
const itemIndex = getItemIndexFromElement(event.currentTarget); //assigning the index of the the editted item to itemIndex
const updatedItem = STORE.items[itemIndex];
updatedItem.name = event.currentTarget.innerHTML;
renderShoppingList();
});
}
//Returns the index of an Item in the Store
function getItemIndexFromElement(item) {
const itemIndexString = $(item)
.closest('.js-item-index-element')
.attr('data-item-index');
return parseInt(itemIndexString, 10);
}
//Function responsible for returning the template HTHML to insert into the html.
function generateItemElement(item) {
let itemIndex = STORE.items.indexOf(item);
return `
<li class="js-item-index-element" data-item-index="${itemIndex}">
<span contentEditable='true' class="shopping-item js-shopping-item ${item.checked ? 'shopping-item__checked' : ''}">${item.name}</span>
<div class="shopping-item-controls">
<button class="shopping-item-toggle js-item-toggle">
<span class="button-label">check</span>
</button>
<button class="shopping-item-delete js-item-delete">
<span class="button-label">delete</span>
</button>
</div>
</li>`;
}

How to get element by id which is dynamically created by ng-repeat in angularjs

I am only posting the necessary code and solving this much will clear rest of my doubts. I am new to angularjs, so kindly forgive if I am asking something stupid.
I am using ng-repeat to generate a list which uses an array defined in the controller scope. When I click on 'Add Another' button, a new element is created. I want to get access of this element to add a class to it. But when I use 'getElementById' function in the same function 'addNewForm' I get 'null'.
However, when I call function 'fn' by hitting 'Find Untitled' button, I get the correct element. Could anybody explain and solve this? Any help is appreciated. Thanks in advance!
I am posting the code below:
HTML:
<div ng-controller="myctrl3">
<ul id ="menu_Ul">
<li ng-repeat="x in list">
<button id="{{ 'navAppsButtonID-' + $index }}">{{x}}</button>
<br>
</li>
<li>
<button ng-click="addNewForm()">Add another</button>
</li>
</ul>
<button ng-click="fn()">Find Untitled</button>
</div>
JS:
.controller("myctrl3", function($scope) {
var list = ['abcd', 'efgh', 'ijkl', 'mnop'];
$scope.list = list;
$scope.abc = function () {
var listPush = function () {
$scope.list.push("Untitled Menu");
for(var i = 0;i<$scope.list.length-1;i++) {
var element = document.getElementById('navAppsButtonID-'+i);
element.classList.remove('current');
}
};
var listLen = $scope.list.length;
if($scope.list[listLen-1] === undefined) {
listPush();
}
else if ($scope.list[listLen-1] == "Untitled Menu") {
alert("Cannot open more than one Untitled Menu at the same time.");
}
else {
listPush();
}
};
$scope.addNewForm = function() {
$scope.abc();
console.log("Element is: ", document.getElementById('navAppsButtonID-'+($scope.list.length-1)));
};
$scope.fn = function () {
console.log("Element is: ", document.getElementById('navAppsButtonID-'+($scope.list.length-1)));
};
})
You're thinking too much jQuery and too little angular. If the goal is to add a class to the last element of ng-repeat, this is how you do that:
<li ng-repeat="x in list">
<button ng-class="{ current: $last }">{{ x }}</button>
</li>
$last is a variable available inside ng-repeat, and if it's true, ng-class will set the class current on the element.
You don't assign unique ids to elements to getElementById from somewhere else when working in angular.

ng-show working with multiple filters in ng-repeat

I have an ng-repeat list with multiple filters, but as I need the elements to be hidden and not removed from the DOM, I use ng-show for the filtering.
This is how my first filter look like:
<a href="" ng-click="myFilter = ''; toggle = toggle=0; togglesec=0; mySecondFilter = {}" ng-class="{'active' : toggle==0}" >
Tot
</a>
<a href="" ng-click="myFilter = 'pa'; toggle = toggle=1; togglesec=0; mySecondFilter = {}" ng-class="{'active' : toggle==1}">
Pa
</a>
<a href="" ng-click="myFilter = 'Reposteria'; toggle = toggle=2; togglesec=0; mySecondFilter = {}" ng-class="{'active' : toggle==2}">
Reposteria
</a>
And the second one:
<div ng-init="togglesec=0; mySecondFilter = {}">
<a ng-click="mySecondFilter = {}; togglesec = togglesec=0" ng-class="{'active' : togglesec==0}">
All
</a>
<a ng-click="mySecondFilter = {'vegan': true}; togglesec = togglesec=1" ng-class="{'active' : togglesec==1}">
Vegan
</a>
<a ng-click="mySecondFilter = {'gluten': true}; togglesec = togglesec=2" ng-class="{'active' : togglesec==2}">
Gluten Free
</a>
</div>
Now, I was able to filter the ng-repeat using ng-show and the first filter like so:
<div ng-repeat="pa in products" ng-show="pa.tipus.indexOf(myFilter) != -1">
Basically it compares the value of myFilter with the pa.tipus object property, and it works OK.
But it won't work with the second filter, because mySecondFilter is an object, not a string (it needs to filter the results containing vegan:true or gluten:true)
Here's an example of my object type:
pa {
tipus : 'pa',
gluten : false,
vegan : true
}
Any tips on how to combine both filters in the same ng-show?
EDIT
I've applied the answer by Naren, but I get the following error on click on any filter:
angular.min.js:122 TypeError: Cannot create property 'vegan' on string ''.
I've also tried to initialize myFilter by adding this, but no luck, same error appears:
$scope.myFilter = {
tipus : '',
vegan : '',
gluten : '',
lactosa : ''
};
Update:
Since the user wanted a generic version for the filtering. The following function should be the answer.
$scope.validate = function(row) {
for (var key in $scope.myFilter) {
if ($filter('filter')([row], {
[key]: $scope.myFilter[key]
}).length === 0) {
return false;
}
}
return true;
}
Where we loop through an object where all the filters are stored, then return false if any of the filters are not satisfied.
Please check the below example to get a understanding of how the filter works.
JSFiddle Demo
Old:
Here is my version of the fix. Angular's $filter will be great for identifying the object with the property, but this is not possible to have written in the HTML, hence I call a function which will return true or false to the ng-show.
$scope.validate = function(row) {
if (row.tipus.indexOf($scope.myFilter) != -1) {
if ($filter('filter')([row], $scope.mySecondFilter).length !== 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
Let me explain the function. First we receive the row of the ng-repeat through the parameter of validate, after which I apply the first if condition which is basically whatever you had written earlier, this code works great btw. Then I check the row using the $filter syntax for the object present in $scope.mySecondFilter, Refer here for more on filtering with $filter, this will basically check if the row passed contains the required object property and return true or false.
Here is a working example of your code for reference.
JSFiddle Demo
Please let me know if this fixes your issue completely :)

How to select all with ng-checked and ng-model

I have an Ionic application(it work the same like Angularjs) and I have a little problem.
<ion-list class="list-inset subcategory" ng-repeat="item in shops">
<ion-checkbox class="item item-divider item-checkbox-right" ng-model="selectAll">
{{item}}
</ion-checkbox>
<ion-item ng-repeat="value in data | filter:{shopName: item}" class="item-thumbnail-left" ng-click="openProduct(value)">
...
<div class="row">
<ion-checkbox stop-event='click' ng-model="value.selected" ng-checked="selectAll">{{value.name}}</ion-checkbox>
</div>
...
</ion-list>
When I click on item with ng-model="selectAll" all items is selected. But I have property value.selected. It sets false for each one value. When I click on item with ng-model="value.selected" it changes. But when I want selec all and click on item with ng-model="selectAll" this propety doesn't change.
Help me please.
Note: I have ng-repeat in the ng-repeat. First ng-repeat is for shops, the second is for products. And I have a filter by shopName. And I want select all by shops. Now it works how I want, but doesn't change property value.selected. Value it is produt, item it is shop.
the state of selectAll can be derived from the state of your other check boxes so it should not be stored as a seperate field.
You could use a getterSetter on the selectAll model to determine weather it should be checked. e.g.
<input type="checkbox" ng-model="selectAll" ng-model-options="{getterSetter: true}"/>
JS
var getAllSelected = function () {
var selectedItems = $scope.Items.filter(function (item) {
return item.Selected;
});
return selectedItems.length === $scope.Items.length;
}
var setAllSelected = function (value) {
angular.forEach($scope.Items, function (item) {
item.Selected = value;
});
}
$scope.selectAll = function (value) {
if (value !== undefined) {
return setAllSelected(value);
} else {
return getAllSelected();
}
}
http://jsfiddle.net/2jm6x4co/
you can use ngClick on the item with ng-model="selectAll". you can call a function in ng-click and then make selected=true for all other items where ng-model="value.selected".

Change css class of button clicked in angular with ng-repeat

This is what I want to do:
I get json from an api: ✓
I use ng-repeat to display all the data as a button: ✓
The user can click a button: ✓
if the data attribute for that particular button was "premier", log "premier", if it was "random", then log random: ✓
if the data attribute of this button was "premier", the class should be "btn-danger disabled" : ✗
I'm working in a laravel blade document, so I have to skip angular's double curly brackets by placing an # in front, like this: #{{ xxx }}.
The code at the moment correctly logs the data-correct attribute. But it changes the class of all the buttons, not only the one clicked.
My code:
html:
<a href ng-click="validateClick(premier.correct, $index)"
ng-class="{premier: isPremier, random: isRandom}"
ng-repeat="premier in premiers"
class="btn btn-default btn-game"
data-correct="#{{premier.correct}}"
href="#"
role="button">
#{{premier.name}}
</a>
app.js:
$scope.validateClick = function(row, index) {
if (row == "premier") {
$scope.isPremier = true;
console.log($scope.isPremier + index)
}
else {
$scope.isRandom = true;
console.log($scope.isRandom + index)
}
}
Instead of assigning to the common scope variable assign it to the premier object and use it in the class
HTML
<div ng-click="validateClick(premier, $index)" ng-class="{premier: premier.isPremier, random: premier.isRandom}" ng-repeat="premier in premiers" class="btn btn-default btn-game" data-correct="{{premier.correct}}" href="#" role="button">
{{premier.name}}
</div>
Controller
$scope.validateClick = function (premier, index) {
if (premier.correct == "premier") {
premier.isPremier = true;
console.log(premier.isPremier + index)
} else {
premier.isRandom = true;
console.log(premier.isRandom + index)
}
}
Working sample is available in the jsFiddle
http://jsfiddle.net/cce2g6y2/1/

Categories

Resources