Angular Ivy (8-бета): Как внедрить HttpClient в компонент?

#angular

#angular

Вопрос:

Я пытаюсь создать пример приложения для тестирования Angular Ivy в сочетании с элементами Angular, но я не могу найти никакой информации о том, как DI следует настраивать в этом параметре, поскольку app.module обходится.

main.ts:

 import { ɵrenderComponent as renderComponent } from '@angular/core';
import { AppComponent } from './app/app.component';
renderComponent(AppComponent);
  

app.module.ts: это не используется main.ts, так где должен быть загружен HttpClientModule и определены пользовательские элементы?

 import { NgModule, Injector } from '@angular/core';
import { HttpClientModule } from '@angular/common/http/http';
import { createCustomElement } from '@angular/elements';

import { AppComponent } from 'src/app/app.component';

@NgModule({
    declarations: [ AppComponent ],
    imports: [ HttpClientModule ],
    entryComponents: [AppComponent]
})
export class AppModule {
    constructor(private injector: Injector) { }

    ngDoBootstrap() {
        customElements.define('app-component',
            createCustomElement(AppComponent, { injector: this.injector }));
    }
}
  

app.component.ts:

 import { Component, ChangeDetectionStrategy, ViewEncapsulation, Input } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject } from 'rxjs';

@Component({
  selector: 'app-component',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.ShadowDom,
})
export class AppComponent {
    constructor(private http: HttpClient) {
        http.get<any>('someurl').subscribe(data => console.log(data));
    }
}
  

Это приводит к следующему исключению:

Ошибка: Инжектор: NOT_FOUND [HttpClient]

Я прочитал несколько подсказок о свойстве ‘deps’ для @Component, но оно не найдено (~ 8.0.0-бета.8). Я попытался добавить providers: [ { provide: HttpClient } ] в @Component, который выдает

Ошибка: Инжектор: NOT_FOUND [HttpHandler]

providers: [ { provide: HttpClient, deps: [HttpHandler] } ] по-прежнему выдает то же исключение.

Где я должен настроить зависимости при использовании Ivy? И при этом, куда следует createCustomElement вызывать?

Я добавил репозиторий github с минимальным, полным и проверяемым примером:https://github.com/markusdresch/ng-ivy-custom-element

РЕДАКТИРОВАТЬ Хорошо, я продвинулся немного дальше. HttpHandler должен быть предоставлен более явно (это в @Component):

   providers: [
    { provide: HttpClient, deps: [ HttpHandler ] },
    { provide: HttpHandler, useValue: new HttpXhrBackend({ build: () => new XMLHttpRequest() }) },
    // ...
  ]
  

Таким образом, вышеуказанные ошибки устранены, и это работает. Однако я все еще не уверен, как зарегистрировать пользовательский элемент.

Комментарии:

1. Мне также любопытно, как бы вы использовали другой вложенный компонент angular… никаких блоков объявления, верно?

Ответ №1:

Чтобы ответить на мой собственный вопрос: можно запустить корневой инжектор в main.ts. Это не так просто, как @NgModule, потому что также должны быть предоставлены зависимости:

в main.ts:

 const injector: Injector = Injector.create({
  name: 'root',
  providers: [
    { provide: HttpClient, deps: [ HttpHandler ] },
    { provide: HttpHandler, useValue: new HttpXhrBackend({ build: () => new XMLHttpRequest() }) },
  ]
});

renderComponent(AppComponent, { injector: injector });
  

На самом деле я так и не решил проблему создания пользовательского элемента, подобного этому, за исключением этого взлома:

 class AppComponentCustomElement extends HTMLElement {
  constructor() {
    super();

    renderComponent(AppComponent, { injector: injector });
  }
}

customElements.define('ng-ivy-custom-element', AppComponentCustomElement);
  

Но таким образом @Inputs и т.д. Должны быть перенаправлены вручную. Я продолжу дорабатывать и обновлять, если найду что-то более полезное.

ОБНОВЛЕНИЕ: в соответствии с https://juristr.com/blog/2019/05/Angular-8-and-the-Future-NGConf-2019-Roundup/#not-every-app-is-a-spa моя попытка не считается взломом, но это правильный способ добиться этого.

Ответ №2:

Чтобы обеспечить зависимости модуля в любом компоненте, определите модуль в том же файле компонента, как показано ниже.

 @NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    CommonModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}
  

Здесь ivy renderer разрешите HttpClient из модуля приложения.