Как работать с двойным представлением в Angular2

Если я быстро нажимаю кнопку отправки, форма отправляется два или более раз. Моя мысль заключалась в том, чтобы предотвратить это с отключенным атрибутом, но мне нужна переменная disableButon в каждой форме:

@Component({
    selector: 'example',
    template: `
      <form (submit)="submit()" >
        <--! Some Inputs -->
        <button [disabled]="disableButton" type="submit">Submit<button>
      </form>
       `
  })
  export class ExampleComponent {
    private disableButton: boolean = false;
    .......
    submit(){
      this.disableButton = true;
      /*
      * API call
      */
      this.disableButton = false;
    }
  }

Я делаю это правильно или есть более эффективный/элегантный способ сделать это?

Ответ 1

Это также должно работать:

<button #button (ngSubmit)="button.disabled = true" type="submit">Submit<button>

или просто (click) вместо (ngSubmit)

обновить (см. комментарии)

<button #button [disabled]="!form.valid || button.hasAttribute('is-disabled')"
     (ngSubmit)="button.setAttribute('is-disabled', 'true')"
     type="submit">Submit<button>

update (используйте директиву)

@Directive({
  selector: 'button[type=submit]'
})
class PreventDoubleSubmit {

  @HostBinding() disabled:boolean = false;

  @Input() valid:boolean = true;      

  @HostListener('click') 
  onClick() {
    if(!valid) {
      return;
    }
    this.disabled = true;
  }
}

и используйте его как

<button type="submit" [valid]="!form.valid">Submit<button>

Вам нужно добавить его в directives: [PreventDoubleSubmit] компонентов, где вы хотите его использовать, или же предоставить глобально

provide(PLATFORM_DIRECTIVES, {useValue: [PreventDoubleSubmit], multi: true})

Ответ 2

Как вы уже делаете disableButton = true в вызове отправки, вы можете проверить disableButton перед вызовом метода отправки.

Шаблон

<form (submit)="!disableButton && submit()" >
    <--! Some Inputs -->
    <button [disabled]="disableButton" type="submit">Submit<button>
</form>

Ответ 3

У меня есть несколько иной способ (может быть, более простой) иметь дело с этим - те же принципы применяются.

По сути, я буду делать следующее:

  • Создайте переменную с именем disableButton на компоненте с начальным значением false
  • Затем, когда кнопка нажата, установите для этой переменной значение true
  • Затем reset в false после отправки формы.

Вот мой код шаблона html:

<form #form="ngForm" (ngSubmit)="handleSubmit(form.value, form.valid)">
   <button type="submit" [disabled]="form.invalid || disableButton">
      Submit
   </button>
</form>

И вот мой класс:

export class UpdateForm {
   disableButton: boolean;
   constructor() { this.disableButton = false; }
   handleSubmit(formData: any, isValid: boolean) {
      if (isValid) {
         this.disableButton = true; // the button will then be disabled
         onHandleUpdate(formData);
      }
   }
   onHandleUpdate(formData) {
      this.disableButton = false; // the button will renable
   }
}

Ответ 4

Работа с двойным подчинением легко сделать неправильно. В форме с <form #theForm="ngForm" (ngSubmit)="submit()">:

<button type="submit" [disabled]="theForm.submitted" /> будет работать только в том случае, если не было никакой проверки. Angular ngForm.submitted устанавливается в true, когда кнопка нажата, а не после того, как форма прошла проверку. (NgForm "отправлено" свойство на самом деле означает "пытались отправить".)

<button type="submit" [disabled]="theForm.submitted && theForm.valid" /> не намного лучше: после получения ошибок проверки при отправке, в момент, когда пользователь исправляет ошибки проверки, кнопка отправки отключает себя по мере того, как они добираются до повторной отправки.

Сброс ngForm.submitted напрямую или через ngForm.resetForm() внутри вашего компонента submit() является плохим вариантом, так как submitted - это ваша основная переменная, определяющая, отображаются ли и где отображаются сообщения об ошибках проверки.

Реальная проблема: Angular не знает, когда или ваш API вызывает в submit() не удалось или не удалось. Даже если Angular предоставил свойство, которое означало "просто нажала кнопку" Отправить ", а также проверила всю проверку", на которой вы можете повесить [disabled] = "thisProperty", Angular не знает, когда устанавливать свойство обратно, такое например, когда ошибки API вызывают ошибки, и вы хотите, чтобы пользователь снова нажал кнопку отправки, чтобы повторить попытку сервера.

Возможно, Angular может запретить все функции отправки иметь форму () => Observable<boolean>, и она может подписаться на ваш успех или неудачу отправки, но, похоже, это избыточно, только reset логическое значение в структуре.

Итак, вы должны принять меры после завершения всех вызовов API и сообщить Angular, что кнопка отправки готова к повторному использованию. Это действие будет либо устанавливать явное логическое вы уже делаете, либо принудительно отключаете.

Здесь, как сделать это обязательно, без логического.

Добавьте ссылочную переменную шаблона, например #submitBtn, к кнопке отправки:

<button type="submit" #submitBtn class="green">Go!</button>

Передайте его вашему компоненту submit():

<form (ngSubmit)="submit(submitBtn)" ...>

Примите и используйте компонентную сторону:

submit(submitBtn: HTMLButtonElement): void {
    submitBtn.disabled = true;
    /// API calls
    submitBtn.disabled = false;
}

И если ваши вызовы API имеют несколько путей, которые совместно используют общий обработчик ошибок, вам также необходимо передать HTMLButtonElement, так как они больше не могут вырвать его из компонента с помощью this.disableButton.

(В качестве альтернативы вместо объявления и передачи #submitBtn у вас уже объявлен #theForm, поэтому передайте это вместо: в виде: NgForm и код компонента можно развернуть до кнопки... или наложение по всей форме, или что-то еще.)

Является ли это решение более или менее элегантным, чем объявление другого логического кода, которое работает несколько иначе, чем ngForm.submitted - мнение, но факт, что Angular не может знать, когда компонент submit() и все его асинхронные процессы закончил без подписки.