Services & Dependency Injection A great pattern to follow Angular Development SoftUni Team Technical Trainers Software University http://softuni.bg
Table of Contents Dependency Injection Creating custom services The core idea behind DI Creating custom services Making your own injectables The built-in HTTP service Making simple requests
Have a Question? sli.do #angular-js
A great pattern to follow Dependency Injection A great pattern to follow
Dependency Injection Dependency Injection is an important design pattern It's usually called DI by everyone "High-level modules should not depend on low-level modules. Both should depend on abstractions." "Abstractions should not depend on details. Details should depend on abstractions." Agile Principles, Patterns, and Practices in C#
Dependency Injection What is a dependency: Framework Third Party Libraries Database File System Email Random Web Services / HTTP Requests System Resources (Clock) Configuration The new Keyword Static methods
Dependency Injection Traditional Programming High level modules use lower lever modules UI depends on Business Layer Business layer depends on Infrastructure Database Utilities Static methods (Façade for example) Classes instantiated everywhere
Dependency Injection How it should be How to do it Classes should declare what they need Constructors should require dependencies Hidden dependencies should be shown Dependencies should be abstractions How to do it Dependency Injection The Hollywood principle "Don't call us, we'll call you!"
Dependency Injection Constructor injection Dependencies – through constructors Pros Classes self document requirements Works well without container Always valid state Cons Many parameters Some methods may not need everything
Dependency Injection Classic violations How to fix? Using of the new keyword Using static methods/properties How to fix? Default constructor Main method/starting point Inversion of Control container
Dependency Injection Consider this code export class Car { public engine: Engine; public tires: Tires; public description = 'No DI'; constructor() { this.engine = new Engine(); this.tires = new Tires(); } // Method using the engine and tires drive() { return `${this.description} car with ` + `${this.engine.cylinders} cylinders and ${this.tires.make} tires.`;
Dependency Injection Problems in the code The class is brittle, inflexible, and hard to test The Car needs an engine and tires and instantiates them If the Tires or Engine change, the Car class will break Imagine what will happen if you have hundreds of dependencies If you write tests – these dependencies may call external server You have no control over the car's hidden dependencies
Dependency Injection How to fix it? It's easy, add the dependencies to the constructor Then you can create whatever car you want constructor(public engine: Engine, public tires: Tires) { } // Simple car with 4 cylinders and Flintstone tires. let car = new Car(new Engine(), new Tires()); // Super car with 12 cylinders and Flintstone tires. let bigCylinders = 12; let car = new Car(new BigEngine(bigCylinders), new Tires());
Creating Custom Services Suuuuuuper easy!
Creating Custom Services Let's have a data class import { Article } from './article'; export class HomeData { getArticles () : Array<Article> { return [ { title: 'First Title', description: 'First Description' }, { title: 'Second Title', description: 'Second Description' }, { title: 'Third Title', description: 'Third Description' } ]; }
Creating Custom Services And use it in one of our components export class HomeComponent implements OnInit { private homeData: HomeData; articles: Array<Article>; constructor () { this.homeData = new HomeData(); } ngOnInit () { this.articles = this.homeData.getArticles()
Creating Custom Services Let's use DI! First mark the data class as Injectable import { Injectable } from '@angular/core'; import { Article } from './article'; @Injectable() // IMPORTANT: Do not forget the parentheses! export class HomeData { getArticles () : Array<Article> { return [ { title: 'First Title', description: 'First Description' }, { title: 'Second Title', description: 'Second Description' }, { title: 'Third Title', description: 'Third Description' } ]; }
Creating Custom Services Then add it in the providers property of the component It will make the service "injectable" into it and its children import { HomeData } from './home.data'; @Component({ selector: 'home', providers: [HomeData], templateUrl: './home.component.html' }) export class HomeComponent implements OnInit { … }
Creating Custom Services Finally, add a constructor property and "inject" it there export class HomeComponent implements OnInit { articles: Array<Article>; constructor (private homeData: HomeData) { } ngOnInit () { this.articles = this.homeData.getArticles() }
Creating Custom Services If you want, you can make the service available globally Just inject it into the module import { HomeData } from './home/home.data'; @NgModule({ declarations: [ AppComponent, HomeComponent ], imports: [ BrowserModule ], providers: [HomeData], bootstrap: [AppComponent] }) export class AppModule { }
The Built-in HTTP Service Making HTTP Requests
The Built-in HTTP Service First import the HttpModule import { HttpModule } from '@angular/http'; @NgModule({ declarations: [ AppComponent, HomeComponent ], imports: [ BrowserModule, HttpModule providers: [HomeData], bootstrap: [AppComponent] }) export class AppModule { }
The Built-in HTTP Service Then use it in your data class import { Injectable } from '@angular/core'; import { Http } from '@angular/http'; import 'rxjs/add/operator/toPromise'; const url: string = 'http://some.url'; @Injectable() export class HomeData { constructor (private http: Http) { } getData () : Promise<Array<MyDataClass>> { return this.http .get(url) .toPromise() .then(resp => resp.json() as MyDataClass[]) .catch(err => { console.log(err); return []}); }
The Built-in HTTP Service The Http service returns Observable object which we convert to a plain old Promise Observables are more advanced and powerful ways to deal with streams of data You can read more here: https://angular.io/tutorial/toh-pt6#observables
JavaScript Web – Angular Fundamentals https://softuni.bg/courses/angular-2-fundamentals © Software University Foundation – http://softuni.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.
License This course (slides, examples, demos, videos, homework, etc.) is licensed under the "Creative Commons Attribution- NonCommercial-ShareAlike 4.0 International" license Attribution: this work may contain portions from "End-to-end JavaScript Applications" course by Telerik Academy under CC-BY-NC-SA license © Software University Foundation – http://softuni.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.
Free Trainings @ Software University Software University Foundation – softuni.org Software University – High-Quality Education, Profession and Job for Software Developers softuni.bg Software University @ Facebook facebook.com/SoftwareUniversity Software University @ YouTube youtube.com/SoftwareUniversity Software University Forums – forum.softuni.bg © Software University Foundation – http://softuni.org This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike license.