Angular 6 Sharing Service… or not…

Different ways to share Service instance in Angular 6.

Service instance shared across entire application.

  • Declare `providedIn: ‘root’` property of `@Injectable` decorator in the Service. Then inject service to component’s constructor as usual.
  • import { Injectable } from '@angular/core';
    
    @Injectable({
      providedIn: 'root'
    })
    export class Service1Service {
      constructor() {
      }
    }
    
  • Declare service in `providers` property of `@NgModule` decorator in highest module (Ie: app.module.ts). Then inject service to component’s constructor as usual.
  • app.module.ts

    @NgModule({
        declarations: [...],
        imports: [...]
        providers: [Service1Service]
    })
    

Service instance shared across module.
Declare service in `providers` property of `@NgModule` decorator in any module except the highest module (Ie: user.module.ts, order.module.ts, etc). Then inject service to component’s constructor as usual.

user.module.ts

@NgModule({
    declarations: [...],
    imports: [...]
    providers: [Service1Service]
})

Service instance in every single component (not shared).
Declare service in `providers` property of `@Component` decorator in any component. Then inject service to component’s constructor as usual.

component1.component.ts

import { Component } from '@angular/core';
import { Service1Service } from '../service1.service';

@Component({
  selector: 'app-component1',
  templateUrl: './component1.component.html',
  styleUrls: ['./component1.component.css'],
  providers: [Service1Service]
})
export class Component1Component {
  constructor(private service1: Service1Service) {
  }
}

Angular 6 Custom Elements’ Properties

If you are not familiar with Angular custom elements, read my previous post.

Here is tips on how to expose properties from your custom element so the user can do something like this:

<body>
  <fooComponent></fooComponent>

  <script>
    if (document.readyState === 'complete') {
      document.querySelector('fooComponent').value = 'i am value-able';
      document.querySelector('fooComponent').fooProp = 'i am foo prop';

      console.log(document.querySelector('fooComponent').value);
      console.log(document.querySelector('fooComponent').fooProp);
    }
  </script>
</body>

First, this is our custom component, same setup as my previous post.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, Injector } from '@angular/core';
import { createCustomElement } from '@angular/elements';

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

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ]
  entryComponents: [
    AppComponent
  ]
})
export class AppModule {
  constructor(private injector: Injector) {
    let customComponent = createCustomElement(AppComponent, { injector });
    window.customElements.define('fooComponent', customComponent);
  }

  ngDoBootstrap() {
  }
}

And how to expose properties.

app.component.ts

import { Component, Input, SimpleChanges } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  // Element's properties to expose
  @Input() value: string;
  @Input() fooProp: string;

  // Track changes of the properties
  ngOnChanges(changes: SimpleChanges): void {
    console.log(changes.value.currentValue);
    console.log(changes.fooProp.currentValue);
  }
}

Note here, though we use Angular’s Input directive, it also allow user to modify property value, so it’s important to validate before using it.

That’s it. Simple.