Использование независимой ngModel в реактивной форме Angular 2+

У меня есть реактивная форма на моей странице.

Вот краткое изложение кода:

<div class="container">
<form [formGroup]="transactionForm" (ngSubmit)="onSubmit(transactionForm)">
     <div formGroupName="userInfoGroup" class="form-group">
          <input formControlName="name" class="form-control" placeholder="Larry" id="name"> 
     </div>
     ...
</form>   
</div>

Вот где это становится сложно. Я хочу, чтобы пользователь мог вводить информацию о человеке, который его направил (который может существовать или не существовать в нашей базе данных). Поэтому я хочу использовать ng-bootstrap typeahead, чтобы предоставить способ найти существующего пользователя.

Итак, я скопировал код html и ts из ng-bootstrap, и теперь мой шаблон выглядит так:

<div class="container">
<form [formGroup]="transactionForm" (ngSubmit)="onSubmit(transactionForm)">
     <div formGroupName="userInfoGroup" class="form-group">
          <input formControlName="name" class="form-control" placeholder="Larry" id="name"> 
     </div>
     <input id="typeahead-http" type="text" class="form-control" [(ngModel)]="model" [ngbTypeahead]="searchForReferrer" placeholder="Search for Referrer" />
     ...
</form>   
</div>

Когда я запускаю это сейчас, я получаю ошибки:

RegisterTransaction.html:154 ERROR TypeError: Cannot read property 'lift' of undefined
    at tapOperatorFunction (tap.js:52)
    at _do (do.js:48)
    at NgbTypeahead.webpackJsonp.../../../../@ng-bootstrap/ng-bootstrap/typeahead/typeahead.js.NgbTypeahead.ngOnInit (typeahead.js:73)
    at checkAndUpdateDirectiveInline (core.es5.js:10843)
    at checkAndUpdateNodeInline (core.es5.js:12341)
    at checkAndUpdateNode (core.es5.js:12284)
    at debugCheckAndUpdateNode (core.es5.js:13141)
    at debugCheckDirectivesFn (core.es5.js:13082)
    at Object.View_RegisterTransaction_0._co [as updateDirectives] (RegisterTransaction.html:163)
    at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13067)
  [1]: https://ng-bootstrap.github.io/#/components/typeahead/examples

и если я просто удалю [ngbTypeahead]="searchForReferrer", я получу

RegisterTransaction.html:154 ERROR Error: 
      ngModel cannot be used to register form controls with a parent formGroup directive.  Try using
      formGroup's partner directive "formControlName" instead.  Example:


    <div [formGroup]="myGroup">
      <input formControlName="firstName">
    </div>

    In your class:

    this.myGroup = new FormGroup({
       firstName: new FormControl()
    });

      Or, if you'd like to avoid registering this form control, indicate that it's standalone in ngModelOptions:

      Example:


    <div [formGroup]="myGroup">
       <input formControlName="firstName">
       <input [(ngModel)]="showMoreControls" [ngModelOptions]="{standalone: true}">
    </div>


    at Function.webpackJsonp.../../../forms/@angular/forms.es5.js.TemplateDrivenErrors.modelParentException (forms.es5.js:4110)
    at NgModel.webpackJsonp.../../../forms/@angular/forms.es5.js.NgModel._checkParentType (forms.es5.js:4430)
    at NgModel.webpackJsonp.../../../forms/@angular/forms.es5.js.NgModel._checkForErrors (forms.es5.js:4417)
    at NgModel.webpackJsonp.../../../forms/@angular/forms.es5.js.NgModel.ngOnChanges (forms.es5.js:4324)
    at checkAndUpdateDirectiveInline (core.es5.js:10840)
    at checkAndUpdateNodeInline (core.es5.js:12341)
    at checkAndUpdateNode (core.es5.js:12284)
    at debugCheckAndUpdateNode (core.es5.js:13141)
    at debugCheckDirectivesFn (core.es5.js:13082)
    at Object.View_RegisterTransaction_0._co [as updateDirectives] (RegisterTransaction.html:163)

Как мне правильно использовать этот предварительный поиск внутри существующей реактивной формы?


person CodyBugstein    schedule 04.12.2017    source источник
comment
Итак, пожалуйста, покажите код для searchForReferrer   -  person Aluan Haddad    schedule 04.12.2017
comment
@AluanHaddad точно так же, как в примере с ng-bootstrap (пример из Википедии)   -  person CodyBugstein    schedule 04.12.2017
comment
Я почти уверен, что в Википедии нет такой статьи. В любом случае вы что-то не возвращаете или где-то не устанавливаете требуемую привязку.   -  person Aluan Haddad    schedule 04.12.2017
comment
У @AluanHaddad ng-bootstrap есть пример typeahead, который запрашивает википедию ng-bootstrap. github.io/#/components/typeahead/examples   -  person CodyBugstein    schedule 04.12.2017
comment
Верно, значит, ваша функция searchForReferrer возвращает наблюдаемое? Вы сказали, что ваш код точно такой же, но, по крайней мере, он отличается по названию. Почему бы не опубликовать это?   -  person Aluan Haddad    schedule 04.12.2017
comment
@AluanHaddad смотрите ответ, который я только что опубликовал   -  person CodyBugstein    schedule 04.12.2017


Ответы (2)


Благодаря @Aluan Haddad, который подтолкнул меня к тому, чтобы мой код был точно таким же, как и в образце кода, я в конце концов понял, что он действительно не такой. Я непреднамеренно добавил фигурные скобки вокруг части return функции стрелки.

Итак, вместо

search = (text$: Observable<string>) =>
    text$
      .debounceTime(300)
      .distinctUntilChanged()
      .do(() => this.searching = true)
      .switchMap(term =>
        this._service.search(term)
          .do(() => this.searchFailed = false)
          .catch(() => {
            this.searchFailed = true;
            return Observable.of([]);
          }))
      .do(() => this.searching = false)
      .merge(this.hideSearchingWhenUnsubscribed);

я имел

search = (text$: Observable<string>) => {
    text$
      .debounceTime(300)
      .distinctUntilChanged()
      .do(() => this.searching = true)
      .switchMap(term =>
        this._service.search(term)
          .do(() => this.searchFailed = false)
          .catch(() => {
            this.searchFailed = true;
            return Observable.of([]);
          }))
      .do(() => this.searching = false)
      .merge(this.hideSearchingWhenUnsubscribed);
}
person CodyBugstein    schedule 04.12.2017
comment
Это то, что я понял, рад, что вы обнаружили основную проблему. +1 - person Aluan Haddad; 04.12.2017
comment
Большое спасибо за твою помощь. +1 и вам. Такая сложная проблема, поскольку сообщение об ошибке настолько расплывчато - person CodyBugstein; 04.12.2017
comment
Да, я знаю, что lift — это метод для Observable, поэтому у меня было подозрение, но да, его неудобно отлаживать, потому что эти методы используются непосредственно из разметки и не проверяются на тип. Если бы typeahead API вызывался через TypeScript, это было бы примерно так: [ts] Error: cannot assign void to Obersvable<T>. Возможно, было бы полезно написать модульные тесты для таких методов, поскольку они связаны только в разметке. - person Aluan Haddad; 04.12.2017

Решение дается только в сообщении об ошибке. Вы не можете использовать ngModel внутри группы форм. Если вы хотите использовать ngModel, вам нужно указать для этого элемента значение standalone: ​​true, передав [ngModelOptions]="{standalone: ​​true}" в этом элементе. Вам просто нужно написать этот элемент как:

<input id="typeahead-http" type="text" class="form-control" [(ngModel)]="model" [ngModelOptions]="{standalone: true}" [ngbTypeahead]="searchForReferrer" placeholder="Search for Referrer" />

Это должно решить вашу проблему.

person Sudeep Mukherjee    schedule 07.01.2018