Angular ng-repeat value set - javascript

I use ng-repeat to construct table with radio buttons. The idea is to assign to each radio value the position of the object inside the original array (before ordering). When I use $index it assigns position in the ordered array and not original one. How to assign the right index,original one?
<tr class="restTable" data-ng-repeat="person in persons|orderBy:'name'">
<td> {{ person.name}}</td>
<td> <input type="radio" name="radio" ng-model="$parent.selectedPerson" value="{{$index}}"/></td>
</tr>

As I wrote in the comment:
$index is relative to to the current element in the loop and since you are sorting the array then you need to save a reference on the object itself from the directive (You can use person.id for example (If you have a unique id for each person).
You can save a reference to the selected person via ngValue
angular.module('app', []).controller('ctrl', function($scope) {
$scope.selected = { person: null };
$scope.persons = [{id: 1, name: "person1"}, {id: 2, name: "person2"}, {id: 3, name: "person3"}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<table>
<tr class="restTable" data-ng-repeat="person in persons|orderBy:'name'">
<td> {{ person.name}}</td>
<td> <input type="radio" name="radio" ng-model="selected.person" ng-value="person"/></td>
</tr>
</table>
<hr>
<p>Selected Person:</p>
<pre ng-bind="selected.person | json"></pre>
</div>
Here i'm using the ngValue and saving a reference to the selected object inside the loop. I don't care about the current position of the object because angularjs is making sure the selected person will be available in the controller via $scope.selected.person.
If you want to pre select a person, replace
$scope.selected = { person: null };
With
$scope.selected = { person: $scope.persons[1] };
But don't forget to declare $scope.persons before! Put that line after you declared the array in your controller. Example:
angular.module('app', []).controller('ctrl', function($scope) {
$scope.persons = [{id: 1, name: "3person1"}, {id: 2, name: "1person2"}, {id: 3, name: "4person3"}];
$scope.selected = { person: $scope.persons[1] };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<table>
<tr class="restTable" data-ng-repeat="person in persons|orderBy:'name'">
<td> {{ person.name}}</td>
<td> <input type="radio" name="radio" ng-model="selected.person" ng-value="person"/></td>
</tr>
</table>
<hr>
<p>Selected Person:</p>
<pre ng-bind="selected.person | json"></pre>
</div>

$index won't work as it represents index of loop, not the index of item in array. So to fix this you could have index property in source or you could write a function to return related index.
var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function(scope) {
scope.persons = [{
name: 'ABC index 0'
}, {
name: 'EFG index 1'
}, {
name: 'XYX index 2'
}];
scope.selectedPerson = "1";
scope.getIndex = function(item) {
return scope.persons.indexOf(item);
}
}])
angular.bootstrap(document.body, ['app']);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="ctrl">
Selected Person:-
<pre>{{persons[selectedPerson] | json}}</pre>
<hr/>
<table>
<tr class="restTable" data-ng-repeat="person in persons|orderBy:'name'">
<td> {{ person.name}}</td>
<td>
<input type="radio" name="radio" ng-model="$parent.selectedPerson" value="{{$parent.getIndex(person)}}" />
</td>
</tr>
</table>
</div>

Related

how to count items in nested ng-repeat without $index

I want to count iteration of ng-repeat, when condition match.
I've tried $index but it print for all itration/items in nested ng-repeat
Fiddle link :https://jsfiddle.net/gdr7p1zj/1/
<tbody ng-controller="MainCtrl">
<tr ng-repeat-start="a in test1">
<td>{{a.categoryName}}(count_here)</td>
</tr>
<tr ng-repeat-end ng-repeat="b in test" ng-if="a.categoryId==b.categoryId">
<td>{{b.name}}</td>
</tr>
</tbody>
i want like this
category_one(4) <=item count 4 items in this category so 4 will display
item1
item2
item3
item4
category_two(2)
item5
item6
<!-- this is in controller -->
$scope.test1=[{
categoryId:'1',categoryName:'category one'
},
{
categoryId:'2',categoryName:'category two'
}]
$scope.test = [
{categoryId:'1',name:'cate 1 elem0'},
{categoryId:'1',name:'cate 1 elem1'},
{categoryId:'2',name:'cate 2 elem'}
];
});
An option is to create a function (getCount) in the controller which do the count, something like this:
$scope.getCount = function(categoryId) { // returns the count by matching by categoryId
return $scope.test.filter(function(element) { // first, filter elements in `test`
return element.categoryId === categoryId; // matching by categoryId
}).length; // then, return the count of how many results we got after the filter
}
And in the html call that function like this:
<tbody ng-controller="MainCtrl">
<tr ng-repeat-start="a in test1">
<td>{{a.categoryName }} ({{getCount(a.categoryId)}})</td> <!-- <-- call the function in order to display the count -->
</tr>
<tr ng-repeat-end ng-repeat="b in test" ng-if="a.categoryId == b.categoryId">
<td>{{b.name}}</td>
</tr>
</tbody>
See a demo here: https://jsfiddle.net/lealceldeiro/v9gj1ok4/11/
Thanks for your help. But i get expected output without any functions call or filters
Here fiddle Link: https://jsfiddle.net/wk3nzj96/
htmlCode:
<div ng-app='myapp' >
<div ng-controller="MainCtrl">
<table ng-init="$scope.counter=0">
<tr ng-repeat-start="cate in mainCategory">
<td> {{cate.name}} ({{$scope.counter[$index]}})</td></tr>
<tr ng-repeat="itemsItr in items" ng-init="$scope.counter[$parent.$parent.$index]=$scope.counter[$parent.$parent.$index]+1" ng-if="itemsItr.mid==cate.id">
<td>{{itemsItr.name}}</td>
</tr>
<tr ng-repeat-end ng-if="false"></tr>
</table>
</div>
</div>
and ControllerCode:
(function() {
angular.module('myapp', []).controller('MainCtrl', function($scope) {
$scope.mainCategory = [
{ name: "categoryOne",id:1 },
{ name: "categoryTwo",id:2 }
];
$scope.items = [
{ name: "item1FromCateOne" ,mid:1 },
{ name: "item2FromCateOne",mid:1 },
{ name: "item3FromCateOne" ,mid:1 },
{ name: "item1FromCateTwo",mid:2 }
];
});
Is this Standard way to do this?

How to collect data for the rows that have been selected in AngularJS?

I am receiving a list of data from server and has displayed that in table format using ng-repeat along with checkbox in each row. My requirement is to pass the selected rows back to server upon clicking a removeUserData button. Am facing issue to get it done, help would be appreciated.
<table border="2" border-color=black>
<tr data-ng-repeat="user in users">
<td><input type="checkbox"></td><td>{{user.id}}</td><td>{{user.country}}</td><td>{{user.name}}</td>
</tr>
</table><br>
<button data-ng-click="removeUserData()" data-ng-show="users.length">Remove User</button>
I'd suggest you to make use of a new property in users, something like removed, then when checkbox is checked it will be true, otherwise false.
See it working:
(function() {
angular
.module("app", [])
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope'];
function MainCtrl($scope) {
$scope.removeUserData = removeUserData;
$scope.users = [
{
"id":1,
"country":"Italy",
"name":"Pavarotti"
},
{
"id":2,
"country":"French",
"name":"Some user"
}
];
function removeUserData() {
$scope.users = $scope.users.filter(function(user) {
return !user.removed;
})
}
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<table>
<tr ng-repeat="user in users">
<td>
<input type="checkbox" ng-model="user.removed">
</td>
<td ng-bind="user.id"></td>
<td ng-bind="user.country"></td>
<td ng-bind="user.name"></td>
</tr>
</table>
<div ng-if="users.length">
<hr>
<button ng-click="removeUserData()">Remove User</button>
</div>
</body>
</html>
your html
<div ng-app='myApp' ng-controller='myCtrl'>
<table border="2" border-color=black>
<tr data-ng-repeat="user in users">
<td>
<input type="checkbox" ng-change="storeIndexOfRow($index)">
</td>
<td>{{user.country}}</td>
<td>{{user.name}}</td>
</tr>
<button data-ng-click="removeUserData()" data-ng-show="users.length">Remove User</button>
Controller
var app = angular.module("myApp", []);
angular
.module('myApp')
.controller('myCtrl', ['$scope',
function ($scope) {
$scope.users = [
{ country: 'india', name: 'name1' },
{country: 'india2', name: 'name2'}
];
$scope.selectedIndex = [];
$scope.storeIndexOfRow = function (val) {
//write the logic for if checbox is checked or not
$scope.selectedIndex.push(val);
console.log($scope.selectedIndex);
};
$scope.removeUserData = function () {
angular.forEach($scope.selectedIndex, function (v, k) {
console.log($scope.users[v]);
});
};
}]);
One option is to use the ng-model to store a map that will decide for each row if it should be deleted or not,
The ng-model will bind the checkbox value to the given expression, in our case to a map.
for more information about ng-model see official documenation
the map will use user.id as a key, and will store a boolean value, based on the checkbox value.
lets call that map shouldDeleteUserMap.
Then we can filter your users array before sending it back to the server, based on shouldDeleteUserMap.
<table border="2" border-color=black>
<tr data-ng-repeat="user in users">
<td><input type="checkbox" ng-model='shouldDelteUserMap[user.id]' ></td><td>{{user.id}}</td><td>{{user.country}}</td><td>{{user.name}}</td>
</tr>
</table><br>
<button data-ng-click="removeUserData()" data-ng-show="users.length">Remove User</button>
and your controller, would look a bit like this:
angular.module('app',[])
.controller('myCtrl', function($scope){
$scope.shouldDelteUserMap = {};
$scope.users = [{
id: 1,
country: 'USA',
name: 'john'
},
{
id: 2,
country: 'Germany',
name: 'jane'
}];
$scope.removeUserData = function(){
var usersToRemove = $scope.users.filter( function(user){
return $scope.shouldDelteUserMap[user.id];
});
console.log(usersToRemove); // here comes your function that calls the server
}
});
and here is jsbin with an example:
http://jsbin.com/jisigiboha/edit?html,css,js,console,output

Angular select with ng-repeat loses selected option when options are updated

I am trying to create an editor for a dynamic list using AngularJS. For each item I would like to add a select list containing options for all elements in the list. When an item is added to the list (Add button in the JSFiddle), the other selects lose their values. The model is not affected by this, only the view. What am I missing?
Here is my JSFiddle.
View:
<div ng-controller="selectDemoCtrl">{{msg}}
<table>
<tr>
<td>id</td>
<td>references</td>
</tr>
<tr ng-repeat="item in items">
<td>
<input ng-model="item.id" type="number">
</td>
<td>
<select ng-model="item.ref">
<option ng-repeat="i in items" value="i.id" ng-selected="item.ref==i.id">{{i.id}}</option>
</select>
</td>
</tr>
</table>
<button ng-click="addItem()">Add</button>
<div>{{items | json}}</div>
</div>
Controller:
selectDemo.controller('selectDemoCtrl', function ($scope) {
$scope.items = [{
id: 1,
ref: 2
}, {
id: 2,
ref: 1
}];
$scope.addItem = function(){
var newitem = {id: 1, ref:1};
for (var i = 0; i < $scope.items.length; i++){
if ($scope.items[i].id >= newitem.id) { newitem.id = $scope.items[i].id + 1; }
}
if ($scope.items.length > 0){newitem.ref = $scope.items[0].id;}
$scope.items.push(newitem);
};
});
Don't use ngRepeat, it's not reliable for binding model. Use ngOptions instead, it should work as expected:
<select ng-options="i.id as i.id for i in items" ng-model="item.ref"></select>
Demo: https://jsfiddle.net/4bemy5wj/1/

Angularjs: How do I get the item in a list when using ngChange?

I'm trying to get the item that just changed in this small example, is there some kind of context I should use? I hoped it would be as simple as just referring to $this, but that doesn't seem to work.
<html ng-app>
<head>
<script src="https://code.angularjs.org/1.2.9/angular.min.js"></script>
<script>
function myController($scope) {
$scope.items = [
{ id: 1, name: "First" },
{ id: 2, name: "Second" },
{ id: 3, name: "Third" }
];
$scope.test = function() {
// How do I get the object in the list related to the change i did?
// I.e. "{ id: 2, name: "Second" }" for the second item.
};
}
</script>
</head>
<body>
<div ng-controller="myController">
<table>
<tbody ng-repeat="item in items">
<tr>
<td>{{ item.id }}</td>
<td><input type="text" ng-model="item.name" ng-change="test()"/></td>
</tr>
</tbody>
</table>
</div>
</body>
Take a look at this
Working Demo
html
<div ng-app='myApp' ng-controller="myController">
<table>
<tbody ng-repeat="item in items">
<tr>
<td>{{ item.id }}</td>
<td><input type="text" ng-model="item.name" ng-change="test(item.name)"/></td>
</tr>
</tbody>
</table>
</div>
script
var app = angular.module('myApp', []);
app.controller('myController', function ($scope) {
$scope.items = [
{ id: 1, name: "First" },
{ id: 2, name: "Second" },
{ id: 3, name: "Third" }
];
$scope.test = function(item) {
alert(item);
};
});

Is it possible to dynamically assign `ng-model` in AngularJS

Problem Description
I am trying to create a simple Grid using AngularJS. Each cell in this grid has one text-input . There is one extra text-input(I call it global) whose ng-model should be dynamincally assigned to one of the grid-cell, whenever the user focus on that grid-cell.
Isn't that clear ?? Let me show my unsuccessful implementation :
The Markup
<body ng-controller="MainCtrl">
<b> Global : </b>
<input type="text", ng-model="global" size=50 />
<br />
<b> Grid : </b>
<table>
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td> <input type="text" ng-model="item.name" grid-input="global" /></td>
<td> <input type="text" ng-model="item.address" grid-input="global" /></td>
<td> <input type="text" ng-model="item.email" grid-input="global" /></td>
</tr>
</tbody>
</table>
</body>
The Angular App
var app = angular.module('app', []);
app.directive('gridInput', function($rootScope){
return {
restrict : 'AE'
, scope : {
model : '=ngModel'
, global : '=gridInput'
}
, link : function(scope, iElem, iAttrs) {
$(iElem).on('focus', function(e){
scope.global = scope.model;//what is this doing?? I don't KNOW!
})
}
}
});
app.controller('MainCtrl', function($scope) {
$scope.items = [
{name : 'Lekhnath Rijal', address:'Ilam, Nepal', email:'me#gmail.com'},
{name : 'abc def', address:'ghi, jkl', email:'mnop#qrst.uv'}
];
});
What do I want
I want two-way data binding between the global text-input and one of the grid-cell after the cell gets focused. The binding between these two inputs should persist until one of other grid-cell receives focus.
Here is a Plunker
Instead of using custom-directive, you can use ng-change, ng-focus to change the selected item.
index.html
<body ng-controller="MainCtrl">
<b> Global : </b>
<input type="text", ng-model="global.text" size=50 />
<br />
<b> Grid : </b>
<table>
<thead>
<tr>
<th>Name</th>
<th>Address</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>
<input
type="text"
ng-model="item.name"
ng-focus="global.text=item.name; setSelectedItem(item, 'name')"
ng-change="global.text=item.name"/>
</td>
<td>
<input
type="text"
ng-model="item.address"
ng-focus="global.text=item.address; setSelectedItem(item, 'address')"
ng-change="global.text=item.address"/>
</td>
<td>
<input
type="text"
ng-model="item.email"
ng-focus="global.text=item.email; setSelectedItem(item, 'email')" ng-change="global.text=item.email"/>
</td>
</tr>
</tbody>
</table>
</body>
app.js
app.controller('MainCtrl', function($scope) {
$scope.global = {};
$scope.items = [{
name: 'Lekhnath Rijal',
address: 'Ilam, Nepal',
email: 'me#gmail.com'
}, {
name: 'abc def',
address: 'ghi, jkl',
email: 'mnop#qrst.uv'
}];
$scope.$watch('global.text', function(text) {
if (text != undefined && $scope.selectedItem) {
$scope.selectedItem[$scope.selectedAttribute] = text;
}
}); $scope.setSelectedItem = function(item, attribute) {
$scope.selectedItem = item;
$scope.selectedAttribute = attribute;
}
});
Here is the plunker:
http://plnkr.co/edit/r7rIiT?p=preview

Categories