How to access javascript object's properties dynamically based on textbox value? - javascript

I am new to angular .I am stuck with generating or updating the table with respect to text box.
I have a schema which contains 3 fields-country,sales and profit.
There is two text box named as x and y axis.There is a table which should be generated on updating the x and y axis(text box).The should be of two columns in the table which tells what should be in x and y axis.
This is my home.component.html
<div class="form-group">
<form [formGroup]="myFormGroup">
<label>x-axis : </label>
<input type="text" class="form-control" formControlName = "xaxis" > <br>
<label>y-axis : </label>
<input type="text" class="form-control" formControlName ="yaxis" > <br>
<button class="apply-btn" (click)='apply(myFormGroup.value)'>Apply</button>
</form>
</div>
<table class="table table-hover">
<thead>
<tr>
<th>{{this.xaxis}}</th>
<th>{{this.yaxis}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor = 'let product of products' cdkDrag>
<td>{{product.xaxis}}</td> **<----Here is the problem**
<td>{{product.yaxis}}</td>
</tr>
</tbody>
</table>
This is my home.component.ts
export class HomeComponent implements OnInit{
products:any=[];
xaxis:any;
yaxis:any;
myFormGroup:FormGroup;
constructor(private service : ServiceService,private fb : FormBuilder) {
this.CreateForm();
}
//Fetching of data
refreshData(){
this.service.getAll().subscribe((res) => {
this.products=res;
})
}
CreateForm(){
this.myFormGroup=this.fb.group({
xaxis:['',Validators.required],
yaxis:['',Validators.required]
});
}
apply(formValue){
this.xaxis=formValue.xaxis;
this.yaxis=formValue.yaxis;
}
ngOnInit() {
this.refreshData();
}
}
The values should be in the text box is the attributes of schema i.e country,sales and profit.For example, when we enter country and sales for x and y axis respectively then the table should fetch the values of country and sales from the db and update the table with those values.

You can use JavaScript Square Bracket [] notation to access the product object properties dynamically. Square bracket notation accepts expressions, so you can pass the this.xaxis and this.yaxis in your product object. i.e, product[this.xaxis]
<div class="form-group">
<form [formGroup]="myFormGroup">
<label>x-axis : </label>
<input type="text" class="form-control" formControlName = "xaxis" > <br>
<label>y-axis : </label>
<input type="text" class="form-control" formControlName ="yaxis" > <br>
<button class="apply-btn" (click)='apply(myFormGroup.value)'>Apply</button>
</form>
</div>
<table class="table table-hover">
<thead>
<tr>
<th>{{this.xaxis}}</th>
<th>{{this.yaxis}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor = 'let product of products' cdkDrag>
<td>{{product[this.xaxis]}}</td>
<td>{{product[this.yaxis]}}</td>
</tr>
</tbody>
</table>

Related

Angular get value in the app component coming from a map

I tried several ways and I was unable to print the valueM, ValueR and product in my app.component.html
Can anyone give me a solution or tip for me to proceed?
thank you very much
app.component.ts
forkJoin(
this.service1.method1(filter1),
this.service2.methodo2(filter2),
).subscribe(data => {
const cc = data[0] || [];
console.log(cc);
const pp = data[1] || [];
const arrayIdsProducts = pp.map(element => element.product);
const sc = cc.filter(elemente => arrayIdsProducts.includes(elemente.product));
console.log(sc);
this.valuesC = sc.map(e => ({
valueM: e.valueM,
valueR: e.valueR,
product: e.product
}));
Console.log
[{…}] 0: codigoSistemaFormatado: "0002.0004", id: 119 product: 5, productName: "T-SHIRT XYZ BLUE XL"
[{…}] 0: product: 5, ValueM: 31.053333333333335, valorR: 49.9
app.compontent.html
<table formArrayName="productos" class="table table-bordered table-striped">
<thead>
<tr>
<th width="5%" class="text-center">ValueM</th>
<th width="30%" class="text-center">ValueR</th>
<th width="9%" class="text-center">Produte</th>
<th width="7%"></th>
</tr>
</thead>
<tr [formGroupName]="i" *ngFor="let item of formGroup.controls.produtos.controls; let i=index; last as isLast; first as isFirst">
<td>
{{i+1}}
</td>
<input hidden formControlName="unidadeNome">
<input hidden formControlName="codigoSistemaFormatado">
<input hidden formControlName="ValueM"> >
<input hidden formControlName="valueR">
<td>
<app-vo-filtro-produtos (valueSelected)="onProductChanged($event, i)" [showLabel]="false" [multiple]="false"
formControlName="produto" [itens]="produtos[i]"></app-vo-filtro-produtos>
</td>
<td>
<input type="text" value="{{produtos[i].codigoSistemaFormatado}}" class="form-control" disabled="true">
</td>
<td>
<input type="text" value="{{produtos[i].unidadePrincipal?.unidade.sigla}}" class="form-control" disabled="true">
</td>
<td>
<input type="text" value="{{valueM HERE}}" class="form-control" disabled="true">
</td>
<td>
<input type="text" value="{{valueR HERE}}" class="form-control" disabled="true">
</td>
</td>
</tr>
</table>
</form>
As you need to access valuesC value which is assigned dynamically, you should access it like:
<input type="text" [value]="valuesC.valueR" >
Update:
If I understood it correctly, you will be having separate array as valueC which will have mapping of productId values with valueR and valueC.
Then better to write separate methods in our ts file to return product specific valu from valueC array like this:
ts file:
getValue(productId, key) {
for(let product of this.valueC) {
if(productId == product.product) {
return product[key];
}
}
}
Read in html file like:
<input type="text" [value] = "getValue(<REPLCAE_WITH_PRODUCT_ID>, 'valueM')">
<input type="text" [value] = "getValue(<REPLCAE_WITH_PRODUCT_ID>, 'valueR')">

save table data angular 2 created from ngFor

I am creating an editable table from the data that I am getting from the back end now I want to save the data that has been updated.
I have tried using formControl but it only save the data that is in the last column
Here is my code
<form [formGroup]="pagesForm">
<tr *ngFor="let data of pagesArray; let i = index; trackBy: trackByFn">
<td style="text-align: center;" >
<input type="text" formControlName="nameControl" value=[data.name]>
</td>
<td style="text-align: center;">
<input type="text" formControlName="descriptionControl"
vaue=[data.description]>
</td>
</tr>
<button class="btn btn-common" (click)="submit(pagesForm)">Save</button>
</form>
Can anyone help me to save this table data in bulk
In case of reactive form, which I suggest, especially when dealing with an array... with that you need a FormArray to which you push your values when you get them from the backend.
So you can build your form:
constructor(private fb: FormBuilder) {
this.pagesForm = this.fb.group({
arr: this.fb.array([])
})
}
and when you receive your data, in the callback (subscribe or then if you are using promises) call a method, in this example setFormArray() that populates your form array:
setFormArray() {
let arr = this.pagesForm.controls.arr;
this.pagesArray.forEach(x => {
arr.push(this.fb.group({
name: x.name,
description: x.description
}))
})
}
Then you can modify your template to iterate the formarray:
<form [formGroup]="pagesForm" (ngSubmit)="submit(pagesForm.value)">
<div formArrayName="arr">
<tr *ngFor="let page of pagesForm.controls.arr.controls; let i = index"
[formGroupName]="i" >
<td>
<input type="text" formControlName="name">
</td>
<td>
<input type="text" formControlName="description">
</td>
</tr>
</div>
<button type="submit">Save</button>
</form>
Now you end up with an form object that contains property arr, which is an array of your data.
Here's a demo: http://plnkr.co/edit/zfpbUzkvMLOn8CCermGD?p=preview
Hope this helps! :)

MVC/Javascript: how to post an array of integers in a form submission?

Before doing a form submit for my MVC webpage, I want to see a list of key fields to the controller. However the parameter on the controller is null.
My JavaScript is as follows;
$("#savePropertiesToBeAssigned").click(function (e) {
e.preventDefault();
var $propertyIds = $("#propertyRows").find($(".selectProperty:checked"));
var propertyIds = [];
$.each($propertyIds, function () {
var propertyId = $(this).data("msurvey-property-id");
propertyIds.push(propertyId);
});
var $form = $(this).closest("form")[0];
$form.action += "?PropertyIds=" + propertyIds + "&page=" + GetHiddenField("msurvey-page");
$form.submit();
});
The MVC Action is;
[HttpPost]
public async Task<ActionResult> AddFromContract(int[] PropertyIds, int? page)
{
var pageNumber = page.GetValueOrDefault(1);
return RedirectToAction("AddFromContract", new { page = pageNumber });
}
The PropertyIds comes through wrongly as null, whilst the page has the correct value.
EDIT - I am displaying the View in response to a comment:
#{
ViewBag.Title = "Add properties from the contract into the survey";
}
#using (Html.BeginForm("AddFromContract", "PropertySurvey", FormMethod.Post))
{
<div id="hiddenFields"
data-msurvey-page="#ViewBag.Page"></div>
<input type="hidden" id="propertyIds" name="propertyIds" />
<fieldset>
<legend>#ViewBag.Title</legend>
#if (ViewBag.PagedList.Count > 0)
{
<section id="PropertyList" style="margin-right: 28px;">
<p>
The properties below have already been added to the contract <b>#SessionObjectsMSurvey.SelectedContract.ContractTitle</b>, but are NOT in this survey
<b>#SessionObjectsMSurvey.SelectedContract.SurveyTitle.</b>
</p>
<table class="GridTbl">
<thead>
<tr>
<th>UPRN</th>
<th>Block UPRN</th>
<th>Address</th>
<th style="text-align: center;">
Select All<br/>
<input type="checkbox" id="selectAll"/>
</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3" style="text-align: right;">Select the properties you want to include in the survey, and click on the Save button.</td>
<td style="text-align: center;">
<button id="savePropertiesToBeAssigned" class="btn-mulalley">
Save
</button>
</td>
</tr>
</tfoot>
<tbody id="propertyRows">
#foreach (var property in ViewBag.PagedList)
{
<tr>
<td>#property.UPRN</td>
<td>#property.BlockUPRN</td>
<td>#property.Address</td>
<td style="text-align: center;">
<input type="checkbox"
name="selectProperty"
class="selectProperty"
data-msurvey-property-id="#property.PropertyId"/>
</td>
</tr>
}
</tbody>
</table>
#Html.PagedListPager((IPagedList) ViewBag.PagedList, page => Url.Action("AddFromContract", new {page}))
</section>
}
else
{
<p>Either no properties have been entered, or all of them have been assigned to the survey.</p>
}
</fieldset>
}
#section scripts
{
#Scripts.Render("~/bundles/page/propertyTransfer")
}
There is no need for any javascript to solve this. You already have checkbox elements in you form, and if they have the correct name and value attributes, they will bind to your model in the POST method.
Delete the <input type="hidden" id="propertyIds" name="propertyIds" /> and change the the view to
#foreach (var property in ViewBag.PagedList)
{
<tr>
<td>#property.UPRN</td>
....
<td style="text-align: center;">
<input type="checkbox" name="propertyIds" value="#property.PropertyId" />
</td>
</tr>
}
and delete the script.
When the form submits, the value of all checked checkboxes will be sent to the controller, and because the checkbox has name="propertyIds" they will bind to your int[] PropertyIds in the POST method.
You will also need to change <div id="hiddenFields" data-msurvey-page="#ViewBag.Page"></div> to
<input type="hidden" name="page" value="#ViewBag.Page" />
Side note: I recommend you start using view models rather that using ViewBag, including a view model for the collection, which would contain properties int ID and bool IsSelected so that you can strongly type your view to your model.

Knockout Validation - Validation not binding to correct instance of object

I'm using knockout-validation and am having a problem with the error messages not showing correctly after changing what observable an input field is bound to.
I have the following html
<div id="editSection" data-bind="if: selectedItem">
<div>
<label>First Name</label>
<input data-bind="value:selectedItem().FirstName" />
</div>
<div>
<label>Last Name</label>
<input data-bind="value:selectedItem().LastName" />
</div>
</div>
<br/>
<table data-bind='if: gridItems().length > 0'>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody data-bind='foreach: gridItems'>
<tr>
<td data-bind='text: FirstName' ></td>
<td data-bind='text: LastName' ></td>
<td><a href='#' data-bind='click: $root.editItem'>Edit</a></td>
</tr>
</tbody>
</table>
And JavaScript
var lineViewModel = function(first, last) {
this.FirstName = ko.observable(first).extend({required:true});
this.LastName = ko.observable(last).extend({required: true});
this.errors = ko.validation.group(this);
}
var mainViewModel = function() {
this.gridItems = ko.observableArray();
this.gridItems([new lineViewModel('first1'), new lineViewModel(null,'last2')]);
this.selectedItem = ko.observable();
this.editItem = function(item){
if (this.selectedItem()) {
if (this.selectedItem().errors().length) {
alert('setting error messages')
this.selectedItem().errors.showAllMessages(true);
}
else{
this.selectedItem(item)
}
}
else
this.selectedItem(item)
}.bind(this)
}
ko.applyBindings(new mainViewModel());
Reproduce
Use this JSFiddle
Click Edit on the first line
Click Edit on the second line - You will be alerted of validation
message being shown and then it will show
Fill out required field
Click Edit on the second line again - You will see "First Name" go
blank and "Last Name" change to "last2"
Click Edit on the first line - You will be alerted of validation
message being shown, BUT it's not show (BUG)
Should I take another approach to this or should I do something different with the way that I am using ko.validation.group?
The validation is fine... your edit section has problems.
Use the with binding. Never use someObservable().someObservableProperty in a binding, it will not work like you might expect it. You should change the binding context.
<div id="editSection" data-bind="with: selectedItem">
<div>
<label>First Name</label>
<input data-bind="value: FirstName" />
</div>
<div>
<label>Last Name</label>
<input data-bind="value: LastName" />
</div>
</div>

Sending HTML table data to a form

I have the table in the below format.
FirstName Last Name
Jill Smith
Eve Jackson
Also i have Form for updating the firstname & lastname. This is the form code.
<!DOCTYPE html>
<html>
<body>
<form border="1">
<tr>
<td><label >FirtsName</label></td>
<td><input type="text" id="firstname" class="medium"></td>
</tr>
<tr>
<td><label >LastName</label></td>
<td><input type="text" id="lastname" class="medium"></td>
</tr>
</form>
</body>
</html>
How to send the table data to a form using jquery or javascript. Any help will be much appreciated!
Thanks & regards
Karthick
I'm not an expert in js, but you could submit the form each time the input looses the focus
Use <form name="myform" border="1">
and :
<input type="text" id="firstname" class="medium" onBlur="document.forms["myform"].submit()">
there's probably better ways to do this but here's just an idea...
-- Edit : --
sorry i forgot something important : you have to name your form like this :
<form name="myform" action="file.php">
I'm not very good in english, so maybe I don't understand well enough, but to do what you want, I would do like this :
First things first, you should improve your HTML code, this will make the job a lot easier :
In your users table :
<table> </table>: add an id to handle it more easly with jQuery : $('#id') method
ex: <table id="users"></table>
<thead><tr><th> </th></tr></thead><tbody> </tbody>: use this markups allow you to distinguish table header from table content
<tr> </tr>: add an id on the server side to know who is who (i.e : if you have two John Smith)
ex: <tr id="name_01"><td>...</td></tr>
<td> </td>: add a class attribute to know where is the firstname and the last name
ex: <td class="firstname">...</td><td class="lastname"></td>
In your form :
<form> </form>: add an id to grab it more easly too
ex: <form id="usersform"></form>
<table> </table> : don't forget the <table> markup !
<label> </label>: add the for attribute matching the input id
ex: <label for="firstname" >FirtsName</label>
Now, your table should look like this :
<table id="users">
<thead>
<tr>
<th>Firstname</th><th>Last Name</th>
</tr>
</thead>
<tbody>
<tr id="name_01">
<td class="firstname">Jill</td><td class="lastname">Smith</td>
</tr>
<tr id="name_02">
<td class="firstname">Eve</td><td class="lastname">Jackson</td>
</tr>
</tbody>
</table>
There are several ways for make what you want, but, basically, there is two main ways :
Have only one of the table entry in the form at a time
Have all of the table entries
I - Only one table entry at a time
HTML
<form id="usersform" name="usersedit" >
<table id="users">
<tr>
<td><label for="firstname" >FirtsName</label></td>
<td><input type="text" id="firstname" class="medium"></td>
</tr>
<tr>
<td><label for="lastname" >LastName</label></td>
<td><input type="text" id="lastname" class="medium"></td>
</tr>
</table>
</form>
jQuery :
//When there is a click on a line of the table
$('#users tbody tr').click(function(e) {
//Get the <tr> id
userid = $(this).attr('id');
//Put the value of the firstname cell in the firstname input
$('#usersform input#firstname').val($(this).find('td.firstname').html());
//You can add a name attribute or an id for later works
$('#usersform input#firstname').attr('name','first'+userid);
//Now for the lastname input
$('#usersform input#lastname').val($(this).find('td.lastname').html()).attr('name','first'+userid);
}
II - All table entries
HTML
<form id="usersform" name="usersedit" >
<table id="users">
<thead>
<tr>
<th>Firstname</th><th>Last Name</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</form>
jQuery :
//When there is a click on the table (#users) :
$.('#users').click(function(e){
//handle the part of the form where we want to add input field
myformtable = $('#userform table tbody');
//For each row in the table
$.('#users tbody tr').each(function(e) {
//Create and append a new line
userline = $(document.createElement('tr'));
userline.appendTo(myformtable);
//Create and append a firstname cell
tdfirstname = $(document.createElement('td')).addClass('firstname');
tdfirstname.appendTo(userline);
//Create and append a firstname input
firstname = $(document.createElement('input')).addClass('medium');
firstname.appendTo(tdfirstname);
//Add attribute
firstname.attr({type: 'text', name: 'first'+$(this).attr('id')});
//Set value
firstname.val($(this).find('.firstname').html());
//Same things with the lastname
tdlastname = $(document.createElement('td')).addClass('lastname');
tdfirstname.after(tdlastname);
lastname = $(document.createElement('input')).addClass('medium');
lastname.appendTo(tdlastname);
lastname.attr({type: 'text', name: 'last'+$(this).attr('id')});
lastname.val($(this).find('.lastname').html());
}
}
You can improve it with a loop, or use css pseudo-class to handle your table cells or form inputs, but I thought it was easier to understand this way.

Categories