JHipster:通过将 ComboBox 替换为 NgbTypeahead 和 observable 来实现 AutoComplete

Posted

技术标签:

【中文标题】JHipster:通过将 ComboBox 替换为 NgbTypeahead 和 observable 来实现 AutoComplete【英文标题】:JHipster : implement AutoComplete by replacing ComboBox with a NgbTypeahead with observable 【发布时间】:2020-08-03 13:56:08 【问题描述】:

我想用“自动完成”字段替换 JHipster(6.8.0) 中使用的组合框,我在 Antonio Goncalves's 博客上找到了使用 PrimeNG 的方法,但我做到了不想添加另一个新的小部件库。

我意识到 JHipster 已经在使用“Bootstrap 小部件”库 (https://ng-bootstrap.github.io) 通过“ngb-datepicker”输入日期。

此库提供了一个组件,允许使用 “Ngb-typeahead” 指令实现“自动完成”功能。 我不是 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 
    Contactlanguage(name) required to Language


filter *

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

contact-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>

contact-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 组件的“初始查询生成方法”,但是这个方法使用 RXJS 并返回一个“Observable "和我不知道如何等待http请求结束将结果传递给函数

初始查询生成方法

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

如果有人可以帮我解决这个问题?

【问题讨论】:

http.get() 返回一个 Observable,您将 searchByName() 键入为“any”这一事实并没有改变这一点(阅读angular.io/guide/http)。我看不出 searchByName() 和 query() 之间没有真正的区别,在这两种情况下都会返回一个 Observable,您必须在其上调用 subscribe() 来处理服务器返回的数据。 感谢盖尔的关注,我的分析错了。 在 searchByName() 的情况下,该方法返回一个 ILanguage 的 observable,但在 Query() 的情况下,该方法返回一个我不能用作迭代的 HttpResponse 的 Observable。 【参考方案1】:

终于,我找到了一种重用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() 方法不再需要了。

【讨论】:

以上是关于JHipster:通过将 ComboBox 替换为 NgbTypeahead 和 observable 来实现 AutoComplete的主要内容,如果未能解决你的问题,请参考以下文章

jHipster:仅将某些实体公开为REST端点

无法在JHipster on Production上加载另一个页面

JHipster 和 mongodb:创建名称为“mongobee”的 bean 时出错

选择项目时替换 ComboBox 中的文本

如何使用 Jhipster 生成的代码为注销添加审核?

通过 YARN 添加生成器 jhipster 时出错