
Squeeze Angular - the leading framework for dynamic JavaScript applications - everything. Adam Freeman begins with a description of MVC and its advantages, then shows how to effectively use Angular, covering all stages, starting with the basics and up to the most advanced features that lie in the depths of this framework.
Each topic is presented clearly and concisely, provided with a large number of details that will allow you to become really effective. The most important features are given without unnecessary details, but contain all the necessary information so that you can bypass all the pitfalls.
about the author
Adam Freeman is an experienced IT professional who has held senior positions in many companies. Until recently, he served as technical director and chief engineer in one of the largest banks. Now Adam devotes his time mainly to writing books and running long distances.
About science editor
Fabio Claudio Ferracchiati (Fabio Claudio Ferracchiati) is a senior consultant and lead analyst / developer with experience in using Microsoft technologies. He works at BluArancio (www.bluarancio.com). Fabio is a certified .NET software developer, a certified .NET application developer, a Microsoft-certified professional, a prolific writer and scientific editor. Over the past 10 years, he has written a number of articles for Italian and international journals and has participated in writing more than 10 books on various computer topics.
')
Angular project preparation
Update root component
Let's start with the root component - the Angular structural block that will control the app element in an HTML document. An application may contain several components, but among them there is always a root component responsible for displaying top-level content. Edit the app.component.ts file in the SportsStore / src / app folder and include the code in Listing 7.5.
Listing 7.5. The contents of the app.component.ts file in the SportsStore / src / app folder
import { Component } from "@angular/core"; @Component({ selector: "app", template: `<div class="bg-success pa-1 text-xs-center"> This is SportsStore </div>` }) export class AppComponent { }
The
Component decorator tells Angular that the AppComponent class is a component, and its properties describe the use of this component. The full set of component properties is given in Chapter 17, but the three properties listed in the listing are basic and often used in practice. The selector property tells Angular how the component should be used in the HTML document, and the template property determines the content to be displayed by the component. Components can define embedded templates, as in this case, or use external HTML files that simplify the management of complex content.
The AppComponent class does not contain code, because the root component in the Angular project exists only to manage the content displayed to the user. At the initial stage, we will manage the content displayed by the root component manually, but in Chapter 8 a URL routing mechanism will be introduced to automatically adapt the content depending on the user's actions.
Update root module
Angular modules fall into two categories: functional modules and root module. Functional modules are used to group related application functionality to simplify application management. We will create functional modules for all major functional areas of the application, including the data model, the user interface of the store and the administration interface.
The root module passes the application description for Angular. The description indicates which functional modules are required to run the application, which non-standard features should be loaded and what the root component is called. Traditionally, the root component file is named app.module.ts; Create a file with this name in the SportsStore / src / app folder and include the code from listing 7.6.
Listing 7.6. The contents of the app.module.ts file in the SportsStore / src / app folder
import { NgModule } from "@angular/core"; import { BrowserModule } from "@angular/platform-browser"; import { AppComponent } from "./app.component"; @NgModule({ imports: [BrowserModule], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule { }
By analogy with the root component, the root module class does not contain code. The fact is that the root module exists only to transfer information through the decorator @NgModule. The imports property tells Angular to load the BrowserModule function module with all the basic Angular functionality needed for the web application.
The declarations property tells Angular to load the root component, and the bootstrap property tells you that the root component is the AppModule class. Information will be added to the properties of this decorator when functionality is included in the SportsStore application, but a basic configuration will be enough to run the application.
Analysis boot file
The next block of service code is the boot file that launches the application. The book focuses on using Angular to create applications that run in browsers, but the Angular platform can be ported to different environments. The bootstrap file uses the Angular browser platform to load the root module and launch the application. Create a file called main.ts, traditionally assigned to the boot file, in the SportsStore / src / app folder and add the code from Listing 7.7 to it.
Listing 7.7. The contents of the main.ts file in the SportsStore / src folder
import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule);
Development tools detect changes in the project file, compile code files and automatically reboot the browser with the content shown in Figure 2. 7.2.
When viewing the DOM model in the browser, you will see that the temporary content from the root component template was inserted between the initial and final tags of the app element:
<body class="ma-1"> <app> <div class="bg-success pa-1 text-xs-center"> This is SportsStore </div> </app> </body>
Getting started on the data model
Work on any new project is best to start with the data model. I want to quickly demonstrate some of Angular’s capabilities in action, so instead of defining a data model from beginning to end, we’ll start by implementing basic functionality on dummy data. This data will then be used to create the interface part, and in Chapter 8 we will return to the data model and associate it with a REST-compatible web service.
Creating model classes
Each data model requires classes to describe the data types included in the data model. In the SportsStore application, these are classes with descriptions of products sold in the online store and orders received from users. To start using the SportsStore application, it is enough to have the description of products; other classes of models will be created to support extended functionality as they are implemented. Create a file called product.model.ts in the SportsStore / src / app / model folder and include the code in Listing 7.8.
Listing 7.8. The contents of the file product.model.ts from the folder SportsStore / src / app / model
export class Product { constructor( public id?: number, public name?: string, public category?: string, public description?: string, public price?: number) { } }
The Product class defines a constructor that gets the id, name, category, description, and price properties. These properties correspond to the data structure used to populate the REST-compatible web service in Listing 7.2. Question marks (?) Behind parameter names indicate that these are optional parameters that can be omitted when creating new objects using the Product class; This can be useful when developing applications, the properties of which model objects are populated using HTML forms.
Creating a dummy data source
To prepare the transition from dummy data to real data, we will transfer data to the application from the data source. The rest of the application code does not know where the data came from, and the transition to receiving data from HTTP requests will be transparent.
Create a static.datasource.ts file in the SportsStore / src / app / model folder and enable the class definition from Listing 7.9.
Listing 7.9. Contents of the static.datasource.ts file from the SportsStore / src / app / model folder
import { Injectable } from "@angular/core"; import { Product } from "./product.model"; import { Observable } from "rxjs/Observable"; import "rxjs/add/observable/from"; @Injectable() export class StaticDataSource { private products: Product[] = [ new Product(1, "Product 1", "Category 1", "Product 1 (Category 1)", 100), new Product(2, "Product 2", "Category 1", "Product 2 (Category 1)", 100), new Product(3, "Product 3", "Category 1", "Product 3 (Category 1)", 100), new Product(4, "Product 4", "Category 1", "Product 4 (Category 1)", 100), new Product(5, "Product 5", "Category 1", "Product 5 (Category 1)", 100), new Product(6, "Product 6", "Category 2", "Product 6 (Category 2)", 100), new Product(7, "Product 7", "Category 2", "Product 7 (Category 2)", 100), new Product(8, "Product 8", "Category 2", "Product 8 (Category 2)", 100), new Product(9, "Product 9", "Category 2", "Product 9 (Category 2)", 100), new Product(10, "Product 10", "Category 2", "Product 10 (Category 2)", 100), new Product(11, "Product 11", "Category 3", "Product 11 (Category 3)", 100), new Product(12, "Product 12", "Category 3", "Product 12 (Category 3)", 100), new Product(13, "Product 13", "Category 3", "Product 13 (Category 3)", 100), new Product(14, "Product 14", "Category 3", "Product 14 (Category 3)", 100), new Product(15, "Product 15", "Category 3", "Product 15 (Category 3)", 100), ]; getProducts(): Observable<Product[]> { return Observable.from([this.products]); } }
The StaticDataSource class defines a method called getProducts that returns dummy data. Calling the getProducts method returns the result Observable <Product []> - an implementation of Observable for receiving arrays of Product objects.
The Observable class is provided by the Reactive Extensions package, which Angular uses to handle state changes in applications. The Observable class will be described in Chapter 23, and in this chapter it is enough to know that the Observable object is similar to the JavaScript Promise object: it represents an asynchronous task that should return a result in the future. Angular reveals the use of Observable objects for some of its functions, including working with HTTP requests; That is why the getProducts method returns Observable <Product []> instead of returning data - simple synchronous or using Promise.
The @Injectable decorator applies to the StaticDataSource class. This decorator tells Angular that this class will be used as a service, which allows other classes to access its functionality through the dependency injection mechanism described in Chapters 19 and 20. When the application begins to take shape, we will show how the service works.
Creating a model repository
The data source must provide the application with the requested data, but data is usually accessed via an intermediary (repository) responsible for transferring this data to the individual structural blocks of the application so that the details of the data acquisition remain hidden. Create a file product.repository.ts in the SportsStore / src / app / model folder and define the class from Listing 7.10.
Listing 7.10. The contents of the file product.repository.ts from the folder SportsStore / app / model
import { Injectable } from "@angular/core"; import { Product } from "./product.model"; import { StaticDataSource } from "./static.datasource"; @Injectable() export class ProductRepository { private products: Product[] = []; private categories: string[] = []; constructor(private dataSource: StaticDataSource) { dataSource.getProducts().subscribe(data => { this.products = data; this.categories = data.map(p => p.category) .filter((c, index, array) => array.indexOf(c) == index).sort(); }); } getProducts(category: string = null): Product[] { return this.products .filter(p => category == null || category == p.category); } getProduct(id: number): Product { return this.products.find(p => p.id == id); } getCategories(): string[] { return this.categories; } }
When Angular needs to create a new repository instance, Angular examines the class and sees that it needs a StaticDataSource object to call the ProductRepository constructor and create a new object. The constructor of the repository calls the data source's getProducts method, and then uses the subscribe method of the Observable object returned to retrieve these goods. For details on how Observables work, see Chapter 23.
»More information about the book can be found on
the publisher's website.»
Table of Contents»
ExcerptFor Habrozhiteley a 20% discount on the coupon -
Angular