Starts in:
1 DAY
10 HRS
51 MIN
31 SEC
Starts in:
1 D
10 H
51 M
31 S
Open Closed

Angular: show errors when user clicks submit with invalid form #870


User avatar
0
paul.harriman created

Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ Check the samples, to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index The exact solution to your question may have been answered before, please use the search on the homepage.

  • ABP Framework version: v4.0.2
  • UI type: Angular
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Seperated (Angular): yes / no
  • Exception message and stack trace:
  • Steps to reproduce the issue:

Have a form in a modal with validation. For simplicity mark fields as required

component.html <abp-modal [(visible)]="isModalVisible" [busy]="modalBusy" (disappear)="form = null"> <ng-template #abpHeader> <h3>{{ (selected?.id ? 'AbpUi::Edit' : 'HR::NewEmployeeExperience') | abpLocalization }}</h3> </ng-template>

<ng-template #abpBody> <form [formGroup]="form" validateOnSubmit> <div class="mt-2 fade-in-top"> <div class="form-group"> <label for="employeeExperience-workplace"> {{ 'HR::Workplace' | abpLocalization }} </label> <span class="req-mark"> * </span> <input type="text" id="employeeExperience-workplace" class="form-control" formControlName="workplace" /> </div> <div class="form-group"> <label for="employeeExperience-seniority"> {{ 'HR::Seniority' | abpLocalization }} </label> <span class="req-mark"> * </span> <input type="number" id="employeeExperience-seniority" class="form-control" formControlName="seniority" /> </div> <div class="form-group"> <label for="employeeExperience-position"> {{ 'HR::Position' | abpLocalization }} </label> <span class="req-mark"> * </span> <input type="text" id="employeeExperience-position" class="form-control" formControlName="position" /> </div> </div> </form> </ng-template>

<ng-template #abpFooter> <button type="button" class="btn btn-secondary" #abpClose> {{ 'AbpUi::Cancel' | abpLocalization }} </button>

&lt;abp-button iconClass=&quot;fa fa-save&quot; (click)=&quot;save()&quot;&gt;
  {{ 'AbpUi::Save' | abpLocalization }}
&lt;/abp-button&gt;

</ng-template> </abp-modal>

component.ts buildForm() { this.form = this.fb.group({ employeeCode: [this.employeeCode || '', [Validators.required]], workplace: [this.selected.workplace || '', [Validators.required]], seniority: [this.selected.seniority || '', [Validators.required]], position: [this.selected.position || '', [Validators.required]], }); }

submitForm(): void { if (this.form.invalid) { return; } .... remaining logic to do update }

don't enter any data, click save. the click will send it to the component, and indeed the form is invalid. the form is not marked up b/c validateOnSubmit is not triggered, the user cannot visually see what the issue is. i tried to move the form html element after <abp-modal [(visible)]="isModalVisible" [busy]="modalBusy" (disappear)="form = null"> so it would wrap all the ng-template. I also removed the click event and replaced it with a buttonType="submit" the html form element is not rendered.


4 Answer(s)
  • User Avatar
    0
    Mehmet created

    Hi

    validateOnSubmit is not work in your case. Because submit button and form are placed in different templates. You can use the methods below to achieve this:

    Recommended:

    <abp-modal [(visible)]="isModalVisible">
      <ng-template #abpHeader>
        <h3>Modal Title</h3>
      </ng-template>
    
      <ng-template #abpBody>
        <form [formGroup]="form" (ngSubmit)="save()" validateOnSubmit>
          <!-- form elements here -->
    
          <div class="text-right mt-2">
            <button type="button" class="btn btn-secondary mr-1" #abpClose>
              Close
            </button>
    
            <!-- make sure the button type is submit and placed between the <form> tag -->
            <abp-button iconClass="fa fa-check" (click)="save()" buttonType="submit">
                Save
            </abp-button>
          </div>
        </form>
      </ng-template>
    </abp-modal>
    

    Alternate:

    <!-- HTML template -->
    <abp-modal [(visible)]="isModalVisible">
      <ng-template #abpHeader>
        <h3>Modal Title</h3>
      </ng-template>
    
      <ng-template #abpBody>
         <!-- set a hash id as shown below (#myForm) -->
        <form #myForm [formGroup]="form" (ngSubmit)="save()" validateOnSubmit>
          <!-- form elements -->
        </form>
      </ng-template>
    
      <ng-template #abpFooter>
            <abp-button iconClass="fa fa-check" (click)="save()">
                Save
            </abp-button>
      </ng-template>
    </abp-modal>
    
    ----------------
    
    // ts
    
    // catch the form element via ViewChild
    @ViewChild('myForm', { static: false, read: ElementRef })
    myFormRef: ElementRef<HTMLFormElement>;
    
    save() {
    if (this.form.invalid) {
    // dispatch submit event of form element
    this.myFormRef.nativeElement.dispatchEvent(new Event('submit', { bubbles: true, cancelable: true }));
    
    return;
    }
    
    // your save logic
    }
    
  • User Avatar
    0
    paul.harriman created

    I', going with the first solution. I have to do some ui repair as moving the footer creates some visual issues. the send solution did not work for me.

  • User Avatar
    0
    Mehmet created

    Can you share the code?

  • User Avatar
    0
    paul.harriman created

    Which r u looking for? Solution 2?

Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06