콜백 함수를 Angular 하위 구성 요소에 전달

이 예제는 구성 요소에 함수를 전달하는 것과 관련하여 최근에 직면한 문제를 다룰 것입니다.

예를 들어 다음을 사용하는 꽤 큰 응용 프로그램이 있다고 상상해 봅시다. 국가 목록을 제공하는 콤보 상자 또는 테이블 구성 요소. 구성 요소는 앱의 여러 위치에서 사용됩니다.

이제 추가 요구 사항이 있습니다. 한 페이지에는 사용자가 기본적으로 자신이 좋아하는 국가만 보고 싶어하는 제한이 있습니다.

지금까지 모든 것이 구성 요소 자체에 캡슐화되었으며 백엔드에 대한 호출도 여기에서 수행되었습니다.

import {Component, OnInit} from '@angular/core';
import {CountryService} from "../services/country.service";
import {Country} from "../model/country";

@Component({
  selector: 'app-country-table',
  templateUrl: './country-table.component.html',
  styleUrls: ['./country-table.component.css']
})
export class CountryTableComponent implements OnInit {

  countries: Country[] = [];

  constructor(private countryService: CountryService) {
  }

  ngOnInit(): void {
    this.countryService.getAllCountries().subscribe(data => {
      this.countries = data;
      // any other operations
    }, error => console.log(error));
  }
}


이제 몇 가지 방법으로 변경 사항을 구현할 수 있습니다.
  • 지원에 대한 호출은 국가 구성 요소를 사용하는 상위 구성 요소에서 수행할 수 있으며 단순히 입력 배열로 전달됩니다. 이 접근 방식이 나쁘다는 말은 아닙니다. IMHO 국가 구성 요소가 모든 마법을 수행해야 합니다. 부모는 올바른 매개변수와 함께 사용하는 것에 대해서만 책임을 져야 합니다.
  • 추가 매개변수가 있을 수 있습니다. useFavourite 및 적절한 백엔드 요청을 호출하는 국가 구성 요소의 조건 – 이 구성 요소를 가능한 한 밀폐된 상태로 유지하고 싶습니다. 미래에는 다음과 같은 몇 가지 변경 사항이 있을 수 있습니다. 사용자가 이미 방문한 유럽의 즐겨찾기를 표시합니다. 일부 추가 매개변수를 다시 추가해야 합니다. 이것은 그다지 좋지 않을 것입니다.
  • 국가 구성 요소는 다음과 같이 확장할 수 있습니다. 좋아하는 나라. 이 경우 백엔드를 호출하는 데 사용되는 한 가지 방법을 덮어씁니다. 일반적으로 나는 상속을 사용하는 것을 피하고 싶기 때문에 이것은 단순히 사용하지 않거나 마지막으로 사용하도록 남겨 둘 것입니다.
  • 백엔드를 호출하는 데 사용되는 함수를 전달하는 것이 합리적으로 보입니다.

  • 몇 가지 생각을 한 후, 나는 네 번째 접근 방식인 구성 요소에 함수를 전달하기로 결정했습니다. 고려해야 할 매우 중요한 한 가지는 국가 구성 요소의 이미 종료된 사용을 전혀 변경해서는 안 된다는 것입니다. 즉, 구성 요소에 대한 기본 콜백 호출(모든 국가 가져오기)을 제공해야 합니다. 입력으로 제공된 것이 없을 때 항상 사용됩니다.

    우선 기본 요청 호출에 입력을 제공해야 합니다. 그런 다음 코드에서 하드코딩된 방법을 입력 함수로 지정된 방법으로 변경해야 합니다. 코드에서는 다음과 같습니다.

    import {Component, OnInit} from '@angular/core';
    import {CountryService} from "../services/country.service";
    import {Country} from "../model/country";
    
    export class CountryTableComponent implements OnInit {
    
      countries: Country[] = [];
      @Input() request: () => Observable<Country[]> = 
    this.countryService.getAllCountries;
    
      constructor(private countryService: CountryService) {
      }
    
      ngOnInit(): void {
        this.request().subscribe(data => {
          this.countries = data;
          // any other operations
        }, error => console.log(error));
      }
    }
    


    모든 국가를 사용해야 하는 곳에서 응용 프로그램을 새로 고치면 빈 페이지가 나타납니다.

    나는 무엇이 잘못되었다고 생각 했습니까? 기본 기능을 사용해야 하므로 브라우저에서 문제를 디버깅했습니다. 국가 구성 요소에서 전화가 걸려오는 것을 볼 수 있었기 때문에 서비스를 확인했고 소년은 놀랐습니다. 중단점을 추가했고 이것이 서비스에서 본 것입니다.



    따라서 중단은 국가 서비스에 있지만 'this'는 ... CountryTableComponent를 가리키고 있습니다.

    어떻게 든 범위가 정확하지 않았고 이것이 내 문제였습니다. 약간의 분석과 인터넷 검색 후에 나는 그것에 대한 해결책을 찾았습니다. (API에서) 다음과 같은 bing 메서드를 사용해야 합니다.

    creates a new function that, when called, has its this keyword set to the provided value….



    입력 속성의 정의를 변경했는데 이제 구멍 구성 요소가 다음과 같이 표시됩니다.

    @Component({
      selector: 'app-country-table',
      templateUrl: './country-table.component.html',
      styleUrls: ['./country-table.component.css']
    })
    export class CountryTableComponent implements OnInit {
    
      countries: Country[] = [];
      @Input() request: () => Observable<Country[]> = 
    this.countryService.getAllCountries.bind(this.countryService);
    
      constructor(private countryService: CountryService) {
      }
    
      ngOnInit(): void {
        this.request().subscribe(data => {
          this.countries = data;
          // any other operations
        }, error => console.log(error));
      }
    }
    


    앱을 새로고침했을 때 모든 국가가 올바르게 표시되었습니다.

    즐겨찾는 국가만 표시하고 싶을 때 구성 요소의 사용은 다음과 같습니다.

    <app-country-table
      [request]="getRequest">
    </app-country-table>
    


    그리고 그 정의는

    @Component({
      selector: 'app-favourite-countries',
      templateUrl: './favourite-countries.component.html',
      styleUrls: ['./favourite-countries.component.css']
    })
    export class FavouriteCountriesComponent implements OnInit {
    
      constructor(public countryService: CountryService) { }
    
      ngOnInit(): void {
      }
    
      getRequest():Observable<Country[]>{
        return this.countryService.getFavouritesCountries();
      }
    }
    


    이 구성 요소가 훨씬 더 복잡하다고 상상할 수 있습니다. 나는 미래에 이런 종류의 구현이 약간의 이점을 가져올 것이라고 생각합니다. 누군가가 유용하다고 생각하기를 바랍니다.

    간단한 구현은 here에서 찾을 수 있습니다.


    https://developersmill.com

    좋은 웹페이지 즐겨찾기