0

I face an issue with data binding in LWC if I want to use dynamic form. Let's say I have html like this:

 <template for:each={data} for:item="item">
    <lightning-combobox
        key={item.name}
        label={item.name}
        required={item.isRequired}
        placeholder="Select"
        options={item.allowedValues}
     >
    </lightning-combobox>
 </template>

and where {data} is JSON object with all data I need for view .

I need to gather all data(values of selected combobox values) and make JSON from it. Is there any data binding possibilities in LWC for such situations?

For now I have found out only opportunity to use:

var selectFields = this.template.querySelectorAll("combobox"); 

which is not scalable, since I have not only combobox inside template for:each...

1

To track the values of your lightning-combobox and other form components, track the index of each item in the for:each template, use the value attribute in the combobox, and handle the onchange event:

<template for:each={data} for:item="item" for:index="index">
   <lightning-combobox
       key={item.name}
       data-index={index}
       label={item.name}
       required={item.isRequired}
       placeholder="Select"
       options={item.allowedValues}
       value={item.myPropertyValue}
       onchange={handleChange}>
   </lightning-combobox>
</template>

In your JS class, assign the value:

@track data;

handleChange(event) {
  this.data[event.target.dataset.index].myPropertyValue = event.target.value;
}

If your Javascript object is a Proxy, you may need to do JSON.parse(JSON.stringify(this.data)) in some fashion in order to be able to directly set the properties as I've illustrated above.

See docs on:

| improve this answer | |
0

Welcome to the forum.

You can give a name to the combobox

 <lightning-combobox
    name ="comboboxName"
    key={item.name}
    label={item.name}
    required={item.isRequired}
    placeholder="Select"
    options={item.allowedValues}>
</lightning-combobox>

After that you can access this combobox, only this one, from you JS like this:

let myCombobox = this.template.querySelector('.comboboxName');

that way you can access that specific combobox...

| improve this answer | |
  • I just want to avoid this.template.querySelector and want to find possibility to bind data in html and js. Since this.template.querySelector is manipulating with the DOM. – Vitalijs Miņins Nov 26 '19 at 15:21
  • But you are getting the data first in LWC JS by using a connectedCallback? Maybe is better to post all the code so we can see how are you getting the data... are you using data service? – Carlos Naranjo Nov 26 '19 at 15:24
  • yes. At first I get the {data} from Apex in connectedCallback then i use it in JS and then in html for:each={data} – Vitalijs Miņins Nov 26 '19 at 15:30
0

This is the code snippet of html.


                        <template for:each={data} for:item="item" >
                            <template if:false={item.isRequired}>
                                <c-child-textcomponent key={item.name}
                                    get-item-from-parent={item}>
                                </c-child-textcomponent>
                                <c-child-selectcomponent key={item.name}
                                    get-item-from-parent={item}>
                                </c-child-selectcomponent>
                                <c-child-rich-textcomponent key={item.name}
                                    get-item-from-parent={item}>
                                </c-child-rich-textcomponent>
                                <c-child-floatcomponent key={item.name}
                                    get-item-from-parent={item}>
                                </c-child-floatcomponent>
                                <c-child-date-timecomponent key={item.name}
                                    get-item-from-parent={item}>
                                </c-child-date-timecomponent>
                                <c-child-datecomponent  key={item.name}
                                    get-item-from-parent={item}>
                                </c-child-datecomponent>
                            </template>
                        </template>

                        &nbsp;&nbsp;&nbsp;&nbsp;
                        <div style="margin-left:4%">
                            <div>
                                <lightning-input label="" name="file uploader" onchange={handleFilesChange} type="file" multiple></lightning-input>
                            </div>
                            <br/>
                        </div>
                    </div>
                </div>
                <footer class="slds-modal__footer">
                    <lightning-button label="Cancel" variant="neutral" onclick={closeModal}></lightning-button>&nbsp;&nbsp;&nbsp;&nbsp;
                    <lightning-button label="Save&Sync" variant="brand" onclick={saveMethod}></lightning-button>
                </footer>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>

   </template>
</div>

And js:

import { LightningElement, api, track } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent'
import postJiraIssue from '@salesforce/apex/JiraController.postJiraIssue';
import getRestProjectIssues from '@salesforce/apex/JiraController.getRestProjectIssues';
import getRestProjectIssueTypeFields from '@salesforce/apex/JiraController.getRestProjectIssueTypeFields';
import postJiraAttachment from '@salesforce/apex/JiraController.postJiraAttachment';
import JIRA_LOGO from '@salesforce/resourceUrl/jiraLogo';
import {parseIssues, getJiraProjects, createPostJson, getAttachmentArray } from 'c/jiraButtonPopupHelper';

export default class JiraButtonPopup extends LightningElement {

    @api recordId;
    @track jiraLogo = JIRA_LOGO;
    @track openmodel = false;
    @track projectDropdown = null;
    @track issueTypeDropdown = null;
    @track data =[];
    projectKey;
    issueTypeId;

    connectedCallback() {  
        this.projectDropdown = getJiraProjects();  
    }

    get projectOptions() {
        return this.projectDropdown;
    }

    get issueTypeOptions() {
        return this.issueTypeDropdown;
    }

    handleProjectChange(event) {
        this.data =null;
        this.projectKey = event.detail.value;
        getRestProjectIssues({ projectKey: this.projectKey})
        .then(result=>{
            if(result){
                this.issueTypeDropdown = parseIssues(result);
            }
        });
    }

    handleIssueTypeChange(event) {
        this.data = null;
        this.issueTypeId = event.detail.value;
        getRestProjectIssueTypeFields({projectKey: this.projectKey, issueTypeId: this.issueTypeId})
        .then(result => {
            if(result){
                this.data = result;
            }
        });

    }

    openmodal() {
        this.openmodel = true;
    }

    closeModal() {
        this.data = null;
        this.openmodel = false;
    } 

    saveMethod() {

        var richTextFields = this.template.querySelectorAll("c-child-rich-textcomponent");
        var textFields = this.template.querySelectorAll("c-child-textcomponent");
        var selectFields = this.template.querySelectorAll("c-child-selectcomponent");
        var floatFields = this.template.querySelectorAll("c-child-floatcomponent");
        var dateTimeFields = this.template.querySelectorAll("c-child-date-timecomponent");
        var dateFields = this.template.querySelectorAll("c-child-datecomponent");
        var postJson = createPostJson(this.projectKey, this.issueTypeId, richTextFields, textFields, selectFields, floatFields, dateTimeFields, dateFields);

        console.log(JSON.stringify(postJson));

        postJiraIssue({jsonBody:JSON.stringify(postJson)})
        .then(data => {

            if(data.length>20){
                var parsedErrors = JSON.parse(data);
                var errorMessages ='';
                for(var key in parsedErrors){  
                    errorMessages = errorMessages + ' ' + parsedErrors[key];
                }  
                console.log(errorMessages);
                this.dispatchEvent(
                    new ShowToastEvent({
                        title: 'Please Fill The Required Fields',
                        message: errorMessages,
                        variant: 'error'
                    }),
                );  
            }else{
                this.createdJiraIssueKey = data;
                console.log(data);
                for(var z=0; z<this.attachmentArray.length; z++){      
                    postJiraAttachment({fileBody:this.attachmentArray[z].blobArray, fileName:this.attachmentArray[z].filename, projectKey:data}); 
                }
                this.data = null;          
                this.closeModal();
            }
        });
    }

    handleFilesChange(event) {
        this.attachmentArray = getAttachmentArray(event);
    } 
}
| improve this answer | |
0

It's advisable to create a child component that only renders a single form and pass in a single item, the child component would render the form for a single item and have onchange handlers on all it's components, it would also expose a method that the parent component can call to get the edited item.

When the submit/save button is pressed you'd use this.template.querySelectorAll('c-child-component') and call the method to get the edited items for each one.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.