서비스를 클래스에 주입하는 방법 (컴포넌트가 아님)


88

컴포넌트아닌 클래스에 서비스를 삽입하고 싶습니다 .

예를 들면 :

Myservice

import {Injectable} from '@angular/core';
@Injectable()
export class myService {
  dosomething() {
    // implementation
  }
}

내 수업

import { myService } from './myService'
export class MyClass {
  constructor(private myservice:myService) {

  }
  test() {
     this.myservice.dosomething();
  }
}

이 솔루션은 작동하지 않습니다 ( MyClass아직 인스턴스화되지 않았기 때문에 생각합니다 ).

구성 요소가 아닌 클래스에서 서비스를 사용하는 다른 방법이 있습니까? 아니면 내 코드 디자인이 부적절하다고 생각하십니까 (컴포넌트가 아닌 클래스에서 서비스를 사용하는 것)?

감사합니다.

답변:


56

주입은 Angulars DI (종속성 주입)에 의해 인스턴스화 된 클래스에서만 작동합니다.

  1. 당신은
    • 추가 @Injectable()MyClass
    • 제공 MyClass과 같은 providers: [MyClass]구성 요소 또는 NgModule있다.

그런 다음 MyClass어딘가에 주입하면 DI에 의해 인스턴스화 될 때 MyService인스턴스가 전달됩니다 MyClass(처음 주입되기 전).

  1. 다른 방법은 다음과 같은 사용자 지정 인젝터를 구성하는 것입니다.
constructor(private injector:Injector) { 
  let resolvedProviders = ReflectiveInjector.resolve([MyClass]);
  let childInjector = ReflectiveInjector.fromResolvedProviders(resolvedProviders, this.injector);

  let myClass : MyClass = childInjector.get(MyClass);
}

이 방법 myClassMyClassAngulars DI에 의해 인스턴스화 된 인스턴스가되고 인스턴스화 myService될 때 주입됩니다 MyClass. 지시문 내에서 수동으로 Injector에서 종속성 가져 오기를
참조하십시오.

  1. 또 다른 방법은 인스턴스를 직접 만드는 것입니다.
constructor(ms:myService)
let myClass = new MyClass(ms);

2
독립형 클래스에 서비스를 주입하는 것은 안티 패턴이라고 생각합니다.
tomexx

11
물론입니다.하지만 때로는 여전히 의미가 있으며 무엇이 가능한지 아는 것이 항상 좋습니다.
Günter Zöchbauer 2017 년

생성자에서 새 인젝터를 만드는 이유는 무엇입니까? 주입 된 것을 사용하지 않겠습니까? 당신은 새로 만들려고하는 경우 다음 중 하나가 처음에 주입해야 할 이유가 없다
smac89

새로운 것은 추가 공급자가있는 어린이 주입기입니다. 자식 인젝터에 추가 된 공급자가 부모 구성 요소 또는 모듈 수준에서 제공되는 공급자에 의존하는 경우 DI는 모든 것을 자동으로 해결할 수 있습니다. 따라서 이것이 의미있는 상황이 분명히 있습니다.
Günter Zöchbauer

1
@TimothyPenz 편집에 감사드립니다. 이 예에서,이 private때문에, 불필요 injector하므로 필드 참조를 유지할 필요가없는 생성자 밖에 사용하지 않는 것은 아니다.
Günter Zöchbauer 2017 년

29

질문에 대한 직접적인 대답은 아니지만이 글을 읽는다면 도움이 될 수 있습니다.

당신이 사용하고 있다고 가정 해 봅시다. ng2-translate를 사용 하고 있고 당신의 User.ts수업에 정말로 그것을 원한다고 . DI를 사용하여 삽입하는 것이 즉각적인 생각이며 결국 Angular를 수행하고 있습니다. 그러나 그것은 지나치게 생각하는 것입니다. 생성자에 전달하거나 구성 요소에서 설정 한 공용 변수로 만들 수 있습니다 (아마도 DI를 수행 한 위치).

예 :

import { TranslateService } from "ng2-translate";

export class User {
  public translateService: TranslateService; // will set from components.

  // a bunch of awesome User methods
}

그런 다음 TranslateService를 주입 한 일부 사용자 관련 구성 요소에서

addEmptyUser() {
  let emptyUser = new User("", "");
  emptyUser.translateService = this.translateService;
  this.users.push(emptyUser);
}

바라건대 이것은 우리가 때때로 너무 영리하기 때문에 코드를 유지하기가 훨씬 더 어려운 저 같은 사람들에게 도움이되기를 바랍니다 =]

(참고 : 생성자 메서드의 일부로 만드는 대신 변수를 설정하려는 이유는 서비스를 사용할 필요가없는 경우가있을 수 있으므로 항상 전달해야한다는 것은 추가 가져 오기를 도입하는 것을 의미합니다. / 실제로 사용되지 않는 코드)


어쩌면 만들 translateService가 GET / SET get당신이 그것을 설정하는 것을 잊었다 경우 NullReference 예외 대신 의미있는 오류가 발생합니다
Simon_Weaver

1
클래스 생성자에서 translateService를 필수 매개 변수로 만드는 것이 더 합리적일까요? 이 패턴은 DI 패턴 imho와 더 일치합니다.
Icycool

15

이것은 일종의 ( 매우 ) 해키이지만 내 솔루션도 공유 할 것이라고 생각했습니다. Singleton 서비스 (컴포넌트가 아닌 앱 루트에 주입 됨) 에서만 작동 합니다. 애플리케이션만큼 오래 살며 인스턴스가 하나뿐이기 때문입니다.

첫째, 서비스에서 :

@Injectable()
export class MyService {
    static instance: MyService;
    constructor() {
        MyService.instance = this;
    }

    doSomething() {
        console.log("something!");
    }
}

그런 다음 모든 수업에서 :

export class MyClass {
    constructor() {
        MyService.instance.doSomething();
    }
}

이 솔루션은 코드 혼란을 줄이고 어쨌든 비 단일 서비스를 사용하지 않는 경우에 좋습니다.


그러나 생성자에서 선언하지 않고 MyClass에서 MyService를 어떻게 사용합니까?
Akhil V

@AkhilV 다른 클래스를 가져 오는 것처럼 MyService를 가져 오면 설명 된대로 직접 메소드를 호출 할 수 있습니다.
킬 베스

13

locator.service.ts

import {Injector} from "@angular/core";

export class ServiceLocator {
    static injector: Injector;
}

app.module.ts

@NgModule({ ... })

export class AppModule {
    constructor(private injector: Injector) {
        ServiceLocator.injector = injector;
    }
 }

poney.model.ts

export class Poney {

    id: number;
    name: string;
    color: 'black' | 'white' | 'brown';

    service: PoneyService = ServiceLocator.injector.get(PoneyService); // <--- HERE !!!

    // PoneyService is @injectable and registered in app.module.ts
}

1
OP 시나리오의 모범 사례가 무엇인지 확실하지 않지만이 답변은 주요 답변보다 훨씬 간단 해 보입니다. injector.get()호출을 모듈 로 이동하면 작동합니까 (상태 비 저장 서비스를 가정하여 여러 클래스가 동일한 인스턴스를 "공유"할 수 있다고 가정)?
G0BLiN

나는 코드가 동일한 poney 서비스 인스턴스를 공유하는 모든 poney 인스턴스에 의해 끝날 것이라고 생각합니다. 어떻게 생각해?
Julien

Julien-내 시나리오에서 허용 가능한 결과 (실제로 선호되는 결과)입니다. 입력 유효성 검사기, 사용자 권한 처리기 또는 현지화 서비스와 같은 것을 생각해보십시오. 앱 전체에 동일한 기능이 필요하지만 각각에 대해 고유 한 인스턴스가 필요하지 않습니다. 서비스의 개별 소비자.
G0BLiN

3

서비스 메서드가 순수 함수 인 경우이를 해결하는 깨끗한 방법은 서비스에 정적 멤버를 포함하는 것입니다.

당신의 서비스

import {Injectable} from '@angular/core';
@Injectable()
export class myService{
  public static dosomething(){
    //implementation => doesn't use `this`
  }
}

당신의 수업

export class MyClass{
  test(){
     MyService.dosomething(); //no need to inject in constructor
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.