In Angular, concrete and runtime version of a dependency is provided by a provider. This dependency value(object) are then injected into components and services by injector. Therefore dependency need to be configured within providers otherwise injector will not be able to inject it. The configuration of Provider is via providers metadata. @NgModule() decorator as well as @Component() decorator contains providers metadata.
NgModule.providers
NgModule.providers are configured providers of @NgModule() decorator within module. Whenever providers configures a dependency(service) in application module then for all the components which are configured in declarations metadata of the @NgModule() decorator, the configured service will be available for dependency injection.
Example :-
Consider a service "sharedservice"
import { Injectable } from '@angular/core';
@Injectable()
export class sharedservice {
value: string;
}
Consider two components parent and child component.
ChildComponent
import { Component, OnInit } from '@angular/core';
import { sharedservice } from '../services/shared.service';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
constructor(private service: sharedservice) { } // instance of sharedservice is injected in constructor
ngOnInit() {
}
}
child.component.html
<div class="child">
<p>Child</p>
{{ service.value }}
</div>
Above ChildComponent html is just rendering the value of "value" property of sharedservice.
ParentComponent
import { Component, OnInit } from '@angular/core';
import { sharedservice } from '../services/shared.service';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
})
export class ParentComponent implements OnInit {
constructor(private service: sharedservice) { } // instance of sharedservice is injected in constructor
ngOnInit() {
}
}
parent.component.html
<div class="parent">
<p>Parent</p>
<form novalidate>
<div class="form-group">
<input type="text" class="form-control" name="value" [(ngModel)]="service.value">
</div>
</form>
<app-child></app-child>
</div>
parent.component.html consist of an input box which is by using two way ngModel binding is reading and writing to value property of sharedservice.The ChildComponent is rendered inside ParentComponent
Consider a root component "app"
AppComponent
import { Component} from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html'
})
export class AppComponent{
}
app.component.html
<div class="container">
<div class="row">
<div class="col-xs-4">
<app-parent></app-parent>
</div>
<div class="col-xs-4">
<app-parent></app-parent>
</div>
</div>
</div>
Two instances of ParentComponent "app-parent" are rendered side by side inside root component.
App.module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { ParentComponent } from './parent/parent.component';
import { ChildComponent } from './child/child.component';
import { sharedservice } from './services/shared.service';
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [
AppComponent,
ParentComponent,
ChildComponent
],
imports: [
BrowserModule,
FormsModule,
],
providers: [sharedservice], //providers on NgModule
bootstrap: [AppComponent]
})
export class AppModule { }
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AngularDemo</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<app-root></app-root>
</body>
</html>
When above application runs
Output :-
Exaplanation :-
In above example root NgModule is the root injector since the service is injected into it through providers property. Therefore, the service dependency is resolved by only one injector, whenever a request of an instance of sharedservice to be injected to one of component is made, it is always the injection of same instance. Above output is obtained since same instance of sharedservice is used everywhere, any changes made to input control in one of parent.component.html automatically changes other input control and the child components. Configuration of providers into NgModule is sharing of one instance into entire application.
Component.providers
Component.providers are configured providers of @Component() decorator within component. Configuration of a service within a component providers metadata allows service availability for dependency injection in current component and its children components up to the bottom component. It is configuration of "sharedservice" through providers property on ParentComponent.
ParentComponent is chaged to following
import { Component, OnInit } from '@angular/core';
import { sharedservice } from '../services/shared.service';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
providers: [sharedservice]
})
export class ParentComponent implements OnInit {
constructor(private service: sharedservice) { }
ngOnInit() {
}
}
When above application runs
Output :-
Explanation :
In above output whenever we type in input control of one instance of ParentComponent make changes to only to its child components. Changes are not made to input control of other instance of ParentComponent and its child components since every ParentComponent has its own child injector with configuration of sharedservice i.e each instance of ParentComponent has separate instance of sharedservice the state of sharedservice is only shared between a ParentComponent and it’s child components not shared globally.
Component.viewProviders
Component.viewProviders are similar to Component.providers with the only difference that configured service will be available only in current component and its view children not in component content children.
Following changes are made :-
ParentComponent
import { Component, OnInit } from '@angular/core';
import { sharedservice } from '../services/shared.service';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css'],
viewProviders: [sharedservice] //component viewprovider
})
export class ParentComponent implements OnInit {
constructor(private service: sharedservice) { }
ngOnInit() {
}
}
parent.component.html
<div class="parent">
<p>Parent</p>
<form novalidate>
<div class="form-group">
<input type="text" class="form-control" name="value" [(ngModel)]="service.value">
</div>
</form>
<ng-content></ng-content> //content child
</div>
app.component.html
<div class="container">
<div class="row">
<div class="col-xs-4">
<app-parent><app-child></app-child></app-parent>
</div>
<div class="col-xs-4">
<app-parent><app-child></app-child></app-parent>
</div>
</div>
</div>
When above application runs
Output:-
Exaplanation :-
In above example ChildComponent now behave as content children instead of view children. Component whenever uses viewProviders property, an injector is created by component which can only be shared between component and its view children and not to its content children.
0 Comment(s)