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.

2 Answers 2

  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'
  • 1
    As I mentioned, I am starting from a blank state so onLoad is not applicable and I can't use updateRecord. Aug 20, 2019 at 20:45
  • @DavidCheng did you find resolution?
    – user891859
    Nov 11, 2019 at 17:49
  • 1
    @user891859 See my answer below. Nov 18, 2019 at 17:59
  • @salesforce-sas is there any way to use this approach update as well create record?
    – sdandamud1
    Aug 15, 2020 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, 2019 at 7:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .