【问题标题】:Angular - How to close/remove search input when input empty, click outside input element or press escAngular - 如何在输入为空时关闭/删除搜索输入,单击外部输入元素或按 esc
【发布时间】:2022-01-12 19:12:35
【问题描述】:

我有一个搜索栏,当输入文本时会显示结果,问题是:

  1. 即使输入字段/搜索栏为空,搜索结果也不会消失。
  2. 如果我按 ESC 或在搜索栏或搜索结果外部单击,它不会关闭。我用渲染器和主机视图尝试了不同的东西,我不能让它工作。如果是普通的js,我敢肯定我会解决这个问题的。 Angular 有太多特殊的怪癖,我需要一些帮助。

这就是问题的样子:problem

components.ts 文件(删除了我失败的尝试):

import {
  Component,
  OnInit,
  Renderer2,
  ElementRef,
  ViewChild,
} from '@angular/core';

import { faSearch } from '@fortawesome/free-solid-svg-icons';
import { CountryService } from '../services/country.service';
import { OneCountry } from '../country';

@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.css'],
})
export class SearchComponent implements OnInit {
  faSearch = faSearch;
  countries: OneCountry[] = [];
  searchTerm: any;
  cachedCountries: OneCountry[] = [];
  

  constructor(private countryService: CountryService) {}

  ngOnInit(): void {}

  onKeyPressEvent(event: KeyboardEvent): void {
    this.getCountries();
  }

  getCountries(): void {
    this.countryService.searchCountries().subscribe({
      next: (countries) => (
        (this.countries = countries),
        (this.cachedCountries = this.countries),
        console.log(this.countries)
      ),
    });
  }

  search(value: string): void {
    this.countries = this.cachedCountries.filter((val) =>
      val.name.toLowerCase().includes(value)
    );
  }
}

这是模板文件:

<div id="search-component" class="w-full md:w-[32rem] dark:bg-darkblue-100">
  <div
    class="w-full px-4 h-[53px] flex justify-around align-center shadow-md border rounded"
  >
    <figure class="w-1/6 grid place-items-center">
      <fa-icon
        class="text-darkblue-100 dark:text-white text-lg"
        [icon]="faSearch"
      ></fa-icon>
    </figure>

    <input
      class="w-5/6 h-full focus:outline-none dark:bg-darkblue-100"
      placeholder="Search for a country..."
      #searchBox
      name="searchTerm"
      id="search-box"
      (input)="search(searchBox.value)"
      [(ngModel)]="searchTerm"
      (keypress)="onKeyPressEvent($event)"
    />
  </div>

  <ul class="mt-0 pl-0 relative z-20">
    <li
      class="z-20"
      *ngFor="let country of countries | searchFilter: searchTerm; index as i"
    >
      <a
        *ngIf="i < 10"
        routerLink="/detail/{{ country.name }}"
        class="z-20 border border-t-0 inline-block w-full md:w-[32rem] p-4 rounded shadow hover:bg-darkblue-100 hover:text-white dark:hover:bg-white dark:hover:text-black h-12 box-border"
        >{{ country.name }}</a
      >
    </li>
  </ul>
</div>

【问题讨论】:

  • 好奇你为什么使用 (input) 和 (keypress) - 它们或多或少不会触发同一个事件吗?
  • @Kinglish 按键和输入只是尝试不同的事情并希望一个人坚持下来,忘记删除按键的结果。接受了答案中的建议并使用了 observables。

标签: javascript html angular typescript dom


【解决方案1】:

“Angular 有太多特殊的怪癖”。我猜的问题是您没有将 this.countries 重置回[]。你可以模糊地接线:

   <input 
      ...
      (blur)="onBlur()" />

然后在你的课堂上

onBlur(){
   this.countries = [];
}

不过,您确实应该研究一下 observables,正如 @kinglish 在评论中提到的,您有一个奇怪的输入和按键。

【讨论】:

  • 谢谢。这很好,但我确实切换到 observables 并在搜索服务中使用了过滤器方法。按键和输入只是尝试不同的事情并希望有人坚持,忘记删除按键的结果。
【解决方案2】:

摆脱了大部分旧的东西,转而使用 observables。现在看起来像这样:

组件.ts:

import { Component, OnInit } from '@angular/core';

import { faSearch } from '@fortawesome/free-solid-svg-icons';
import { CountryService } from '../services/country.service';
import { OneCountry } from '../country';
import { Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators';

@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.css'],
})
export class SearchComponent implements OnInit {
  faSearch = faSearch;

 countries$!: Observable<OneCountry[]>;
  private searchTerms = new Subject<string>();
  constructor(private countryService: CountryService) {}

  // Push a search item into the observable stream
  search(term: string): void {
    // if (term.length >= 3) {
    //
    // }
    this.searchTerms.next(term);
  }

  ngOnInit(): void {
    this.countries$ = this.searchTerms.pipe(
      // Wait 300ms after each keystroke before considering search term
      debounceTime(300),
      // ignore new term if same as previous term
      distinctUntilChanged(),

      // Switch to new search observable each time the term changes
      switchMap((term: string) => this.countryService.searchCountries(term))
    );
  }

搜索服务:

 searchCountries(term: string): Observable<any[]> {
    const url = `${this.countriesUrl}all?fields=name`;
    if (!term.trim()) {
      // If not search term, return empty country list
      return of([]);
    }
    return this.http
      .get<Country[]>(url)
      .pipe(
        map((country) =>
          country.filter((val) => val.name.toLowerCase().includes(term))
        )
      );
  }

模板:

<div id="search-component" class="w-full md:w-[32rem] dark:bg-darkblue-100">
  <div
    class="w-full px-4 h-[53px] flex justify-around align-center shadow-md border rounded"
  >
    <figure class="w-1/6 grid place-items-center">
      <fa-icon
        class="text-darkblue-100 dark:text-white text-lg"
        [icon]="faSearch"
      ></fa-icon>
    </figure>

    <input
      class="w-5/6 h-full focus:outline-none dark:bg-darkblue-100"
      placeholder="Search for a country..."
      #searchBox
      name="searchTerm"
      id="search-box"
      (input)="search(searchBox.value)"
    />
  </div>

 <ul class="mt-0 pl-0 relative z-20">
    <li
      class="z-20"
      *ngFor="
        let country of countries$ | async;
        index as i;
        searchFilter: searchTerms
      "
    >
      <a
        *ngIf="i < 10"
        routerLink="/detail/{{ country.name }}"
        class="z-20 border border-t-0 inline-block w-full md:w-[32rem] p-4 rounded shadow hover:bg-darkblue-100 hover:text-white dark:hover:bg-white dark:hover:text-black"
        >{{ country.name }}</a
      >
    </li>
  </ul>
</div>

Resource

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多