sourcecode

@Input()에 기반한 Angular 2 동적 종속성 주입

copyscript 2023. 7. 13. 21:01
반응형

@Input()에 기반한 Angular 2 동적 종속성 주입

Angular 2 성분 지침이 있다고 가정합니다. 여기서 성분이 사용하는 주입된 종속성이 @Input()에 의해 결정되기를 원합니다.

저는 다음과 같은 것을 쓰고 싶습니다.<trendy-directive use="'serviceA'">그리고 트렌디 디렉티브의 인스턴스가 A 서비스를 사용하도록 하거나, 만약 그것이 내가 지정한 것이라면 B 서비스를 사용하도록 합니다.(이것은 제가 실제로 하려고 하는 것을 지나치게 단순화한 버전입니다.)

(처음에 이것이 좋지 않은 생각이라고 생각하신다면, 저는 그 피드백에 동의합니다. 하지만 그 이유를 설명해 주십시오.)

여기 제가 생각하는 것을 성취하는 방법의 한 가지 예가 있습니다.이 예에서 서비스 A와 서비스 B가 모두 '슈퍼 쿨 기능'을 통해 iService를 구현하는 주입식이라고 상상해 보십시오.

@Component({
    selector: 'trendy-directive',
    ...
})
export class TrendyDirective implements OnInit {
    constructor(
        private serviceA: ServiceA,
        private serviceB: ServiceB){}

    private service: iService;
    @Input() use: string;

    ngOnInit() {
        switch (this.use){
            case: 'serviceA': this.service = this.serviceA; break;
            case: 'serviceB': this.service = this.serviceB; break;
            default: throw "There's no such thing as a " + this.use + '!';
        }
        this.service.superCoolFunction();
    }
}

저는 이것이 기술적으로 효과가 있을 것이라고 생각하지만, 동적 의존성 주입을 하는 더 나은 방법이 있을 것입니다.

그렇다.

// can be a service also for overriding and testing
export const trendyServiceMap = {
  serviceA: ServiceA,
  serviceB: ServiceB
}

constructor(private injector: Injector) {}    
...
ngOnInit() {
    if (trendyServiceMap.hasOwnProperty(this.use)) {
        this.service = this.injector.get<any>(trendyServiceMap[this.use]);
    } else {
        throw new Error(`There's no such thing as '${this.use}'`);
    }
}

일반적으로 동일한 접근 방식은 Angular2 설명서에 설명되어 있습니다.인젝터 구성 요소

@Component({
    providers: [Car, Engine, Tires, heroServiceProvider, Logger]
})
export class InjectorComponent {
     car: Car = this.injector.get(Car);
     heroService: HeroService = this.injector.get(HeroService);
     hero: Hero = this.heroService.getHeroes()[0];

     constructor(private injector: Injector) { }
}

주입해야 합니다.Injector생성자에서 모든 서비스 나열providers의 재산.@Component주석그러면 할 수 있습니다.injector.get(type),어디에type에서 해결됩니다.@Input문서에 따르면,Service요청하기 전까지는 실제로 주입되지 않습니다..get()).

이름을 배열 개체로 선언할 필요 없이 Estus Flask의 답변을 한 단계 더 진행하여 서비스를 가져오는 논리를 만들고 싶습니다.

기본적으로, 우리는 그냥 지나치면 됩니다.path그리고.name서비스와 나머지는 거의 같습니다.

public _dynamicService: any;

dynamicDI(service_path, service_name){
    import(service_path).then(s => {

      this._dynamicService = this.injector.get<any>(s['service_name']);

    })
}

이제 내부의 기능에 액세스할 수 있습니다.dynamicService다음과 같이:

(필요한 서비스에 http 관찰 가능한 fn이 있다고 가정합니다.)

this._dynamicService['your_function_name']().subscribe(res=> { console.log(res) } );

여기 약간 복잡하지만 매력적으로 일하는 방법이 있습니다!

공유 모듈 및 다중 사용자 지정 구현에서 기본 검색 서비스를 설정합니다.그리고 가능한 모든 구현을 명시적으로 참조할 필요가 없습니다.

인터페이스 및 기본 구현

export interface ISearch {
    searchByTerm(textInput: string);
}

export class DefaultSearch implements ISearch {
    searchByTerm(textInput: string) { console.log("default search by term"); }
}

Injection을 사용하여 서비스 구현 목록 생성상품권

 // Keep list of token, provider will give a implementation for each of them
 export const SearchServiceTokens: Map<string, InjectionToken<ISearch>> = new Map();
 // Add File service implementation token
 SearchServiceTokens.set('default', new InjectionToken<ISearch>('default'));

기본 서비스 구현을 위한 공급자

   providers: [
      ...
      // Default implementation service
      {
         provide: SearchServiceTokens.get('default'),
         useClass: DefaultSearch
      }
   ]

사용자 정의 구현(다른 모듈에 있을 수 있음)

export class Component1Search implements ISearch {
    searchByTerm(textInput: string) { console.log("component1 search by term"); }
}

사용자 정의 구현을 위한 토큰 추가

SearchServiceTokens.set('component1', new InjectionToken<ISearch>('component1'));

공급자 추가

   providers: [
      ...
      // Other implementation service
      {
         provide: SearchServiceTokens.get('component1'),
         useClass: Component1Search
      }
   ]

마지막으로, 당신의 구성 요소에서

    @Input() useService;
    searchService: ISearch;

    constructor(private injector: Injector) {
       // Use default if none provided
       let serviceToUse = 'default';
       if (null !== this.useService) { serviceToUse = this.useService; }
       this.searchService = this.injector.get(SearchServiceTokens.get(serviceToUse));
    }

Inject in @angular/core module이라는 서비스가 있습니다.@Inject를 사용하면 대체 주입 방법을 얻을 수 있습니다.그러나 이것은 시공자에서만 가능합니다.

따라서 구성요소의 입력을 @구성요소 장식자의 입력 배열에 넣은 다음(클래스 내에서 @입력 장식자를 사용하지 않음) 해당 입력 변수를 생성자에 주입해야 합니다.

너무 늦었을 수도 있지만 어떤 상황에서 동적 주입을 위한 흥미롭고 깔끔한 해결책이 있을 수 있습니다.주요 아이디어는 서비스 래퍼를 사용하고 필요한 서비스의 적절한 인스턴스를 가져오기 위한 메소드 또는 게터를 추가하는 것입니다.

@Injectable({
    providedIn: 'root',
})
export class CredentialsServiceImp {      
    constructor(           
        private visitorService: VisitorCredentialsServiceImp,
        private employeeService: EmployeeCredentialsServiceImp
    ) {

    }
    instance(userType:UserType): UserCredentialsService {
        return userType == UserType.employee ? this.employeeService : this.visitorService;
    }

}

모두 및 사용자 CredentialsService를 합니다.instancegetter는 조건에 따라 적절한 인스턴스로 얻어집니다.사용자 구성 요소에서 사용

export class Component implements OnInit {
      @Input() userType : UserType;    
    constructor(           
        private credentials: CredentialsServiceImp  
    ) {
        
    }

     ngOnInit():  {
      const service = this.credentials.instance(this.userType);
    }  
   
   
}

언급URL : https://stackoverflow.com/questions/41366108/angular-2-dynamic-dependency-injection-based-on-input

반응형