How can I update a particular variable in an ng-repeat - angularjs

I have an ng-repeat that contains items, each of which has an ng-click.
<div ng-repeat="item in items">
<div ng-click="clickMe()">Show Item</div>
<div ng-show="show_item" ng-init="show_item = false>Item 1: {{item.name}}</div>
</div>
$scope.clickMe = function () {
$scope.show_item = !$scope.show_item
};
The problem is that I end up with a list of items that all have the show_item variable. For example, if I end up with a list of 10 items, and I click on the second item in the list, then how can I get angular to know that I want to show the 2nd item, and not one of the other items in the list?

All your items are sharing the scope variable show_item. you have to create this variable for each item
Change your ng-show and ng-init to ng-show="item.show_item" and ng-init="item.show_item = false". Also ng-click="clickMe(item)"
$scope.clickMe = function (item) {
item.show_item = !item.show_item
};

Related

ngRepeat doesn't refresh rendered value

I'm having an issue with ngRepeat :
I want to display a list of students in two different ways. In the first one they are filtered by group, and in the second they are not filtered.
The whole display being quite complex, I use a ngInclude with a template to display each student. I can switch between view by changing bClasseVue, each switch being followed by a $scope.$apply().
<div ng-if="currentCours.classesOfGroup !== undefined"
ng-show="bClassesVue">
<div ng-repeat="group in currentCours.classesOfGroup">
<br>
<h2>Classe : [[group.name]]</h2>
<div class="list-view">
<div class="twelve cell"
ng-repeat="eleve in group.eleves | orderBy:'lastName'"
ng-include="'liste_eleves.html'">
</div>
</div>
</div>
</div>
<div class="list-view" ng-show="!bClassesVue">
<div class="twelve cell"
ng-repeat="eleve in currentCours.eleves.all"
ng-include="'liste_eleves.html'">
</div>
</div>
My problem happens when my list of students change (currentCours here). Instead of refreshing the ngRepeat, both lists concatenate, but only in the unfiltered view.
I tried adding some $scope.$apply in strategic places (and I synchronize my list for example) but it doesn't help.
EDIT : the function used to refresh currentCours in the controller. It's called when a "cours" is selected inside a menu.
$scope.selectCours = function (cours) {
$scope.bClassesVue = false;
$scope.currentCours = cours;
$scope.currentCours.eleves.sync().then(() => {
if ($scope.currentCours.classe.type_groupe === 1) {
let _elevesByGroup = _.groupBy($scope.currentCours.eleves.all, function (oEleve) {
return oEleve.className;
});
$scope.currentCours.classesOfGroup = [];
for(let group in _elevesByGroup) {
$scope.currentCours.classesOfGroup.push({
name: group,
eleves: _elevesByGroup[group]
});
}
$scope.bClassesVue = true;
}
});
utils.safeApply($scope);
};
Well, I found a workaround, but I still don't know why it didn't work, so if someone could write an explanation, I would be very thankful.
My solution was simply to open and close the template each time I switch between views.

how to avoid duplicate items with ng-repeat and drop in angularjs?

Can you advice me the right sole of some issue?
I have next situation:
1.I load list of items from server and list it with ng-repeat in container here:
<div layout="column" id={{vm.folderId}}container flex layout-align="start center" class='container' dragula='"first-bag"'>
<div id={{item.id}}child class="md-whiteframe-5dp capitalize itemsInList" layout="column" ng-repeat="item in vm.workItems | filter:search">
<div layout="column" flex >
<div class="workItemName">{{vm.getWorkItemName(item.metadata)}}</div>
<div class="workItemDescription">{{vm.getWorkItemDescription(item.metadata)}}</div>
</div>
</div>
</div>
So lets say we have listed next list:
item_1
item_2
item_3
item_4
than I drop another element into this container, ITEM_5.
After I've droped server gives me new list: item_1 -
item_2 -
item_3 -
item_4 -
item_5
and I update my vm.workItems here:
if (data.ok) {
if (data.content.items.length != vm.workItems.length) {
vm.workItems = data.content.items; //from server
SharedDataService.setLastUpdateTimeStamp(SharedDataService.getNewUpdateTimeStamp());
}
}
After when it ng-repeat fresh items it also view droped element in list.So in the end I have:
item_1 //ng-repeated
item_2 //ng-repeated
item_3 //ng-repeated
item_4 //ng-repeated
item_5 //ng-repeated
item_5 //droped element
How to avoid this? is there some normal solving?
update. I drop element ,when it's droped I make request to server to ad new item to list:
$scope.$on('first-bag.drop', function (e, el, container) {
var elementId = parseInt(el[0].id);
var newContainerId = parseInt(container[0].id);
var newPrevElementId;
var newPrevElement = document.getElementById(el[0].id).previousElementSibling;
if(newPrevElement) {
newPrevElementId = parseInt(newPrevElement.getAttribute('id'));
} else if(!newPrevElement) {
newPrevElementId = newContainerId;
}
if(exContainerId != newContainerId) {
WebSocketService.addItem(elementId, exContainerId,
}
}
You can do
ng-repeat="item in vm.workItems track by item.id | filter:search"
If each item has a unique ID(or something unique property), and if you use track by ID, then even if server returns previous items with a new item added to it DOM will not get re-rendered, only new item will be added to the DOM.
Plunker (take a look at console)
ng-repeat adds $$hashkey property to each object when it repeats through a list of objects.
When your server returns the new data, though there are already existing objects, since, the new data(each object) does not contain $$hashkey property in it, ng-repeat re-renders then thinking they are new objects.
If you use track by ID then ng-repeat does not add a $$hashkey property, it keeps track of each item using ID. So, even if server returns same data again, since, ID's matches, ng-repeat does not repeat them. If there are new ID's then it renders then to the DOM.
Take a look at this blog post.
Try this in your function:
let data = data.content.items;
let temp = [];
data.forEach(function(item) {
if (temp.indexOf(item) === -1) {
temp.push(item);
}
});
vm.workItems = temp;
Hope this helps.

Why my angularjs filter does not apply some time when the object property change

I have array of object say person which have two property name and hideMe. i have make a directive to add, remove person from array and use filter to hide the person using property hideMe.
service
app.factory("personService", function () {
var person = function () {
this.name = "";
this.hideMe = false;
};
var persons = [];
return {
add: function () {
persons.push(new person());
},
hide: function (index) {
persons[index].hideMe = true;
}
}
});
controller
app.controller("personCtrl", function ($scope, personService) {
$scope.model = personService;
});
HTML
Add New Person
<table>
<tr>
<td>Name </td>
<td>remove</td>
</tr>
<tr ng-repeat="person in model.persons | filter : { hideMe: false}" >
<td>
<input type="text" ng-model="person.name">
</td>
<td>Hide Me </td>
</tr>
</table>
when i hide the person by click on hideMe link some time it is not hide ????
here is the fiddle http://jsbin.com/kolaraliki/1/
The reason you are experiencing this error is because of the use of $index.
$index gives the index of the current item in the iterator ng-repeat, not the index of the source element. As soon as an item is removed from the array, the $digest triggers the ng-repeat to re-calculate, and $index of the items in the ng-repeat are re-calculated. Thus, if you have 3 items in your array, at 0,1,2 but item 1 is hidden, you would expect your ng-repeat would have 2 items, 0,2 but it actually has 0,1. clicking to hide 2 would actually try to hide 1 in the array, which is already hidden.
instead of using $index, try instead model.hide(model.persons.indexOf(person)) to get the actual array index instead of the iterator index.
I forked your jsbin with an example: http://jsbin.com/jecosofequ/2/edit
It is because you have already filtered only those persons who have hideMe value as true to be shown and by clicking link which calls hide() you are simply setting hideMe value as true for second time. You can simply fix this by changing that filter to be filter: { hideMe: false } in your ngRepeat and then it should work. Because it would show's only those objects which hideMe values are false.

ng-repeat doesn't seem to be working

I am trying to pull all items from my array called 'collections'. When I input the call in my html I see only the complete code for the first item in the array on my page. I am trying to only pull in the 'edm.preview' which is the image of the item. I am using Angular Firebase and an api called Europeana. My app allows the user to search and pick which images they like and save them to that specific user.
here is the js:
$scope.users = fbutil.syncArray('users');
$scope.users.currentUser.collections = fbutil.syncArray('collections');
$scope.addSomething = function (something) {
var ref = fbutil.ref('users');
ref.child($rootScope.currentUser.uid).child('collections').push(something);
}
$scope.addSomething = function(item) {
if( newColItem ) {
// push a message to the end of the array
$scope.collections.$add(newColItem)
// display any errors
.catch(alert);
}
};
and the html:
<ul id="collections" ng-repeat="item in collections">
<li ng-repeat="item in collections">{{item.edmPreview}}</li>
</ul>
First, remove the outer ng-repeat. You want to only add the ng-repeat directive to the element which is being repeated, in this case <li>.
Second, from your AngularJS code, it looks like you want to loop over users.currentUser.collections and not just collections:
<ul id="collections">
<li ng-repeat="item in users.currentUser.collections">{{item.edmPreview}}</li>
</ul>
And third, you're defining the function $scope.addSomething twice in your JavaScript code. Right now, the second function definition (which, incidentally, should be changed to update $scope.users.currentUser.collections as well) will completely replace the first.

Parse scope variable name to scope function?

I have a dropdown menu and the clickable element that toggles the dropdown. When the user clicks on a list item in the dropdown menu I want to add that value to the input boxes value.
The dropdown menu I have is iterated a defined number of times to create a dropmenu listing incremented numbers.
<!--input-->
<input type="text" value="{{rooms}}">
<!--dropdown-->
<ul role="menu">
<li data-ng-repeat="i in getNumber(num_of_rooms)">
{{$index+1}}
</li>
</ul>
//This function simply returns an array so the dropdown menu repeats a defined number of times
$scope.getNumber = function(n) {
return new Array(n);
};
//I want this scope function to add the value to the input by updating a scope variable
$scope.addToDropDown = function(scope_name, value){
$scope.scope_name = value;
};
-----------
//This works but I'm defining a scope name which I would like to add dynamically as I have multiple dropdown menus
$scope.addToDropDown = function(value){
var val = value+1;
$scope.rooms = val;
};
Is there a way to assign a new value to the scope variable inside the view itself?
Is this what you want? http://plnkr.co/edit/Pew3KIoTy2fVp0tV3xv6?p=preview
give a string of the variable name to the click handler:
<a href="" ng-click="addToDropDown('rooms', $index)">
{{ $index + 1 }}
</a>
just refer the property of the given name in the handler:
$scope.addToDropDown = function(scope_name, value) {
$scope[ scope_name ] = value;
};

Resources