I'm new to Lightning web components (LWC) and I'm trying to find the best way to build an input form where I need to control the submit process - I need to do extra validation and then construct a contact object to submit to an Apex method then do my own record insert.

The form has some contact fields - first name, last name, email, etc. Some fields are required, some are not. We're starting from blank, there will be no existing data pre-filled.

When the user submits the form, I need to do some extra validation. Then I want to construct a contact from the data and call Apex to find any matching contacts (using duplicate rules). Based on those results, I'll insert a new contact or update an existing contact.

I started by looking at lightning-record-edit-form, but lightning-input-field doesn't have a required attribute and I didn't like the workarounds I found in web searches.

So instead, I'm using lightning-input fields with a lightning-button. When the user submits, I get the data for each input using querySelector and construct the contact object, then I call the Apex method,

I have two questions:

  1. Is there a way to mix lightning-input and lightning-input-field on lightning-record-edit-form so that I can use required attribute where I need it, yet still get the lightning-input data into the contact object instantiated by the form?

  2. If I can't do #1, is there a more efficient pattern than the one I'm doing below?

The HTML page:

    <lightning-input data-formfield="firstName" label="First Name" required></lightning-input>
    <lightning-input data-formfield="lastName" label="Last Name" required></lightning-input>
    <lightning-input data-formfield="mobile" label="Mobile" type="phone" class="spec-req"></lightning-input>
    <lightning-input data-formfield="email" label="Email" type="email" class="spec-req"></lightning-input>
    <lightning-button label="Submit" click={handleFirstSubmit}></lightning-button>

The JS code:

handleFirstSubmit() {
  let submittedContact = { 'sObjectType': 'Contact' };
  submittedContact.FirstName = this.template.querySelector('lightning-input[data-formfield="firstName"]').value;
  submittedContact.LastName = this.template.querySelector('lightning-input[data-formfield="firstName"]').value;
  submittedContact.MobilePhone = this.template.querySelector('lightning-input[data-formfield="mobile"]').value;
  submittedContact.Email = this.template.querySelector('lightning-input[data-formfield="email"]').value;
  // Call Apex method and pass submittedContact.
  1. There is no need of Apex as you have standard updateRecord.

  2. Get the record values from onload event of record-edit-form and create a record structure from that data. Filter the fields based on what fields are used in form.

  3. Use combination of input and input-field for fast implementation.

  4. Update the field value with onchange event. You can use data-field on all fields for this purpose.

Below is the example:

<lightning-record-edit-form record-id="00328000008ZUIdAAO"
    <lightning-input-field data-field="AccountId" field-name="AccountId" onchange={handleFieldChange}>
    <lightning-input data-field="FirstName" value={contactRecord.FirstName} onchange={handleFieldChange}>
    <lightning-input data-field="LastName" value={contactRecord.LastName} onchange={handleFieldChange}>
    <lightning-input-field data-field="Email" field-name="Email" onchange={handleFieldChange}>
    <lightning-button class="slds-m-top_small"


import { LightningElement, wire, api, track } from 'lwc';
import { updateRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';

export default class Poc extends LightningElement {
    @track contactRecord = {};

    handleLoad(event) {
        if (!this.loadedForm) {
            let fields = Object.values(event.detail.records)[0].fields;
            const recordId = Object.keys(event.detail.records)[0];
            this.contactRecord = {
                Id: recordId,
                    .filter((field) => !!this.template.querySelector(`[data-field=${field}]`))
                    .reduce((total, field) => {
                        total[field] = fields[field].value;
                        return total;
                    }, {})
            this.loadedForm = true;
    handleFieldChange(e) {
        this.contactRecord[e.currentTarget.dataset.field] = e.target.value;
    saveForm() {
        // if(this.validated())
        console.log('Contact for save => ', JSON.stringify(this.contactRecord));
        updateRecord({ fields: this.contactRecord })
            .then(() => {
                    new ShowToastEvent({
                        title: 'Success',
                        message: 'Contact updated',
                        variant: 'success'
            .catch((error) => {
                    new ShowToastEvent({
                        title: 'Error creating record',
                        message: error.body.message,
                        variant: 'error'
  • As I mentioned, I am starting from a blank state so onLoad is not applicable and I can't use updateRecord. Aug 20 '19 at 20:45
  • @DavidCheng did you find resolution?
    – user891859
    Nov 11 '19 at 17:49
  • @user891859 See my answer below. Nov 18 '19 at 17:59
  • @salesforce-sas is there any way to use this approach update as well create record?
    – sdandamud1
    Aug 15 '20 at 23:16

Since lightning-input-field now has a required attribute, I decided to use lightning-record-edit-form. I'm using both lightning-input-field and lightning-input because some of the form fields reside in different objects. I use an onsubmit handler to do the validation that I needed.

  • 1
    I was going to say that you can use lightning-record-form with onsubmit, as per documentation, clearing the ID from the data submitted as part of this handler, if you want to ultimately create a new Contact instead of updating an existing one.
    – Phil W
    Nov 14 '19 at 7:31

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.