JHipster:通过用具有可观察性的 NgbTypeahead 替换 ComboBox 来实现自动完成

JHipster : implement AutoComplete by replacing ComboBox with a NgbTypeahead with observable

我想用 "Autocomplete" 字段替换 JHipster(6.8.0) 中使用的组合框,我在 Antonio Goncalves's 博客上找到了方法用 PrimeNG 来做,但我不想添加另一个新的 Widgets 库。

我意识到 JHipster 已经在使用 "Bootstrap widgets" 库 (https://ng-bootstrap.github.io) 来输入带有 "ngb-datepicker" 的日期。

此库提供了一个组件,允许使用 "Ngb-typeahead" 指令实现 "Autocomplete" 功能。 我不是 Angular 专家,所以找到最好的方法对我来说并不容易。也就是说,要进行的更改相对较小,但最重要的是:有效

有变化:

JDL文件用于生成JHipster示例应用程序

entity Contact {
    firstName String required,
    lastName String required,
    email String
}

entity Language {
    alpha3b String required maxlength(3),
    alpha2 String required maxlength(2)
    name String required,
    flag32  String,
    flag128 String,
    activated Boolean
}

relationship ManyToOne {
    Contact{language(name) required} to Language
}

filter *

service all with serviceClass
paginate Contact with pagination
dto * with mapstruct

接触-update.component.html

将现有控件替换为:

                <div class="form-group">
                    <label class="form-control-label" jhiTranslate="jhcontact2App.contact.language" for="field_language">Language</label>
<!--                     <select class="form-control" id="field_language" name="language" formControlName="languageId"> -->
<!--                         <option *ngIf="!editForm.get('languageId')!.value" [ngValue]="null" selected></option> -->
<!--                         <option [ngValue]="languageOption.id" *ngFor="let languageOption of languages; trackBy: trackById">{{ languageOption.name }}</option> -->
<!--                     </select> -->

                    <input type="text" class="form-control" id="field_language" formControlName="language"
                           placeholder="{{ 'jhcontact2App.contact.language.placeholder' | translate }}"                         
                           (selectItem)="selectedItem($event)"
                           [ngbTypeahead]="search"
                           [inputFormatter]="formatter"
                           [resultFormatter]="formatter"
                           [editable]='false' />

                </div>
                <div *ngIf="editForm.get('language')!.invalid && (editForm.get('language')!.dirty || editForm.get('language')!.touched)">
                    <small class="form-text text-danger"
                           *ngIf="editForm.get('language')?.errors?.required" jhiTranslate="entity.validation.required">
                        This field is required.
                    </small>
                </div>

接触-update.component.ts

更新 ngOnInit、updateFrom、createForm 方法

  ngOnInit(): void {
    this.activatedRoute.data.subscribe(({ contact }) => {
      this.updateForm(contact);
// remove service call to populate Languages Collection
//      this.languageService.query()
//               .subscribe((res: HttpResponse<ILanguage[]>) => (this.languages = res.body || []));
    });
  }
  updateForm(contact: IContact): void {
    this.editForm.patchValue({
      id: contact.id,
      firstName: contact.firstName,
      lastName: contact.lastName,
      email: contact.email,
// Patch full Language object instead id      
//      languageId: contact.languageId,
      language: {id: contact.languageId, name: contact.languageName}
    });
  }
  private createFromForm(): IContact {
    // get full object from form
    const language: ILanguage = this.editForm.get(['language'])!.value;
    return {
      ...new Contact(),
      id: this.editForm.get(['id'])!.value,
      firstName: this.editForm.get(['firstName'])!.value,
      lastName: this.editForm.get(['lastName'])!.value,
      email: this.editForm.get(['email'])!.value,      
//      languageId: this.editForm.get(['languageId'])!.value     
      languageId: language.id
    };
  }

添加 Ngb-typeahead 使用的新功能:

  // Add formatter
  formatter = (x: { name: string }) => x.name;

  // the seach function
  search = (text$: Observable<string>) =>
        text$.pipe(
            debounceTime(300),
            distinctUntilChanged(),
            switchMap(term => this.languageService.searchByName( term ))
        )
  // the OnSelect 
  selectedItem(language: ILanguage): void {
      this.editForm.patchValue({
      language: language.name
    });
  }

language.service.ts

  searchByName(term: string): any {
    if (term === '') {
      return of([]);
    }
    const options = createRequestOption({ 'name.contains': term });
    return this.http.get<ILanguage[]>(this.resourceUrl, { params: options });
  }

这最后一点不能完全满足我,因为我想重用language.service.ts组件的"initial query generated method",但是这个方法使用了RXJS和returns一个"Observable"和我不知道如何等待http请求结束将结果传递给函数

初始查询生成方法

  query(req?: any): Observable<EntityArrayResponseType> {
    const options = createRequestOption(req);
    return this.http.get<ILanguage[]>(this.resourceUrl, { params: options, observe: 'response' });
  }

有谁能帮我解决这个问题吗?

终于,我找到了重用 JHispter 生成的 "query()" 方法的方法!

像这样:

  // the search function
  search = (text$: Observable<string>) =>
    text$.pipe(
      debounceTime(300),
      distinctUntilChanged(),
      switchMap(term => term.length < 2 ? [] : this.languageService.query({ 'name.contains': term })),
      map((res: HttpResponse<ILanguage[]>) => (res.body || []))
    );

searchByName() 方法不再需要。