Nhận phiên bản dịch vụ mà không cần chèn hàm tạo


81

Tôi có một @Injectabledịch vụ được định nghĩa trong bootstrap. Tôi muốn lấy phiên bản của dịch vụ mà không cần sử dụng hàm tạo. Tôi đã thử sử dụng ReflectiveInjector.resolveAndCreatenhưng điều đó dường như tạo ra một phiên bản mới.

Lý do tôi đang cố gắng làm là tôi có một thành phần cơ sở được tạo ra bởi nhiều thành phần. Bây giờ tôi cần truy cập một dịch vụ nhưng tôi không muốn thêm nó vào ctor vì tôi không muốn đưa dịch vụ vào tất cả các thành phần phái sinh.

TLDR: Tôi cần một ServiceLocator.GetInstance<T>()

CẬP NHẬT: Mã cập nhật cho RC5 +: Lưu trữ phiên bản kim phun để sử dụng trong các thành phần

Câu trả lời:


72

Có, ReflectiveInjector.resolveAndCreate()tạo một phiên bản kim phun mới và chưa kết nối.

Bạn có thể chèn Injectorcá thể Angulars và lấy cá thể mong muốn từ nó bằng cách sử dụng

constructor(private injector:Injector) {
  injector.get(MyService);
}

Bạn cũng có thể lưu trữ biến Injectortrong một số biến toàn cục và sử dụng phiên bản bộ phun này để lấy các phiên bản được cung cấp, ví dụ như được giải thích trong https://github.com/angular/angular/issues/4112#issuecomment-153811572


1
Lưu trữ bộ phun trong một biến toàn cục trong bootstrap.then () giống như những gì tôi cần.
dstr

65
Câu hỏi nói mà không có hàm tạo, điều này làm cho câu trả lời này khá vô ích.
Jonathan Miles

1
Nếu hàm tạo nằm trong một thành phần, thì đó là bộ phun các thành phần, trong một dịch vụ, nó là bộ phun mô-đun (về cơ bản là bộ phun gốc nếu nó không phải là một mô-đun được tải lười biếng). Bạn cũng có thể lấy bộ phun các thành phần mẹ bằng cách thêm @SkipSelf(). Bạn cũng có thể tăng tốc parentgetter, để có được bộ phun gốc.
Günter Zöchbauer

2
@Rhyous ma thuật? Bạn có thể chia sẻ bộ tiêm trong trường tĩnh hoặc biến toàn cục và truy cập nó từ đó, nhưng trước tiên bạn cần đưa nó vào "một nơi nào đó" bằng cách sử dụng một hàm tạo và gán nó cho trường tĩnh.
Günter Zöchbauer

1
Có phải DI container ng sử dụng không tốt, rằng nó thậm chí không hỗ trợ các tính năng cơ bản của DI container thông thường?
Rhyous

61

Trong Angular đã cập nhật nơi sử dụng ngModules, bạn có thể tạo một biến có sẵn ở bất kỳ đâu trong mã:

export let AppInjector: Injector;

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

Bây giờ, bạn có thể sử dụng AppInjectorđể tìm bất kỳ dịch vụ nào ở bất kỳ nơi nào có mã của bạn.

import {AppInjector} from '../app.module';

const myService = AppInjector.get(MyService);

1
Đẹp. Cũng có thể là một câu trả lời hay tại stackoverflow.com/questions/39409328/… .
Arjan

1
Bạn là vua!
Davide Perozzi

Wow chúng tôi được phép làm điều này?
Simon_Weaver

2
Điều này có một vấn đề nhỏ. Bạn phải tạo các kim phun riêng biệt cho các mô-đun tải chậm cung cấp dịch vụ.
Vahid

7

Một cách tiếp cận khác sẽ bao gồm việc xác định trình trang trí tùy chỉnh (một CustomInjectableđể đặt siêu dữ liệu cho chèn phụ thuộc:

export function CustomComponent(annotation: any) {
  return function (target: Function) {

    // DI configuration
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('design:paramtypes', parentTarget);

    Reflect.defineMetadata('design:paramtypes', parentAnnotations, target);

    // Component annotations / metadata
    var annotations = Reflect.getOwnMetadata('annotations', target);
    annotations = annotations || [];
    annotations.push(annotation);
    Reflect.defineMetadata('annotations', annotations, target);
  }
}

Nó sẽ tận dụng siêu dữ liệu từ phương thức khởi tạo mẹ thay vì của chính nó. Bạn có thể sử dụng nó trên lớp con:

@Injectable()
export class SomeService {
  constructor(protected http:Http) {
  }
}

@Component()
export class BaseComponent {
  constructor(private service:SomeService) {
  }
}

@CustomComponent({
  (...)
})
export class TestComponent extends BaseComponent {
  constructor() {
    super(arguments);
  }

  test() {
    console.log('http = '+this.http);
  }
}

Xem câu hỏi này để biết thêm chi tiết:


2
Vấn đề là tsc không cho phép tôi gọi super (đối số) vì các đối số cho hàm tạo cơ sở không khớp.
quốc hội

1
trong đó trường hợp cụ thể chúng tôi chỉ có thể loại bỏ constructor từ lớp có nguồn gốc github.com/Microsoft/TypeScript/issues/12439
slowkot

-1

StoreService .ts

  import { Injectable} from '@angular/core';

    @Injectable()
    export class StoreService {
      static isCreating: boolean = false;
      static instance: StoreService ;

      static getInstance() {
        if (StoreService.instance == null) {
          StoreService.isCreating = true;
          StoreService.instance = new StoreService ();
          StoreService.isCreating = false;
        }
        return StoreService.instance;
      }
      constructor() {
        if (!StoreService.isCreating) {
          throw new Error('You can\'t call new in Singleton instances! Call StoreService.getInstance() instead.');
        }
     }

  MyAlertMethod(){
    alert('hi);
    }
  }

component.ts

//call this service directly in component.ts as below:-

 StoreService.getInstance().MyAlertMethod();

Làm thế nào điều này có thể hoạt động với các dịch vụ yêu cầu các dịch vụ khác được đưa vào hàm tạo?
Emeke Ajeh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.