Variable to affect single item in ng-repeat - javascript

I have an ng-repeat listing items with a button inside, which updates certain info from this item into the DB and then retrieves the new object.
I'm trying to show a loading gif while this happens, but so far the gif appears on all items of the ng-repeat, as I'm using a $scope variable.
Like so:
<div ng-repeat="fair in allfairs">
<img ng-show="loading" src="../images/loading.gif">
<a ng-click="deactivate(fair)" ng-if="!loading">Deactivate</a>
</div>
And in the controller:
$scope.deactivate = function(fair){
$scope.loading = true;
var $promisedb=$http.post('databaseconnect/updatefair.php',$scope.activated);
$promisedb.then(function (data) {
$scope.loading = false;
});
};
How could I achieve the same but only for the particular item that I'm clicking on without affecting the whole array?

Assign the item to a scope variable instead and compare item to that scope variable in ng-if
$scope.deactivate = function(fair){
$scope.loadingItem = fair;
var $promisedb=$http.post('databaseconnect/updatefair.php',$scope.activated);
$promisedb.then(function (data) {
$scope.loadingItem = false
});
};
View
<a ng-click="deactivate(fair)" ng-if="loadingItem != fair">Deactivate</a>

You can chain the img element and a element together via $index of the array allfairs,and you must change the type of loading to object {},when you click the a element,you should add a item to loading,and you can take the $index as the key of item.The loading gif which has a $index will be affected by same $index which has clicked on a element. The code looks like below:
<div ng-repeat="fair in allfairs">
<img ng-show="loading[$index]" src="../images/loading.gif">
<a ng-click="deactivate(fair,$index)" ng-if="!loading[$index]">Deactivate</a>
</div>
$scope.loading = {};
$scope.deactivate = function(fair,index){
$scope.loading[index] = true;
var $promisedb=$http.post('databaseconnect/updatefair.php',$scope.activated);
$promisedb.then(function (data) {
$scope.loading[index] = false;
});
};

Related

Ng-repeat and directive expand one list item at a time

I have an ng-repeat code with expandable list items. I would like to expand one item at a time.
The way I am trying to do it is
in the html file
<div data-ng-repeat="parts in data track by $index">
<li id="titleHelp" ng-click='setItem($index);">
and in the directive in the setItem function I want to collapse the previously expanded item and expand the new one. Is it possible to access one repeat element in the directive using index?
thanks!
How do you currently expand the list item?
What I would do is set a variable as soon as an item is clicked and in your repeated list do a
<div data-ng-repeat="parts in data track by $index">
<li id="titleHelp" ng-click='setItem($index);">
<div ng-show="$index = selected_item"> <!-- contents --></div>
In your setItem function:
$scope.setItem = function(i) {
$scope.selected_item = i;
}
Declare a object
$scope.obj={selected:null};
After that add a method in the ng repeat,
$scope.isHide = function (id) {
if (id == $scope.obj.selected)
return $scope.obj.selected = "all";
return $scope.obj.selected = id;
}
If you want to hide div, call this method with the id. Do the same thing for the li if you need.

dynamically change ng-repeat

I have an object made like this:
var examples = {
'example1': {
ex1: {},
ex2: {},
ex3: {}
},
'example2': {
ex1: {},
ex2: {},
ex3: {}
}
}
There is a button linked to a function which fills the example1 object with values on the first click, and the example2 object on a second click.
First click: example1 get values.
Second click: example2 get values.
Then i loop through the object using ng-repeat, like this:
data-ng-repeat="example in examples.example1.ex1"
data-ng-repeat="example in examples.example1.ex2"
data-ng-repeat="example in examples.example1.ex3"
The problem here is, i need the ng-repeat to somehow change and loop through the example2 object aswell when the button is clicked a second time. So my question is, is there a way to change ng-repeat dynamically?
EDIT: The goal is for the first list of appear after the first click, and then for BOTH lists appear together after the second click.
I tried to make a $scope with the value 2 and put it in the ng-repeat, but that didn't work.
$scope.counter = 2; //in a controller
data-ng-repeat="example in examples.example(counter).ex1"
Use dynamic property name
$scope.prop = 'example1';
$scope.click = function (newProp) {
$scope.prop = newProp;
// do whatever you want here
// change prop to example2 or
// or simply toggle Boolean to change prop text
}
And in html use
ng-repeat="example in examples[prop].ex1"
Would it be a solution to loop through "examples" instead, and then have a ng-repeat inside an ng-repeat?
Something like this:
<div data-ng-repeat="example in examples">
<div data-ng-repeat="ext in example">
{{ext.ex1}} {{ext.ex2}} {{ext.ex3}}
</div>
</div>
Do something like Jannik's answer in the html and this in the JS:
$scope.examples = {};
function example(exes) {
this.exes = exes;
}
$scope.onClick = function(exes) {
$scope.examples.push(new example(exes));
}
The exes is a list of ex1,ex2,etc. You may need a $scope.$apply() at the end of this to update the UI.

tabs not storing scope vars

My markup:
<li active="active.search">search</li>
<li active="active.lists">lists</li>
<li active="active.find">find</li>
My code:
$scope.active = {
search: true
};
$scope.activate = function(li) {
$scope.active = {};
$scope.active[li] = true;
}
First - the item I've set to be highlighted, doesn't actually get highlighted by default, however they do work when clicked.
Secondly - I'm trying to use what is actually active via:
if ($scope.active[0].search === true) {
... some values
}
Is this not correct? as I can't seem to make this work.
active isn't an angular directive so you need to enclose the variable in angular brackets {{ }} like
active="{{active.search}}"
for angular to parse it.

How to Programatically check elements and add class in angular?

I have an app where I am running ng-repeat to display information. I need to then add classes to some of the generated elements after an Ajax call has been made.
I could do this easily with jQuery but I'm trying to stick to Angular/jqlite.
The problem I'm having is that I can get the element, but not as an object that addClass works on.
Here's what I've got so far:
angular.forEach($(".tile"), function(tile){
if(srv.free.indexOf(angular.element(tile.querySelector('.label')).text()) != -1){
tile.addClass("free");
}
});
The array srv.free contains a list of names, those name values are the same as the text value of the div with class .label, which is inside of .tile. So I need to loop through each .tile, check the text value of the child .label and if that text value is in the array srv.free, add the class .free to .tile.
The point I'm at, is that addClass is "undefined" because at this point, tile is just a string, not a jquery/jqlite object.
How do I add a class to that, or get to the object version?
Update
I have previously tried to use ng-class on the elements to update the class, but could not get them to update.
I have a service that has free in it, which is initially set to a blank array. After an Ajax call:
$http.get('/json/free.json').success(function(data){
srv.free = data;
});
Then, in my controller I have:
$scope.gsrv = globalService;
and in my ng-repeat:
<div class="col-xs-3 col-md-2" ng-repeat="Tile in list.tiles">
<div class="tile" id="{{$index}}" ng-class="{free:$.inArray(Tile.Name, gsrv.free)}" ng-click="main.changeView('/Tile/'+$index)">
<img src="http://placehold.it/256" ng-src="{{Tile.Icon}}" ng-class="{dis:!Tile.Stats}">
<div class="label">{{Tile.Name}}</div>
</div>
</div>
When that didn't work, I tried adding:
$scope.gsrv.free = globalService.free;
which did not change anything.
You state that the elemens are rendered in an ng-repeat. Therefore you can just use the ng-class directive to add a class based on some variable, something like the following:
<div ng-repeat="tile in tiles"
ng-class="{ free: tile.someVariable }"> // <-- adds a class 'free' when someVariable verifies to true
<label>{{ tile.someVariable }}</label>
</div>
UPDATE
You can add those variables to the tiles, after the ajax call:
$http.get('/json/free.json').success(function(data){
setTilesFree(data);
});
var setTilesFree = function (free) {
var tiles = $scope.list.tiles; // shortcut
for (var i = 0; i < tiles.length; i++) {
// If in 'free' array, set tile free = true
// This will update the DOM from this tile, adding the class 'free'
if (free.indexOf(tiles[i].Name) > -1) {
tiles[i].free = true;
} else {
tiles[i].free = false;
}
}
}
Then in your view:
<div ng-repeat="Tile in list.tiles">
<div ng-class="{free: Tile.free}">
<img src="http://placehold.it/256" ng-src="{{Tile.Icon}}" ng-class="{dis:!Tile.Stats}">
<div class="label">{{Tile.Name}}</div>
</div>
</div>
See this jsfiddle
You can return empty array from list and free services and populate them later. Since Angular runs digest cycle after every $http.get, $scope will be properly updated and binding will work as expected. The most tricky thing is to populate the same existing array (initially returned by service) instead of creating new one every time. This is required, because controller function will not run again every time digest is running and therefore new array instance will not be assigned to the $scope. Here is on of the possible solutions:
JavaScript
angular.module('app',[]).
factory('list', ['$http', function($http) {
var tiles = [];
return {
getList: function() {
if(!tiles.length) {
$http.get('data.json').then(function(res) {
res.data.forEach(function(item) {
tiles.push(item);
});
});
}
return {
tiles: tiles
};
}
}
}]).
factory('free', ['$http', function($http) {
var free = [];
return {
getFree: function() {
if(!free.length) {
$http.get('free.json').then(function(res) {
res.data.forEach(function(item) {
free.push(item);
});
});
}
return free;
}
}
}]).
controller('ctrl', ['$scope', 'list', 'free', function($scope, list, free){
$scope.list = list.getList();
$scope.free = free.getFree();
}]);
HTML
<div class="col-xs-3 col-md-2" ng-repeat="Tile in list.tiles">
<div class="tile" ng-class="{free: free.indexOf(Tile.Name) > -1}">
<img ng-src="{{Tile.Icon}}" ng-class="{dis:!Tile.Stats}">
<div class="label">{{Tile.Name}}</div>
</div>
</div>
Plunker
http://plnkr.co/edit/UEWnexi3wVU6eLN1BW2b?p=preview
Update:
http://plnkr.co/edit/vOHkLyCHQFoWdqaix4pH?p=preview
(the same example with static pre-populated list, and also service instead of factory)

AngularJS disabling one dropdown in ng-repeat

I have the following ng-repeat in my HTML code:
<div ng-repeat="a in items">
<div>
<span>{{a.name}}</span>
</div>
<div>
<select ng-model="a.c_id" ng-options="d.c_id as d.description for d in loclist" ng-disabled="display" ng-change="selected(a.c_id)">
</select>
</div>
Then in my controller I have:
$scope.display = false;
$scope.selected = function (value) {
$scope.te = value;
if ($scope.te == 3) {
$scope.display = true;
}
};
Problem I am facing is that when I change the selection in the drop down it is supposed to disable or enable the dropdown based on value. However when I change the selection in one of the drop down that has value of 3 all the dropdowns change to disabled state rather than that particular one.
Please let me know how to fix this code so when after ng-repeat has displayed all rows and I change the dropdown value of one of the rows it just disables that particular one rather than disabling all the dropdowns in all rows.
Angular ng-repeat creates child scopes inherited from parent scope. In your case, all your ng-repeat's scopes inherit the display property from parent scope. Therefore when this property changes, it reflects on all scopes.
Try this instead of $scope to access the current scope of ng-repeat:
$scope.selected = function (value) {
this.te = value;
if (this.te == 3) {
this.display = true;
}
};

Categories

Resources