Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Ivy (8-beta): How to Inject HttpClient into Component?

Tags:

angular

I'm trying to build an example application to test Angular Ivy in combination with Angular Elements, but i can't find any information on how DI should be configured in that setting - since app.module is bypassed.

main.ts:

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

app.module.ts: this is not used by main.ts, so where should HttpClientModule be loaded and custom elements be defined?

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));
    }
}

This results in the following exception:

Error: Injector: NOT_FOUND [HttpClient]

I've read some hints about a 'deps' property for @Component, but it's not found (~8.0.0-beta.8). I tried adding providers: [ { provide: HttpClient } ] to @Component, which throws

Error: Injector: NOT_FOUND [HttpHandler]

providers: [ { provide: HttpClient, deps: [HttpHandler] } ] still throws the same exception.

Where should i configure dependencies when using Ivy? And while at it, where should createCustomElement be called?

I added a github repository with a minimal, complete and verifiable example: https://github.com/markusdresch/ng-ivy-custom-element

EDIT Alright, i got a little further. HttpHandler has to be provided more explicitly (this is in @Component):

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

This way the above errors are gone and it works. However, i'm still not sure how to register the custom element.

like image 492
Markus Dresch Avatar asked Mar 15 '19 14:03

Markus Dresch


People also ask

Where do you inject HttpClient in service file in angular?

Before you can use HttpClient , you need to import the Angular HttpClientModule . Most apps do so in the root AppModule . You can then inject the HttpClient service as a dependency of an application class, as shown in the following ConfigService example.

How does Angular connect to backend?

AJAX enables the communication with the backend / servers without refreshing the page. As AngularJS also used for single page applications. it provides built in support for AJAX communication with server. Create a service where we will create function send http requests to the server.


1 Answers

To answer my own question: It's possible to fire up the root injector in main.ts. It's not that straight forward as @NgModule, because dependencies have to be provided as well:

in 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 });

I haven't really solved creating a custom element like this though, with the exception of this hack:

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

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

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

But this way @Inputs etc have to be routed through manually. I'll keep tinkering and update if i find something more usable.

UPDATE: according to https://juristr.com/blog/2019/05/Angular-8-and-the-Future-NGConf-2019-Roundup/#not-every-app-is-a-spa my attempt is not considered a hack, but the right way to achieve this.

like image 69
Markus Dresch Avatar answered Oct 18 '22 19:10

Markus Dresch