ng-repeat errors. Can't read property of undefined - angularjs

I have two errors saying: Cannot read property 'active' of undefined and Cannot read property 'boss' of undefined while I'm trying to use ng-repeat over my array of users.
In the controller I'm using the following code:
$scope.users = [
{
id: 1,
name: 'John',
birthday: '06.07.2008',
city: 'Budapest',
active: false,
boss: false
},
{
id: 2,
name: 'Mary',
birthday: '01.02.2003',
city: 'Berlin',
active: false,
boss: true
},
{
id: 3,
name: 'James',
birthday: '04.05.2006',
city: 'Vienna',
active: false,
boss: false
}
];
$scope.isActive = function (id) {
return $scope.users[id].active;
}
$scope.isBoss = function (id) {
console.log($scope.users[id]);
return $scope.users[id].boss;
}
In the view I have following code:
<thead>
<tr>
<th>#</th>
<th>Username</th>
<th>Birthday</th>
<th>City</th>
<th>Active</th>
<th>Boss</th>
</tr>
</thead>
<tbody>
<div>
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.birthday}}</td>
<td>{{user.city}}</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }">
</td>
</tr>
</div>
</tbody>
At the end it prints the table in the right way but also throws those errors. Did I miss something?
Also here's rendered result:
<tbody>
<!-- ngRepeat: user in users -->
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users" class="ng-scope">
<td class="ng-binding">1</td>
<td class="ng-binding">John</td>
<td class="ng-binding">06.07.2008</td>
<td class="ng-binding">Budapest</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }" checked="checked">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }" checked="checked">
</td>
</tr>
<!-- end ngRepeat: user in users -->
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users" class="ng-scope">
<td class="ng-binding">2</td>
<td class="ng-binding">Mary</td>
<td class="ng-binding">01.02.2003</td>
<td class="ng-binding">Berlin</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }" checked="checked">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }" checked="checked">
</td>
</tr>
<!-- end ngRepeat: user in users -->
<tr ng-click="goToProfile(user.id)" ng-repeat="user in users" class="ng-scope">
<td class="ng-binding">3</td>
<td class="ng-binding">James</td>
<td class="ng-binding">04.05.2006</td>
<td class="ng-binding">Vienna</td>
<td>
<input type="checkbox" name="active" ng-checked="{ checked: isActive(user.id) }">
</td>
<td>
<input type="radio" name="boss" ng-checked="{ checked: isBoss(user.id) }">
</td>
</tr>
<!-- end ngRepeat: user in users -->
</tbody>

That's because your isActive and isBoss functions are being passed user.id. I observed your user.id starts from id 1, meanwhile in these functions, you're trying to access the $scope.users using the indexes passed in. What happens is that, for example, a user.id of 3 in your isActive function would try to access $scope.users[3].active. However, there's actually no index 3 (representing the fourth item in the $scope.users array, which is undefined)
Change your ..isActive(user.id) to ...isActive($index) and your ...isBoss(user.id) to ...isBoss($index)

Related

ng-if to hide/show row when value =0

The table has columns - ID, PASSED, FAILED and there is a checkbox -show students with no FAILURES
I can't figure out how to use angular ng-if to bind the checkbox with the table. So if the user checks the checkbox , it should show all rows else only students with no failures. I'm new to angularJS :|
<tr>
<td><span class="CheckBox"><input type="checkbox" value="">Show Students with No Failures</span></td>
</tr>
<tbody >
<!--display none-->
<tr ng-repeat="t in table">
<td colspan="1" ng-hide='t.Failed===0'>{{t.id}}</td>
<td colspan="1" ng-hide='t.Failed===0'>{{t.Total}</td>
<td colspan="1" ng-hide='t.Failed===0'>{{t.Passed}}</td>
<td colspan="1" ng-hide='t.Failed===0'>{{t.Failed}}</td>
</tr>
Added a implementation of what you are trying to accomplish.
Using a ng-repeatin combination with a filter.
See JSFIDDLE
VIEW
<div id="app" ng-app="myApp" ng-controller="myCtrl">
Only passes students?
<input type="checkbox" ng-init="passes = true" ng-model="passes">
<br/> Not passed student students?
<input type="checkbox" checked ng-init="fails = true" ng-model="fails">
<br/>
<br/>
<table cellspacing="0" cellpadding="0">
<tbody>
<tr class="days">
<th>Student name</th>
<th>#FAILS</th>
<th>PASSED?</th>
</tr>
<tr ng-repeat="student in studentData | filter: studentFilter">
<td>{{ student.name }}</td>
<td>{{ student.fails }}</td>
<td>
{{ (student.fails <=0 ) ? 'YES' : 'NO' }} </td>
</tr>
</tbody>
</table>
</div>
CONTROLLER
var app = angular.module('myApp', [])
app.controller('myCtrl', function($scope) {
$scope.studentFilter = function (item) {
if($scope.passes && $scope.fails) return item;
if($scope.passes && item.fails <= 0) return item;
if($scope.fails && item.fails > 0) return item;
};
$scope.studentData = [{
id: 1,
name: 'Nabil',
fails: 1
}, {
id: 2,
name: 'Daan',
fails: 0
}, {
id: 3,
name: 'Walter',
fails: 2
}, {
id: 4,
name: 'Magaly',
fails: 0
}, {
id: 5,
name: 'Steven',
fails: 2
}, {
id: 6,
name: 'Bill',
fails: 0
}];
});
I wouldn't use ng-if or ng-show/ng-hide for this. I'd use a filter in your in your ng-repeat expression to filter the array values.
filter UI
`<input type="checkbox" ng-model="filterObj.Failed">`
table
`ng-repeat="t in table | filter:filterObj"`
Something along those lines. Your boolean property keys are a little confusing to me but basically the filterObj keys should match with keys found on your table objects.
codepen - http://codepen.io/pen?template=zrGjgW
Instead of doing a ng-hide on each <td>, do it on tr level. Also, bind to a ng-model with your checkbox, to be able to use it:
<tr>
<td>
<span class="CheckBox">
<input type="checkbox"
ng-model="showNoFailures">Show Students with No Failures
</span>
</td>
</tr>
<tr ng-repeat="t in table"
ng-if="t.Failed === 0 || showNoFailures">
<!-- show if all passed, or the cb is checked -->
<td colspan="1">{{t.id}}</td>
<td colspan="1">{{t.Total}}</td>
<td colspan="1">{{t.Passed}}</td>
<td colspan="1">{{t.Failed}}</td>
</tr>
See this working jsfiddle

angularjs + get multiple checkbox value and attribute values

I am trying to get the multiple checkbox value and attribute values.
Each checkbox have multiple attribute values(data-id, data-ot,data-si).
How to get the checked checkbox with 3 attribute values.
<table>
<thead class="search">
<tr>
<th>
<input type="checkbox" class="selectall " ng-model="selectall" ng-click="select(data)">
</th>
</tr>
</thead>
<tbody>
<tr >
<td>
<input data-id="287" data-ot="31" data-si="541" type="checkbox" - ng-model="rowselect">
</td>
</tr>
<tr >
<td>
<input data-id="295" data-ot="331" data-si="31" type="checkbox" ng-model="rowselect">
</td>
</tr>
<tr >
<td>
<input data-id="297" data-ot="321" data-si="31" type="checkbox" ng-model="rowselect">
</td>
</tr>
<tr >
<td>
<input data-id="296" data-ot="451" data-si="671" type="checkbox" ng-model="rowselect">
</td>
</tr>
<tr >
<td>
<input data-id="293" data-ot="91" data-si="651" type="checkbox" ng-model="rowselect">
</td>
</tr>
<tr >
<td>
<input data-id="294" data-ot="13" data-si="14" type="checkbox" ng-model="rowselect">
</td>
</tr>
</tbody>
</table>
<input type="button" name="Submit" value="Submit" ng-click="ShowSelected()" />
Expected output:
For example 2 checkbox selected selected means:
[{"id":"xx","ot":"xx","si"},{"id":"xx","ot":"xx","si"},]
Code:
app.controller('MyCtrl', function($scope) {
$scope.ShowSelected = function() {
///
};
});
I don't see the point in keeping your data inside attributes like that unless that is something you specifically need for some particular reason.
The easiest way to do this is to make an object array on your scope like this:
$scope.data = [
{id: 123, ot: 234, si: 567, checked: false},
{id: 321, ot: 243, si: 789, checked: false},
{id: 345, ot: 678, si: 567, checked: false}
];
Then you can use ng-repeat to create the table and bind the checkboxes to the .checked property:
<table>
<thead>
<!-- your table header -->
</thead>
<tbody>
<tr ng-repeat="element in data">
<td>
<input type="checkbox" ng-model="element.checked">
</td>
</tr>
</tbody>
</table>
And then write the showSelected() function:
$scope.showSelected = function(){
var tempArray = [];
for(var i=0; i<data.length; i++){
if(data[i].checked) tempArray.push(data[i]);
}
return tempArray; //or maybe console.log(tempArray) or encode to JSON etc.
}
Add attribute 'checked' to your checkbox model
$scope.checkboxList = {[
{
"id": "xx",
"ot": "xx",
"checked": false
},
{
"id": "xx",
"ot": "xx",
"checked": false
}
]}
Use ng-model in your html to bind to your checked attribute
<tr ng-repeat="checkbox in checkboxList ">
<td><input type="checkbox" ng-model="checkbox.selected"></td>
<td>{{checkbox.ot}}</td>
</tr>
And in your controller you can use $filter to filter your checkboxes
app.controller('MyCtrl', function($scope, $filter) {
$scope.ShowSelected = $filter('filter')($scope.checkboxList , { $: true });
});

Angular.js - How to pass the $index to a function?

This is my structure in scope:
$scope.tables = [
{name: 'tweets',
columns: ['message', 'user'],
items: [
{message: 'hello', user: 'mike'},
{message: 'hi', user: 'bob'},
{message: 'hola', user: 'bob'}
]
},
{name: 'users',
columns: ['username'],
items: [
{username: 'mike'},
{username: 'bob'}
]
}
];
This is the "addTweet" function. Since the button that calls this function is generated from a loop, it needs to pass the $index to the function. I've tried the following but it doesn't work. The button doesn't seem to trigger anything at all. If I call the function from outside the loop though, it works.
$scope.addTweet = function(id){
$scope.tables[id].items.push({message: $scope.message, user: $scope.user});
};
<table ng-repeat="table in tables">
<form ng-submit="addTweet($index)">
<tr>
<td ng-repeat="column in table.columns">
<input type="text" ng-model="column"></input>
</td>
<td>
<button type="submit">Add Row</button>
</td>
</tr>
</form>
</table>
Don't use tag 'form' inside tag 'table' - it's incorrect html syntax.
Use this way:
<table ng-repeat="(tableIdx, table) in tables">
<tr>
<td ng-repeat="column in table.columns">
<input type="text" ng-model="column"></input>
</td>
<td>
<button type="submit" ng-click="addTweet(tableIdx)">Add Row</button>
</td>
</tr>
</table>
or this
<form ng-submit="addTweet($index)" ng-repeat="table in tables">
<table>
<tr>
<td ng-repeat="column in table.columns">
<input type="text" ng-model="column"></input>
</td>
<td>
<button type="submit">Add Row</button>
</td>
</tr>
</table>
</form>
I'm sorry. I didn't see addTweet function code. $scope.message and $scope.user properties are not initialized in your $scope, because this binding ng-model="column" refer to the $scope.table[tableId].columns[columnId]
If you want to add new item and work with dynamic model names try this:
<tr ng-init="table.newPost={}">
<td ng-repeat="column in table.columns">
<input type="text" ng-model="table.newPost[column]"></input>
</td>
<td>
<button type="submit">Add Row</button>
</td>
</tr>
And code for addTweet function:
$scope.addTweet = function(id) {
$scope.tables[id].items.push($scope.tables[id].newPost);
$scope.tables[id].newPost = {};
}

How to calculate a dynamic value with ng-repeat for a nested object property in AngularJs

I want to calculate taxes in relation with a user-input that correspond to the price.
I have no problem when I don't use ng-repeat. But I can't figure out how to make it works with ng-repeat. For information, the code below refers to an invoice controller where I add items to the invoice.
Here is what I have:
Controller
App.controller('FacturesSoloController', function($scope, $stateParams, Facture ) {
$scope.factureId = $stateParams.factureId;
Facture.get({ id: $stateParams.factureId }, function(data) {
$scope.facture = data;
$scope.ajouterItem = function(){
$scope.facture.items.push({});
}
});
$scope.calculTps = function() {
$scope.item.tps = $scope.item.prix*5/100;
};
$scope.calculTvq = function() {
$scope.item.tvq = $scope.item.prix*9.975/100;
};
$scope.calculGrandTotal = function() {
$scope.item.grandtotal = parseFloat($scope.item.prix)+parseFloat($scope.item.tps)+parseFloat($scope.item.tvq);
};
});
Here is my HTML file
<table class="table">
<thead>
<tr>
<th><strong>Description</strong></th>
<th class="text-right"><strong>Prix</strong></th>
<th class="text-right"><strong>TPS</strong></th>
<th class="text-right"><strong>TVQ</strong></th>
<th class="text-right"><strong>Grand Total</strong></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in facture.items">
<td class="bold" width="50%">
<input type="text" class="form-control" name="description" id="description" ng-model="item.description"></td>
<td class="text-right">
<input type="text" class="form-control" name="prix" id="prix" ng-model="item.prix"></td>
<td class="text-right">
<input type="text" class="form-control" name="tps" id="tps" ng-model="item.tps" value="{{calculTps()}}"></td>
<td class="text-right">
<input type="text" class="form-control" name="tvq" id="tvq" ng-model="item.tvq" value="{{calculTvq()}}"></td>
<td class="text-right">
<input type="text" class="form-control" name="grandtotal" id="grandtotal" ng-model="item.grandtotal" value="{{calculGrandTotal()}}">
</td>
</tr>
<tr>
<td class="bold"></td>
<td class="text-right"></td>
<td class="text-right"></td>
<td class="text-right"></td>
<td class="text-right">Grand Total</td>
</tr>
</tbody>
</table>
And here is what {{facture.items | json}} returns
[
{
"id": 1,
"facture_id": 10200,
"description": "Item numéro 1",
"prix": "15.00",
"tps": "0.75",
"tvq": "1.50",
"grandtotal": "17.25",
"created_at": "2015-02-21 15:07:18",
"updated_at": "2015-02-21 15:07:18"
},
{
"id": 2,
"facture_id": 10200,
"description": "Deuxième item quoi",
"prix": "135.00",
"tps": "6.75",
"tvq": "13.47",
"grandtotal": "155.22",
"created_at": "2015-02-21 15:07:18",
"updated_at": "2015-02-21 15:07:18"
}
]
So, I would like the "tps" and the "tvq" to calculate automaticly when I enter a number in the "prix" input. I wonder what is wrong.
In your javascript you still need to refer to 'item' as part of the 'facture' array. The controller doesn't know what '$scope.item' is. You can use '$index' to call a function which will do your calculations for each element in the array.
App.controller('FacturesSoloController', function($scope, $stateParams, Facture ) {
$scope.factureId = $stateParams.factureId;
Facture.get({ id: $stateParams.factureId }, function(data) {
$scope.facture = data;
$scope.ajouterItem = function(){
$scope.facture.items.push({});
}
});
$scope.calculTps = function(i) {
$scope.facture.items[i].tps = $scope.facture.items[i].prix*5/100;
};
$scope.calculTvq = function(i) {
$scope.facture.items[i].tvq = $scope.facture.items[i].prix*9.975/100;
};
$scope.calculGrandTotal = function(i) {
$scope.facture.items[i].grandtotal = parseFloat($scope.facture.items[i].prix)+parseFloat($scope.facture.items[i].tps)+parseFloat($scope.facture.items[i].tvq);
};
$scope.doCalculations = function(i) {
$scope.calculTvq(i);
$scope.calculTps(i);
$scope.calculGrandTotal(i);
}
});
and your HTML
<table class="table">
<thead>
<tr>
<th><strong>Description</strong></th>
<th class="text-right"><strong>Prix</strong></th>
<th class="text-right"><strong>TPS</strong></th>
<th class="text-right"><strong>TVQ</strong></th>
<th class="text-right"><strong>Grand Total</strong></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in facture.items">
<td class="bold" width="50%">
<input type="text" class="form-control" name="description" id="description" ng-model="item.description"></td>
<td class="text-right">
<input type="text" class="form-control" name="prix" id="prix" ng-model="item.prix" ng-change="doCalculations($index)></td>
<td class="text-right">
<input type="text" class="form-control" name="tps" id="tps" ng-model="item.tps"></td>
<td class="text-right">
<input type="text" class="form-control" name="tvq" id="tvq" ng-model="item.tvq"></td>
<td class="text-right">
<input type="text" class="form-control" name="grandtotal" id="grandtotal" ng-model="item.grandtotal">
</td>
</tr>
<tr>
<td class="bold"></td>
<td class="text-right"></td>
<td class="text-right"></td>
<td class="text-right"></td>
<td class="text-right">Grand Total</td>
</tr>
</tbody>
</table>
https://docs.angularjs.org/api/ng/directive/ngRepeat
https://docs.angularjs.org/api/ng/directive/ngChange
UPDATE:
You should also use ngChange to call both calculation functions each time the 'prix' is updated

Hiding the table columns and rows using AngularJs

I have checkboxes with table headers, i want to hide the table columns and rows based on the checkbox click,
<ul>
<li ng-repeat="opt in fieldvalues"><input type="checkbox" ng-model="checked" value="{{opt}}" />{{opt}}</li>
</ul>
<table>
<tr>
<th ng-show="checked=='true'">Activity ID</a></th>
<th>Activity Description</th>
</tr>
<tr ng-repeat="nm in makerQueueData">
<td ng-show="checked=='true'">{{nm.formattedIdentifier}}</td>
<td>{{nm.description}}</td>
</tr>
</table>
I tried but no luck.
<ul>
<li ng-repeat="opt in fieldvalues"><input type="checkbox" ng-model="checked" value="{{opt}}" />{{opt}}</li>
</ul>
<table>
<tr>
<th ng-show="checked"><a>Activity ID</a></th>
//here checked gets bool value itself based on selection. you don't need to compare it to string 'true'.
//keep in mind i assume {{checked}} returns only bool value
<th>Activity Description</th>
</tr>
<tr ng-repeat="nm in makerQueueData">
<td ng-show="checked">{{nm.formattedIdentifier}}</td>
<td>{{nm.description}}</td>
</tr>
</table>
Working fiddle for your : http://jsfiddle.net/b69pkeLd/1/
Let me know if any issue occurs.
I hope this is what you are looking for:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.fieldvalues = [
{text: 'Test1', checked: false},
{text: 'Test2', checked: false}
];
$scope.makerQueueData = [
'Whatever your', 'data is'
];
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<div ng-repeat="opt in fieldvalues">
<input type="checkbox" id="checkbox-{{$index}}" ng-model="opt.checked" value="{{opt.text}}" />
<label for="checkbox-{{$index}}">{{opt.text}}</label>
<table ng-show="opt.checked">
<tr>
<th>Activity ID</a></th>
<th>Activity Description</th>
</tr>
<tr ng-repeat="nm in makerQueueData">
<td ng-show="opt.checked'">{{$index}}</td>
<td>{{nm}}</td>
</tr>
</table>
</div>
</div>
Moreover, use <label> for type="checkbox" description. This makes the label clickable.

Resources