Внедренный сервис не определен прямо в конструкторе

К сведению, я совершенно не связан с Angular (1 или 2 в этом отношении).

Я пытаюсь написать "супер" слой Http, чтобы избежать необходимости помещать одинаковые заголовки везде.

import {Http, ConnectionBackend, RequestOptions, Response, Headers} from '@angular/http';
import {Observable} from 'rxjs';
import {LoadingService} from "../../services/loading.service";

export class HttpLoading extends Http {
    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions,
        private _ls: LoadingService )
    {
        super(backend, defaultOptions);
    }

    getPostPutHeader() {
        var authHeader = new Headers();
        authHeader.append("Authorization", "Bearer "+ localStorage.getItem('token') );
        authHeader.append('Content-Type', 'application/json');
        return authHeader;
    }

    post(url: string, data:any):Observable<Response> {
        this._ls.isLoading = true; // Exception here: this._ls is undefined
        return super.post(url, data, { headers: this.getPostPutHeader() })
            .map(res => {
                this._ls.isLoading = false;
                return res;
            });
    }
}

И сервис, чтобы сказать, когда запрос выполняется; это вводится в вышеупомянутый класс HttpLoading.

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

@Injectable()
export class LoadingService {
    isLoading: boolean = false;
}

У меня есть куча вещей в моей начальной загрузке, включая HttpLoading, LoadingService и ConnectionBackend (для этого последнего я получаю исключение, если его здесь нет).

bootstrap(AppComponent, [
    ConnectionBackend,
    HttpLoading,
    APP_ROUTER_PROVIDERS,
    HTTP_PROVIDERS,
    LoadingService,
    disableDeprecatedForms(),
    provideForms()
])

Проблема в том, что первый раз звоню HttpLoading"s post метод (в еще одном сервисе), я получаю исключение в this._ls.isLoading, так как this._ls не определено, и я не могу понять, почему.

Пожалуйста, скажите мне, если вам нужна дополнительная информация.


редактировать

LoadingService правильно вводится в моем AppComponent (главный компонент).

//imports
//@Component
export class AppComponent {
    requesting:boolean = false;

    constructor(public authService: AuthService, private router: Router, private _ls: LoadingService) {
    }

    navigate(route:string) {
        this._ls.isLoading = true;
        this.router.navigate([route])
            .then(() => this._ls.isLoading = false);
    }
}

Потенциальное решение

Похоже, что ваши публичные / приватные параметры должны быть на первом месте в списке. Я позволю кому-то более опытному, чем я, объяснить, почему, хотя...

export class HttpLoading extends Http {

    constructor(private _ls: LoadingService, backend: ConnectionBackend, defaultOptions: RequestOptions) {
        super(backend, defaultOptions);
}

3 ответа

Я бы настроил ваш HttpLoading Классифицируйте этот способ в поставщиках при загрузке вашего приложения:

bootstrap(AppComponent, [
  (...)
  HTTP_PROVIDERS,
  {
    provide:Http,
    useFactory: (backend: XHRBackend, defaultOptions: RequestOptions, loadingService: LoadingService) => {
      return new HttpLoading(backend, defaultOptions, loadingService);
    },
    deps: [XHRBackend, RequestOptions, LoadingService]
  }
]);

Причина этого в том, что вы хотите использовать свой собственный класс для провайдера Http. Вам нужно изменить класс за провайдером Http вашим HttpLoading учебный класс. Будьте осторожны, чтобы определить его после HTTP_PROVIDERS,

Чтобы иметь возможность внедрить экземпляр XHRBackend к вашему классу, вы должны использовать useFactory...

Хорошо, я знаю, что это может показаться тривиальным, но попробуйте создать переменную и инициализировать ее в конструкторе

Чтобы расширить ответ @Thierry Templier. Я использую Angular v4, и мой опыт показывает, что вам нужно предоставить ВСЕ зависимости, которые нужны вашему расширяющему конструктору, И в правильном порядке - я полагаю, это устаревший способ сделать это, начиная с angular 1.x.

Мой пример:

// Это мой расширенный класс (только соответствующая часть)

@Injectable()
export class HttpService extends Http {

    constructor(
        backend: ConnectionBackend,
        defaultOptions: RequestOptions,

        private router: Router,
        private loaderService: LoaderService,
        private modalService: ModalService,
        private localStorageService: LocalStorageService
    )
    {
        super(backend, defaultOptions)
    }

// Это фабрика провайдеров, определенная в app.module.ts:

export function httpClientFactory(
        backend: XHRBackend,
        defaultOptions: RequestOptions,
        router: Router,
        loaderService: LoaderService,
        modalService: ModalService,
        localStorageService: LocalStorageService
    ) : Http
{
    return new HttpService(
        backend,
        defaultOptions,
        router,
        loaderService,
        modalService,
        localStorageService
    );
}

Это конфигурация (только что оставленная соответствующая часть) в app.module.ts:

providers: [
    ModalService
    LocalStorageService,
    LoaderService,
    {
        provide: HttpService,
        useFactory: httpClientFactory,
        deps: [XHRBackend, RequestOptions, Router, LoaderService, ModalService, LocalStorageService]
    }

Примечание: обратите внимание на порядок объявления deps в конфиге по сравнению с конструктором фабрики.. это то же самое

Другие вопросы по тегам