Getting Started with Angular |
|
Tour of Heroes app |
Tutorial by Matt Ramble: https://developer.okta.com/blog/2020/03/02/angular-bootstrap |
Angular |
|
Angular CLI |
|
Angular Material |
|
Book Code |
CHAPTER 2. Your First Angular App
Angular CLI |
npm install --global @angular/cli |
Creating the Project |
ng new todo |
Adding the Bootstrap CSS Package |
npm install bootstrap |
CHAPTER 7. SportsStore: A Real Application
Path |
/mnt/disk2/home/egor/prog/ng-lists/books/ |
File |
src/app/app.component.html |
Adding the CSS Style Sheets to the Application
|
|
Listing 7-1. Adding CSS to the
angular.json
file in the SportsStore Folder ...
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/SportsStore",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css",
"node_modules/bootstrap/dist/css/bootstrap.min.css", (1)
"node_modules/font-awesome/css/font-awesome.min.css" (2)
],
"scripts": []
},
...
npm install bootstrap --save
npm install font-awesome --save
- angular.json
Preparing the HTML File
Listing 7-5. Preparing the
index.html
File in the src Folder<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SportsStore</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body class="m-2"> (1)
<app>SportsStore Will Go Here</app>
</body>
</html>
Starting the Data Model
Creating the Model Repository
Listing 7-11
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(); (1)
});
}
getProducts(category: string = null): Product[] { (2)
return this.products
.filter(p =>
category == null ||
category == p.category);
}
getProduct(id: number): Product {
return this.products.find(p => (3)
p.id == id);
}
getCategories(): string[] {
return this.categories;
}
}
1 | array.indexOf выдает индекс первого вхождения, то есть таким образом удаляются дубликаты |
2 | Для параметра null возвращается весь список |
3 | В этом фрагменте используются методы массива map, filter, find |
Starting the Store
Creating the Store Component and Template
-
store.component.ts
-
store.component.html
CHAPTER 23. Using Reactive Extensions
import { Component, Inject } from "@angular/core";
import { NgForm } from "@angular/forms";
import { Product } from "../model/product.model";
import { Model } from "../model/repository.model";
import { MODES, SharedState, SHARED_STATE } from "./sharedState.model";
import { Observable } from "rxjs";
import { filter, map, distinctUntilChanged, skipWhile } from "rxjs/operators";
@Component({
selector: "paForm",
templateUrl: "form.component.html",
styleUrls: ["form.component.css"]
})
export class FormComponent {
product: Product = new Product();
constructor(private model: Model,
@Inject(SHARED_STATE) private stateEvents: Observable<SharedState>) {
stateEvents
.pipe(skipWhile(state => state.mode == MODES.EDIT))
.pipe(distinctUntilChanged((firstState, secondState) =>
firstState.mode == secondState.mode
&& firstState.id == secondState.id))
.subscribe(update => {
this.product = new Product();
if (update.id != undefined) {
Object.assign(this.product, this.model.getProduct(update.id));
}
this.editing = update.mode == MODES.EDIT;
});
}
editing: boolean = false;
submitForm(form: NgForm) {
if (form.valid) {
this.model.saveProduct(this.product);
this.product = new Product();
form.reset();
}
}
resetForm() {
this.product = new Product();
}
}