Update model based on ng-repeat of array - javascript

Sorry if you find this question's solution is simple or silly.
Need suggestions or solution on this angular part.
I have an object containing array("value"), as shown below.
scope.resp.DefaultData.graphRowData = [
{YName:"Mary", value:[1,4], points:1},
{YName:"Tom", value:[2,5], points:1}
];
My Code viewer uses this style to render the array.
<table>
<tbody>
<tr ng-repeat="rowLabels in resp.DefaultData.graphRowData track by $index">
<th>
<input type="text" value="{{rowLabels.YName}}" ng-model="rowLabels.YName"/>
</th>
<td ng-repeat="value in rowLabels.value track by $index">
<input type="text" ng-model="value"/>
</td>
</tr>
</tbody>
</table>
The html viewer would render like below way:
<table>
<tbody>
<th>Mary</th><td>1</td><td>4</td>
<th>Tom</th><td>2</td><td>5</td>
</tbody>
</table>
Now to my question:
The table displays the data as per the model but if i try to update the table with custom or edit the values, doesn't update the model and the value remains same
For example: Mary has two tags of 1 and 4 values, if I try to change the 1 to 2 and 4 to 5, the data inside the model remains same without update.
Is there any way to fix in my code or should I change the array into array of objects like below
value:[{val:1},{val:4}]
and so ... for other objects under resp.DefaultData.graphRowData? Then it would work fine. Just confused why for array not working in angular js in my code! :(

You need to pass a reference of array instead of value in ng-model
<tr ng-repeat="rowLabels in resp.DefaultData.graphRowData track by $index">
<th>
<input type="text" value="{{rowLabels.YName}}" ng-model="rowLabels.YName"/>
</th>
<td ng-repeat="value in rowLabels.value track by $index">
<input type="text" ng-model="rowLabels.value[$index]"/>
</td>
</tr>
check this working plunker

Related

hide an item in the parent based on the data in the child loop in Angular

I have the following HTML code snippet where i am looping through my json response to display the data. It is a nested loop with *ngIf as in the HMTL below. What i need is based on the value of one of the items in the child loop i want to hide/show an item in the parent loop.
Basically i have mtr.eu inside the child loop which is an input type.Initially it will be empty and when the user enter any value in it, i want to show the item in the parent shown below. What would be the best suitable way to achieve this.
<div class="row accordian-head" accordion-heading>
<span class="w20">MPRN: {{header.gpr}}</span>
<span class="w20">Meter ID: {{header.num}}</span>
<span class="w20" *ngIf="mtr.eu">New data added</span>
</div>
<div class="accordian-inner-content">
<table class="table table-borderless">
<thead>
<tr class="meter-reading-header">
<th scope="col">Last read date</th>
<th scope="col">Last meter read</th>
<th scope="col">New reading (kWh)</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let mtr of header.mtrs" class="meter-reading-content">
<td>{{mtr.lrd}}</td>
<td>{{mtr.lrv}}</td>
<td>
<input type="number" name="newReading" class="form-control new-reading-input"
placeholder="eg. 12345" [(ngModel)]="mtr.eu">
</td>
</tr>
</tbody>
</table>
</div>
</accordion-group>
You can not use the child variables in the parent node. Instead, you can make a getter where you can check the records which has mu value. based on that getter value you can show the record on the parent element.
The only thing you need to do is write a function and pass your list of items into it. inside that use filter to check for required data(in your case its mt.mu). then return the data. Based on returned data you can show the element.
But when you call any function from the template it calls the function recursively.
So as a best practice I would prefer using pipes to do the same logic. Which makes my code much better.
I hope this helps you to achieve your need.

Regarding AngularJS and datatable combination

First and foremost, hello! I'm new here.
I've been recently learning AngularJS and web development as I'm working so I apologize for my newbieness. I had stumbled upon a wall of sorts regarding datatable integration with AngularJS. Here's the structure of it:
<table class="datatable table table-hover">
<thead>
<tr>
<th ng-repeat="column in columns">
{{column.name}}
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="form in forms | filter : {userName : activeFilter['user name']|rangeDate:activeFilter['range begin']:activeFilter['range end']:'birthDate'">
<td class="row-md-1">
<span ng-model="approvedForm.userName">
{{approvedForm.userName}}
</span>
</td>
<td class="row-md-1">
<span ng-model="approvedForm.birthDate">
{{approvedForm.birthDate}}
</span>
</td>
</tr>
</tbody>
</table>
I've to mention I make use of the filters on the client side, so they can choose the correct rows. The problem was that upon filtering some users and row-sorting with datatable, the data would get misteriously duplicated on the view, and I couldn't delete it or whatsoever. To solve it I had to take out the ng-repeat filters and filter with datatable filter support. Does anybody know what might have caused this behaviour?
Btw I'm using angularJS 1.x and datatable 1.10
Thanks!
Your data is duplicating because you bind it twice as the attribute of the HTML element and with handlebars. Remove either ng-model="..." attribute or {{...}} in your code so it would look like this:
<span>
{{approvedForm.userName}}
</span>
as #Shaishab Roy mentioned ng-model is not supposed to work with <span> so try ng-bind instead:
<span ng-bind="approvedForm.userName"></span>

Trying to invert a table in HTML

I am currently trying to invert a table consisting of the following code:
<table>
<tr ng-repeat="x in dataStuff.data track by $index">
<td ng-repeat="y in x track by $index">
y: {{y}}
</td>
</tr>
</table>
I cannot figure out if there is a simple way to invert this table, or if I will have to write a function in JavaScript to rearrange the data.
If you only want that one condition displayed simplest is to just reverse the array in controller before passing to view using Array.prototype.reverse()
$scope.dataStuff.data.reverse()

How to make an Add/Remove Array of strings in AngularJS

I need to make a data binding to an array of strings.. I need an array of directions.
I module it this way:
JS
function ShoppingCartCtrl($scope) {
$scope.directions = ["a", "b", "c"];
$scope.addItem = function (item) {
$scope.directions.push(item);
$scope.item = "";
};
$scope.removeItem = function (index) {
$scope.directions.splice(index, 1);
};
}
HTML
<div ng-app>
<div ng-controller="ShoppingCartCtrl">
<br />
<table border="1">
<thead>
<tr>
<td>directions</td>
<td>Remove Item</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in directions">
<td>
<input ng-model="item" />{{$index}}
</td>
<td>
<input type="button" value="Remove" ng-click="removeItem($index)" />
</td>
</tr>
</tbody>
</table>
<br />
<table>
<tr>
<td>
<input type="text" ng-model="item" />
</td>
<td colspan="2">
<input type="Button" value="Add" ng-click="addItem(item)" />
</td>
</tr>
<tr>
<td>{{directions}}</td>
</tr>
</table>
</div>
</div>
Everything works as it was expected, but I have a bug that I can't find. When you try to modified the values directly from the inputs, you are not allow. You write and nothing happened (THIS WAS SOLVED WITH PUTTING THE LAST VERSION OF ANGULAR IN JSFIDDLE).
Continue: Now you can modify the values, but they are not updated in the model. If anyone can help me, it would be awesome!!
You can see it working in this jsfiddle
Solution #1: bind an object's property instead of a string
You shouldn't edit item directly, but instead update an attribute of item.
See a working example here: http://jsfiddle.net/ray3whm2/15/
If you want more information you should read this article: http://nathanleclaire.com/blog/2014/04/19/5-angularjs-antipatterns-and-pitfalls/
Basically, never bind a property by itself, instead always have a dot in your bindings, i.e. item.name instead of item. This is a restriction due to javascript itself and not angularjs.
Solution #2: manually update your model
If you really need to, you can actually keep your array up to date manually by using the ng-change directive. See a working example here: http://jsfiddle.net/ray3whm2/16/
There was a problem with older versions of Angular when binding to primitives. See this SO question
So first update the version to a newer version of Angular.
ng-repeat creates a child scope. Because your item in ng-repeat="item in directions" is a primitive (i.e. a string), <input ng-model="item"> modifies the child scope. That's why you won't see the changes in the parent.
One way to address it is to create an array of objects instead of strings for this to work properly:
$scope.directions = [{d: "a"}, {d: "b"}, {d: "c"}];
Then your <input> would be:
<input ng-model="item.d" />
(Another way, I thought, would be to use ng-model=directions[$index], but for some reason it would lose focus after every keypress.
UPDATE: #PSL showed that this could work if you add track by $index)

Get key values and create a table header

I have an angularjs application that basically takes JSON and creates a HTML table, with the keys in the <thead> and the values as table rows.
I have a JSFiddle here where I take the JSON and create table rows based on the values. But I can't figure out how to take the keys and align them with the values as table headers.
My angular code:
<tr ng-repeat='row in rows'>
<td ng-repeat="data in row.data">
{{data}}
</td>
</tr>
and:
function TableController($scope){
$scope.rows = data;
}
Take a look here: How can I iterate over the keys, value in ng-repeat in angular
<tr ng-repeat="(key, value) in data">
<td> {{key}} </td> <td> {{ value }} </td>
</tr>
====EDIT==== Since you're doing it all in the same table, you'll need to do it a different way. You need to separate the header values while you're still in the controller so that you have a clean way to iterate over your list. Here the fiddle: http://jsfiddle.net/L93v5/1/
Your revised way looks bad because there are two different tables and the cell sizes are different. This will keep it all in the same table and make things a bit cleaner.

Categories