Angular 2, get edited data from HTML table - javascript

Our angular 2 application has a html table, that displays data from the database. Now we need to make few items editable in the table. I have made the needed items editable and added the button update, when clicked on the update button I need to get the edited value of the row along with the id of the row.
Please help me how to achieve it. Given below is my code.
<tr *ngFor="let row of tableData;">
<td >{{ row.id}}</td>
<td contenteditable="true">{{ row.editableData1 }}</td>
<td contenteditable="true">{{ row.editableData2}}</td>
<td style="color: black;">{{ row.user }}</td>
<td class="link">
<button (click)="updatetoDB()" type="button"> Update </button>
</td>
</tr>
So When user clicks on the Update Button, I need to get the edited data and the id of the row. Thank you in Advance :)

#data1 method maybe not work because td element does not have value attribute.
Can you try to add an input element into your td like this :
<tr *ngFor="let row of tableData;">
<td >{{ row.id}}</td>
<td contenteditable="true"><input type="text" [value]="row.editableData1" #data1/></td>
<td contenteditable="true"><input type="text" [value]="row.editableData2" #data2/></td>
<td style="color: black;">{{ row.user }}</td>
<td class="link">
<button (click)="updatetoDB(data1, data2, row.id)" type="button">Update</button>
</td>
</tr>
I think it should be working, but you habe to include an input element into your td.
It's annoying ?

Hi,
The best solution is to use reactive form.
But i think you can name the edited data and pass it to your fonction updateToDB like this :
<tr *ngFor="let row of tableData;">
<td >{{ row.id}}</td>
<td contenteditable="true" #data1>{{ row.editableData1 }}</td>
<td contenteditable="true" #data2>{{ row.editableData2}}</td>
<td style="color: black;">{{ row.user }}</td>
<td class="link">
<button (click)="updatetoDB(data1, data2, row.id)" type="button"> Update </button>
</td>
</tr>
Log the content of data1 ans data2 variables, i think tour data should be in data1.value ans data2.value.
Hope that help you.

Related

How can I create expand/collapse function for each row of table? Angular6

So I need to be able to expand some details on each row of a table. Right now I'm having two issues:
Clicking the expand/collapse toggle will trigger the action for every row in the table.
The first row always puts the details above it.
Here's the code segment:
<tbody>
<tr *ngFor="let client of clients">
<td class="details-control">
<a class="btn btn-link" (click)="collapsed1=!collapsed1">
<i class="material-icons">
expand_more
</i>
</a>
</td>
<td>{{client.firstName}}</td>
<td>{{client.lastName}}</td>
<td>{{client.company}}</td>
<td><input type="checkbox"></td>
</tr>
<div *ngIf="!collapsed1">
<p>Details</p>
</div>
</tbody>
And what it looks like:
Toggling
Also I had my *ngFor statement in the tag earlier but I realized I can't hit individual client objects if I build a separate for details.
Let me know how I can improve!
It's a very common pattern.
The best and quick solution is to use some ID instead of just a boolean in your collapsed1 variable.
<tbody>
<tr *ngFor="let client of clients">
<td class="details-control">
<a class="btn btn-link" (click)="collapsed1 = collapsed1 ? 0 : client.id ">
<i class="material-icons">
expand_more
</i>
</a>
</td>
<td>{{client.firstName}}</td>
<td>{{client.lastName}}</td>
<td>{{client.company}}</td>
<td><input type="checkbox"></td>
<div *ngIf="collapsed1=client.id">
<p>Details</p>
</div>
You need a boolean array collapsed[] and use index in your ngFor, so you can use collapsed[i]. Take a look here for using index in ngFor:
ngFor using Index
Let me know if you need more info. Wellcome
Nevermind, here is the code that solved it.
<tbody>
<tr *ngFor="let client of clients; let i = index">
<td class="details-control">
<a class="btn btn-link" (click)="client.hideme=!client.hideme">
<i class="material-icons" *ngIf="!client.hideme">
expand_more
</i>
<i class="material-icons" *ngIf="client.hideme">
expand_less
</i>
</a>
</td>
<td width="30%">{{client.firstName}}
<tr *ngIf="client.hideme">
<td>Hey, I'm a bunch of details!</td>
</tr>
</td>
<td>{{client.lastName}}</td>
<td>{{client.company}}
<tr *ngIf="client.hideme">
<td>More Issuer details</td>
</tr>
</td>
<td><input type="checkbox"></td>
</tr>
</tbody>

How to locate and click an ng-click button in a repeater

I need to test an AngularJS web page using Selenium WebDriver and Protractor.
HTML snippet to be tested:
<tr ng-repeat="item in items" class="ng-scope">
<td class="ng-binding">
Item1
</td>
<td class="ng-binding">
description
</td>
<td class="ng-binding">
1234
</td>
<td>
<div ng-click="AddItem(item.id)" class="btn">Add Item</div>
</td>
</tr>
<tr ng-repeat="item in items" class="ng-scope">
<td class="ng-binding">
Item2
</td>
<td class="ng-binding">
description
</td>
<td class="ng-binding">
1235
</td>
<td>
<div ng-click="AddItem(item.id)" class="btn">Add Item</div>
</td>
</tr>
it looks like this:
screenshot of the html angular page
I already went through the documentation, tutorials on youtube and googled it but I still don't understand how to locate and click "Add Item" for a specific item with a specific item id.
can you please explain to me how it's done?
The specific id you are looking for wont be in the DOM, which means you cannot locate an element using that approach.
The following is the code which i personally use:
element.all(by.repeater('item in items')).filter(function(row){
return row.all(by.tagName('td')).first().getText().then(function(val){
return val === "Item1" //this can be your per your wish
})
}).first().$('[ng-click="AddItem(item.id)"]').click();
In addition to #Danny's answer,it is possible to find the item.id from the DOM using evaluate() method.Try the below code.
element.all(by.repeater('item in items')).filter(function(row){
return row.evaluate('item.id').then(function(id){
return val === "1234";
})
}).first().$('.btn').click();
Source: http://www.protractortest.org/#/api?view=ElementArrayFinder.prototype.evaluate

How to compare value of property in vue.js

I want to use the if-directive in vue.js to determine which datafield should be shown in each table row:
<tr v-repeat="model">
<td>#{{ title }}</td>
<td>#{{ publish_date_start }}</td>
<td v-if="model.publish = 1"><span class="fa fa-check"></span></td>
<td v-if="model.publish = 0"><span class="fa fa-remove"></span></td>
<td class="data-list-action">edit</td>
<td class="data-list-action">delete</td>
</tr>
If the value of the property 'publish' is 1, the datafield with the check has to be shown. If 0, it has to be the a cross.
How can I compare 'model.publish' to a value?
UPDATE: Fiddle
Try with v-if:
<td v-if="publish"><span class="fa fa-check">Check</span></td>
<td v-if="!publish"><span class="fa fa-remove">Cross</span></td>
Fiddle: http://jsfiddle.net/8wy7w560/3/

Radio button is selecting wrongly from data list in angular js and dynamic validation

I have data list which will display in the form of multiple radio buttons . each row will have 3 fields .
ex: row1:abc , 123 , xyz
row2: xyz , 145 , xyz
now when i select radio button in first row it is selecting second row . How to make that radio row unique ?
<label ng-repeat="list in data">
<table>
<tr
<td rowspan="2" >
<input type="radio" name="select" />
</td>
<td>
{{list.name}}
</td>
<td>
{{list.number}}
</td>
</tr>
<tr>
<td>
{{list.value}}
</td>
</tr>
</table>
Also how do I validate these fields , if they are comming as null I have display error message since it is dynamic data and this page is read only page .
Thanks in advance
For the null validation you can use a conditional in a ng-bind directive and for selecting different values you need a different name for each row
<label ng-repeat="list in data">
<table>
<tr
<td rowspan="2" >
<input type="radio" ng-attr-name="{{'select' + list.number}}" />
</td>
<td ng-bind="{{list ? list.number: 'error name'}}">
</td>
<td ng-bind="{{list ? list.number: 'error number'}}">
</td>
</tr>
<tr>
<td ng-bind="{{list ? list.value : 'error value'}}">
</td>
</tr>
</table>
I'm not sure if the ng-attr-name will work :( please let me know if this works
In html
<table>
<tr ng-repeat="data in list">
<td>
<input type="radio" ng-model="val.value" value="{{$index}}">
</td>
<td>
<span ng-show="data.name">{{data.name}}</span>
<span ng-hide="data.name">Error in name</span>
</td>
<td>
<span ng-show="data.number">{{data.number}}</span>
<span ng-hide="data.name">Error in number</span>
</td>
</tr>
</table>
In controller
$scope.val ={} // take this object this will store current row number
//$scope.val.value // contain row number
var data = $scope.list[$scope.val.value] // this will give u data at that row

Simple jQuery selector isn't working

I'm trying to parse this HTML:
<tr id="a">
<td class="classA">
<span class="classB">Toronto</span>
</td>
<td class="classC">
<span class="classD">Winnipeg</span>
</td>
</tr>
<tr id="b">
<td class="classA">
<span class="classB">Montreal</span>
</td>
<td class="classC">
<span class="classD">Calgary</span>
</td>
</tr>
I have a variable team. I want to find the <span> that contains team. Then I want to navigate up to the <tr> and pull the id from it.
I tried:
var team = "Toronto";
var id = $("span:contains(" + team + ")").parent().parent().attr('id');
But it comes back undefined. I know the selector is right, because $("span:contains(" + team + ")").attr('class') comes back with classB. So I can't figure out what's wrong with my query. Can anyone help?
Edit: Here's the JSFiddle.
Your html is invalid but your selector is correct, you need to put tr in table tag for valid html. You better use closest("tr") instead of .parent().parent()
Live Demo
<table>
<tr id="a">
<td class="classA"> <span class="classB">Toronto</span>
</td>
<td class="classC"> <span class="classD">Winnipeg</span>
</td>
</tr>
<tr id="b">
<td class="classA"> <span class="classB">Montreal</span>
</td>
<td class="classC"> <span class="classD">Calgary</span>
</td>
</tr>
</table>
It's not working becuase the browser's automatically fixing your HTML. You can't have a TR without a table so it's just throwing it away. All that's actually part of the DOM by the time your JavaScript runs is the spans.
Wrap it in a <table> and your code will work. Even better wrap it in <table><tbody> because the browser will still be making a tbody for you with just a table & that might cause confusion next (If you look at the parent of the TR).
Currently your HTML markup is invalid, you need to wrap <tr> element inside <table>:
<table>
<tr id="a">
<td class="classA"> <span class="classB">Toronto</span>
</td>
<td class="classC"> <span class="classD">Winnipeg</span>
</td>
</tr>
<tr id="b">
<td class="classA"> <span class="classB">Montreal</span>
</td>
<td class="classC"> <span class="classD">Calgary</span>
</td>
</tr>
</table>
Also, it's better to use .closest() as well as .prop() instead of .parent() and .attr()
var id = $("span:contains(" + team + ")").closest('tr').prop('id');
Fiddle Demo
try:
var id = $("span:contains(" + team + ")").parent('td').parent('tr').attr('id');
Your code works good.Just wrap your code into <table></table>
HTML
<table>
<tr id="a">
<td class="classA">
<span class="classB">Toronto</span>
</td>
<td class="classC">
<span class="classD">Winnipeg</span>
</td>
</tr>
<tr id="b">
<td class="classA">
<span class="classB">Montreal</span>
</td>
<td class="classC">
<span class="classD">Calgary</span>
</td>
</tr>
</table>
Script
var team = "Toronto";
var id = $("span:contains(" + team + ")").closest('tr').prop('id');
console.log(id)
http://jsfiddle.net/7Eh7L/
Better use closest()
$("span:contains(" + team + ")").closest('tr').prop('id');

Categories

Resources