how to fetch array of input values from html to JS - javascript

I have posted the same question on salesforce.stackexchange.com below is the link
https://salesforce.stackexchange.com/questions/283596/how-to-fetch-input-field-value-in-js-in-lwc?noredirect=1#comment426016_283596
But in the comments people suggested this is not much related to salesforce it is more of a Javascript thing so I am posting the same here, please take a look and suggest from html and js point of view.
HTML syntax seem different as it is lightning web component of salesoforce not angular, and also please help me to understand the same behavior in angular and I will do it in salesforce accordingly
in the below html code I am iterating 2 lists linItemData(11 records) and studyData(20 records)
<table class="slds-table slds-table_cell-buffer slds-table_bordered">
<thead>
<tr class="slds-line-height_reset">
<template if:true={studyData}>
<template for:each={studyData} for:item="sData">
<th key={sData}>
<div class="tablename slds-p-bottom_medium"></div>{sData.Visit_Name__c}
</th>
</template>
</template>
</tr>
</thead>
<tbody>
<template if:true={lineItemData}>
<template for:each={lineItemData} for:item="sLineItem">
<tr key={sLineItem}>
<template for:each={studyData} for:item="sData">
<td key={sData.Id}>
<lightning-input variant="label-hidden" class="fieldSize" type="number" step="0.01"
label="visitValue" data-key={sData.Id} onchange={visitValueChange} placeholder="00.00">
</lightning-input>
</td>
</template>
</tr>
</template>
</template>
</tbody>
</table>
and I am getting an expected result with all the required input fields on the UI like below:
now I need to fetch the input value for all v20s for example for v1 (first column name)should have array of 11 input records.
JS is as below:
visitValueChange(event) {
this.studyData
.find(item => item.Id === event.currentTarget.dataset.key)
.visitValue = event.target.value;
}
I have tried everything I could but the visitValue can hold only the 1 recent value for example if I add 1 on first input field, two on 2nd, three on 3rd and so on after that I hit a button which is calling a JS function to see the studyData array but it has only the recent value which is 3 not all 1,2 and 3 values entered and the requirement is to have an array of all the input values added on all the 11 input fileds for all the columns.
Please help me to suggest any workaround for the same.

You have two issues:
The way your data is designed
Linking the input with the correct record
Data model
Depending on your context, you could say that:
Each line is a record with columns being attributes of record (col1, col2, ...)
Each column is a record with lines being attributes of record (row1, row2, ...)
Each cell is a record identified with an id like x_y (1_1, 1_2, ...)
I would probably recommend option 1 as it's the most common representation.
This means you have to prepare / create records like this:
const myRecords = [
{
id: 1,
col1: 0,
col2: 0,
...
}, {
id: 2,
col1: 0,
col2: 0,
...
}
]
Linking input to correct record
Use LWC datatabel to create your table. You can then get what you need using custom data types. This would allow to use properly designed records (one by line and each columns is an attribute) without any transformation.
Display using the provided HTML
Unfortunatly there are some limits in Salesforce (with the HTML you provided) so you need to transform your records into this.
const myRecords = [
{
id: 1,
columns: [
{ id: 1, value: 0 },
{ id: 2, value: 0 }
...
]
}, {
id: 2,
columns: [
{ id: 1, value: 0 },
{ id: 2, value: 0 }
...
]
}
]
This will allow this to work
import {
LightningElement,
track
} from 'lwc';
export default class App extends LightningElement {
columns = [{
id: '1',
name: 'v1'
},
{
id: '2',
name: 'v2'
},
{
id: '3',
name: 'v3'
},
{
id: '4',
name: 'v4'
},
{
id: '5',
name: 'v5'
},
]
records = [{
id: '1',
columns: [{
id: '1',
value: 0
},
{
id: '2',
value: 0
},
{
id: '3',
value: 0
},
{
id: '4',
value: 0
},
{
id: '5',
value: 0
},
]
},
{
id: '2',
columns: [{
id: '1',
value: 0
},
{
id: '2',
value: 0
},
{
id: '3',
value: 0
},
{
id: '4',
value: 0
},
{
id: '5',
value: 0
},
]
}
]
visitValueChange(event) {
const recordId = event.target.dataset.recordId
const columnId = event.target.dataset.columnId
const value = event.target.value
const record = this.records.find(record => record.id === recordId)
const column = record.columns.find(column => column.id === columnId)
column.value = value
}
}
<template>
<table class="slds-table slds-table_cell-buffer slds-table_bordered">
<thead>
<tr class="slds-line-height_reset">
<template for:each={columns} for:item="column">
<th key={column.id}>{column.name}</th>
</template>
</tr>
</thead>
<tbody>
<template for:each={records} for:item="record">
<tr key={record.id}>
<template for:each={record.columns} for:item="column">
<td key={column.id}>
<lightning-input
variant="label-hidden"
class="fieldSize"
type="number"
step="0.01"
label="visitValue"
value={column.value}
data-record-id={record.id}
data-column-id={column.id}
onchange={visitValueChange}
placeholder="00.00"
></lightning-input>
</td>
</template>
</tr>
</template>
</tbody>
</table>
</template>

Related

Getting list of ids of enabled checkboxes angular

I have a table in which I have particular column as checkboxes. I have assigned a empty list. So what I want is that I want the ids of the rows of the enabled checkboxes. Say for example if the checkboxes are enabled in id 4 and 5 then the list should be [4,5]
Sample data:
{ id:1,
name: "A",
qty: 6,
value: 10
},
{ id:2,
name: "B",
qty: 4,
value: 10
},
{ id:3,
name: "C",
qty: 1,
value: 10
}
Getting data from service:
ngOnInit(): void {
this.dataService.getData().subscribe(res => {
this.listes = res;
});
}
List name:
checkboxselectlist: any[];
My stackblitz: https://stackblitz.com/edit/angular-ivy-4vnwed?file=src%2Fapp%2Fapp.component.ts
This should help you.
You need to pass an event handler to ngchange.
In the event handler, you can get the element id which should help you to update your list. checkboxselectlist
// in your app.component.ts
filterResults(obj: any, e: any) {
console.log(obj);
console.log(e.currentTarget.checked); // true or false
// UPDATE LIST HERE
}
// in your app.component.html
<tr *ngFor="let list of listes; index as i">
<td>{{i+1}}</td>
<td>{{list.name}}</td>
<td>{{list.qty}}</td>
<td>{{list.value}}</td>
<td> <input type="checkbox" id="vehicle1"
name="vehicle1"
(change)="filterResults(list, $event)">
</td>
</tr>

React: Render column component as a row component in a Table

I'm creating a Table component in React. I'm looking in some Table components and they create an array of columns to pass to the Table. In this columns array you can put a function to render a component inside each row in tbody.
First Example of Ant Design (https://ant.design/components/table/):
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name'
}, {
title: 'Action',
key: 'action',
render: (text, record) => ( <<-- THIS FUNCTION. IT RECEIVES THE ROW RECORD AS A PARAM TOO
<span>
This gonna be rendered in each row of the table
</span>
),
}];
I'm trying to figure it out a good way to create this mechanism to render a column in each row of the table body.
Is there a good example to study? I'm trying to read the source code in some components in NPM.. but it's hard to understand.
Thanks devs!
This is a basic example, Usually your Table component would receive 2 props:
Data sorce, can be array of objects
The column configuration, which contains the attribute name, the trick of the function is just the functional programming of javascript, you can receive render function so user can implement their own render logic.
eg.
const dataSource = [
{
id: 1,
name: 'aaaa',
age: 10
},
{
id: 2,
name: 'bbbb',
age: 11
},
{
id: 3,
name: 'ccc',
age: 12
},
];
so a column config would be like:
const column = [
{
key: 'id',
label: 'ID'
},
{
key: 'name',
label: 'Student Name'
},
{
key: 'age',
label: 'Student Age',
render: (text, record) => {
return `** ${text} **`; // just for decoration
}
}
]
The table component would iterate around the datasource and with the help of column configuration to build the Table tags.
however you can always add something like this inside of your loop logic:
if (typeof render === 'function') {
cell = <td key={key}>{render(item[key], item)}</td> // call the render function and pass the data
} else {
cell = <td key={key}>{item[key]}</td> // else will just render it
}

Vue2 dynamic v-model for a group

I am working on a housing form and I am stuck somewhere and I am hoping someone give me a solution to my problem.
So, when you select in a form that your house have 2 floors, then you get to write each floor how many rooms, toilets, balcony etc has..
My issue is to "group" these answers somehow that I could send it to my backend and "read" those answers.
so this is what I did so far:
data() {
return {
flooroptions: [
{
name: 'Rooms',
id: '1',
},
{
name: 'Balcony',
id: '2',
},
{
name: 'Toilets',
id: '3',
},
],
floors: '',
floor1: [],
},
}
and if I loop through like this:
<div class="" v-for="(opt, index) in flooroptions">
<input type="number" name="" value="" v-model="floor1[index]">
</div>
I can see my data using floor1:
{{ floor1 }}
But if in the form someone selects that 1st floor has 2 rooms and does not add any other input than I get to floor1 only 2
How would be better approach for this type of problem ??
PS. Everyfloor will have this flooroptions loop and they can input number of each option for each floor, and I want to be able to read that number correctly..
if I understand correctly, I would...
data() {
return {
flooroptions: [
{
name: 'Rooms',
id: '1',
},
{
name: 'Balcony',
id: '2',
},
{
name: 'Toilets',
id: '3',
},
],
numFloors: 2,
floorData: [
{'Rooms':0, 'Balcony':0, 'Toilets':2},
{'Rooms':2, 'Balcony':1, 'Toilets':0}
],
},
}
and loop through like this:
<div v-for="f in numFloors">
<div class="" v-for="opt in flooroptions">
<input type="number" name="" value="" v-model="floorData[f][opt.name]">
</div>
</div>
or... if you want to pass less data and the id's are know on the backen
data() {
return {
flooroptions: {
1: {
name: 'Rooms'
},
2: {
name: 'Balcony'
},
3: {
name: 'Toilets'
},
},
numFloors: 2,
floorData: [
{1:0, 2:0, 3:2},
{1:2, 2:1, 3:0}
],
},
}
and loop through like this:
<div v-for="f in numFloors">
<div class="" v-for="(opt, i) in flooroptions">
<input type="number" name="" value="" v-model="floorData[f][i]">
</div>
</div>

Multiple select Vue.js and computed property

I'm using Vue.js 2.0 and the Element UI library.
I want to use a multiple select to attribute some roles to my users.
The list of all roles available is received and assigned to availableRoles. Since it is an array of object and the v-model accepts only an array with value, I need to extract the id of the roles trough the computed property computedRoles.
The current roles of my user are received and assigned to userRoles: [{'id':1, 'name':'Admin'}, {'id':3, 'name':'User'}].
computedRoles is then equals to [1,3]
The preselection of the select is fine but I can't change anything (add or remove option from the select)
What is wrong and how to fix it?
http://jsfiddle.net/3ra1jscx/3/
<div id="app">
<template>
<el-select v-model="computedRoles" multiple placeholder="Select">
<el-option v-for="item in availableRoles" :label="item.name" :value="item.id">
</el-option>
</el-select>
</template>
</div>
var Main = {
data() {
return {
availableRoles: [{
id: 1,
name: 'Admin'
}, {
id: 2,
name: 'Power User'
}, {
id: 3,
name: 'User'
}],
userRoles: [{'id':1, 'name':'Admin'}, {'id':3, 'name':'User'}]
}
},
computed : {
computedRoles () {
return this.userRoles.map(role => role.id)
}
}
}
I agree mostly with #wostex answer, but he doesn't give you the userRoles property back. Essentially you should swap computedRoles and userRoles. userRoles becomes a computed property and computedRoles is a data property. In my update, I changed the name of computedRoles to selectedRoles.
var Main = {
data() {
return {
availableRoles: [{
id: 1,
name: 'Admin'
}, {
id: 2,
name: 'Power User'
}, {
id: 3,
name: 'User'
}],
selectedRoles:[1,2]
}
},
computed : {
userRoles(){
return this.availableRoles.reduce((selected, role) => {
if (this.selectedRoles.includes(role.id))
selected.push(role);
return selected;
}, [])
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
And here is the fiddle.
Check the solution: jsfiddle
The caveat here is that computed properties are getters mainly. You can define setter for computed property, but my approach is more vue-like in my opinion.
In short, instead of v-model on computed set v-model for data property.
Full code:
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui/lib/index.js"></script>
<div id="app">
<template>
<el-select v-model="ids" multiple placeholder="Select" #change="logit()">
<el-option v-for="item in availableRoles" :label="item.name" :value="item.id">
</el-option>
</el-select>
</template>
</div>
var Main = {
data() {
return {
availableRoles: [{
id: 1,
name: 'Admin'
}, {
id: 2,
name: 'Power User'
}, {
id: 3,
name: 'User'
}],
userRoles: [{'id':1, 'name':'Admin'}, {'id':3, 'name':'User'}],
ids: []
}
},
mounted() {
this.ids = this.userRoles.map(role => role.id);
},
methods: {
logit: function() {
console.log(this.ids);
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')

ng-model returns name of value in place of real value

I have html page using angular.
I have a table with ng-repeat on array:
<tr ng-repeat="oblig in Obligations">
oblig object contains property of chargeOptionId connected to another array ChargeOptions.
Inside the table there is a select element that I want to show details of charge option of oblig.
html code:
<select class="form-control full-width" ng-model="oblig.ChargeOptionId">
<option ng-selected="ch.Id == oblig.ChargeOptionId" value="ch.Id" ng-repeat="ch in ChargeOptions">{{ch.Account}}</option>
</select>
the select element display the charge option details as I want, but when I try saving oblig, oblig.ChargeOptionId="ch.Id" string in place of value of ch.Id.
I tried:
1) using ng-value, but the select did not display the data correctly.
2) ng-options, but still data was not displayed correctly.
how can I fix that problem?
Change
value="ch.Id"
to
value="{{ch.Id}}"
or
ng-value="ch.Id"
The attribute "value" is not an angular directive (like ng-model and ng-value are) so it doesn't know you intend "ch.Id" as a variable.
jsbin
I'm not sure what was failing before, but this seems to work: I used ng-options instead of ng-repeat.
This seemed to do the trick:
angular.module('app', []).controller('Ctrl', function($scope) {
$scope.Obligations = [
{ ChargeOptionId: 1 },
{ ChargeOptionId: 2 },
{ ChargeOptionId: 3 },
{ ChargeOptionId: 4 },
{ ChargeOptionId: 5 },
{ ChargeOptionId: 6 },
{ ChargeOptionId: 7 }
];
$scope.ChargeOptions = [
{ Id: 1, Account: 'Account 1' },
{ Id: 2, Account: 'Account 2' },
{ Id: 3, Account: 'Account 3' },
{ Id: 4, Account: 'Account 4' },
{ Id: 5, Account: 'Account 5' },
{ Id: 6, Account: 'Account 6' },
{ Id: 7, Account: 'Account 7' }
];
$scope.alertSelected = function(idx) {
alert($scope.Obligations[idx].ChargeOptionId);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="app" ng-controller="Ctrl">
<div ng-repeat="oblig in Obligations">
<div>
ChargeOption.Id = {{ChargeOptions[$index].Id}} /
Obligation.ChargeOptionId = {{oblig.ChargeOptionId}}
</div>
<select class="form-control full-width"
ng-model="oblig.ChargeOptionId"
ng-options="ch.Id as ch.Account for ch in ChargeOptions">
</select>
<button ng-click="alertSelected($index)">Selected value?</button>
<br /><br />
</div>
</div>

Categories

Resources