Можно ли в угловых реактивных формах проверять условия вне формы? - PullRequest
0 голосов
/ 22 октября 2018

Я работаю над проверкой угловых реактивных форм.У меня есть вход с реализованным автозаполнением Google:

<input autocorrect="off" autocapitalize="off" spellcheck="off" type="text" class="input-auto input" formControlName="address">

Это стандартная реализация, каждый раз, когда вы вводите ключевое слово, вы получаете предложения мест:

google-autocomplete

Теперь я хотел бы проверить адрес. Адрес должен содержать почтовый индекс - только тогда должен быть действительным .Поэтому, когда вы наберете что-то и выберете одно из предложений, проверка должна быть запущена.Когда выбранное предложение содержит почтовый индекс, допустимо, когда нет - недействительно.

Как вы можете видеть, существует только один элемент управления формой для всего адреса (и так должно быть), который я заполняю отформатированным адресомиз Google API.Я также получаю информацию об адресных компонентах из API мест Google, который храню в глобальных переменных (zipCode, countryName, cityName, streetName):

    this.mapsAPILoader.load().then(() => {
      const autocomplete = new window['google'].maps.places.Autocomplete(this.searchElementToRef.nativeElement, {
        types: ['address']
      });
      autocomplete.addListener('place_changed', () => {
        this.ngZone.run(() => {

          const place = autocomplete.getPlace();

          if (place.geometry === undefined || place.geometry === null) {
            return;
          }

          this.form.get('address').setValue(place.formatted_address);

          for (const addressComponent of place.address_components) {
            for (const addressComponentType of addressComponent.types) {
              switch (addressComponentType) {
                case 'postal_code':
                  this.zipCode = addressComponent.long_name;
                  break;
                case 'country':
                  this.countryName = addressComponent.long_name;
                  break;
                case 'locality':
                  this.cityName = addressComponent.long_name;
                  break;
                case 'route':
                  this.streetName = addressComponent.long_name;
                  break;
              }
            }
          }
        });
      });
    });

Inметод, который создает форму с FormBuilder Я использую пользовательский валидатор:

  public createFormGroup(): FormGroup {
    return this.fb.group({
      address: [null, this.zipCodeValidator()]
    });
  }

При использовании нижеприведенного метода валидации я хотел бы получить ошибку, если в адресе отсутствует zipCode:

  public zipCodeValidator(): ValidatorFn {
    return (control: AbstractControl): Observable<{ [key: string]: boolean } | null> => {
      if (this.zipCode !== undefined) {
        return of({ zipCode: true });
      }
      return null;
    };
  }

Однако форма неверно подтверждена, потому что независимо от того, получаю ли я адрес с почтовым индексом или без него, он всегда действителен:

form print

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

  public zipCodeValidator(): ValidatorFn {
    return (control: AbstractControl): Observable<{ [key: string]: boolean } | null> => {
      if (control.value === null) {
        return of({ noValue: true });
      }
      return null;
    };
  }

Вопрос:
Возможно ли проверить форму подобным образом?- с условиями, фактически не имеющими формы (поскольку я не передаю это значение zipCode непосредственно в какой-либо элемент управления формы)?

1 Ответ

0 голосов
/ 23 октября 2018

Ответ таков: можно проверять условия вне формы , и, как обычно, это было очень близко ко мне.

Сначала я испортил метод проверки,Observable Я использовал для асинхронная проверка .Поэтому после исправления метод вернет только объект, а не Observable:

  public zipCodeValidator(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: boolean } | null => {
      if (control.value !== null) {
        // if value exists, we can add number of conditions
        if (this.zipCode !== undefined) {
          return { zipCode: true };
        }
      } else {
          // here we can react when there is no value entered - act as validator.required
          return { empty: true}
        }
      return null;
    };
  }

Затем я начал выполнять проверку, но для предыдущего состояния переменной zipCode.Я подумал, потому что, возможно, мне нужно использовать асинхронную проверку, но это было еще проще.Я установил значение элемента управления формы адреса слишком рано: this.form.get('address').setValue(place.formatted_address);
Итак, я переместил его за ту часть, где я ищу почтовый индекс, и это сработало:

this.mapsAPILoader.load().then(() => {
  const autocomplete = new window['google'].maps.places.Autocomplete(this.searchElementToRef.nativeElement, {
    types: ['address']
  });
  autocomplete.addListener('place_changed', () => {
    this.ngZone.run(() => {

      const place = autocomplete.getPlace();

      if (place.geometry === undefined || place.geometry === null) {
        return;
      }

      for (const addressComponent of place.address_components) {
        for (const addressComponentType of addressComponent.types) {
          switch (addressComponentType) {
            case 'postal_code':
              this.zipCode = addressComponent.long_name;
              break;
            case 'country':
              this.countryName = addressComponent.long_name;
              break;
            case 'locality':
              this.cityName = addressComponent.long_name;
              break;
            case 'route':
              this.streetName = addressComponent.long_name;
              break;
          }
        }
      }

      this.form.get('address').setValue(place.formatted_address);
    });
  });
});

Существует также вопрос о том, что если я хочу запустить проверку в другой момент, а не с самого начала.Тогда просто нужно установить его в нужном месте и обновить валидаторы:

this.form.get('address').setValidators(this.zipCodeValidator());
this.form.get('address').updateValueAndValidity();

Также, если есть необходимость удалить его в какой-то момент, вот простой способ:

this.form.get('address').clearValidators();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...