See the Angular Basic Tutorial for the basic tutorial
Angular routing introduction
Color {#0abb3c}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component}{component} Router color{#0abb3c}{Router}Router is used in Angular.
Scenarios where route hops are required:
If there are two jump links on the page, we want to click these links to go to the product list page and the personal center page respectively. We can start by creating two components: GoodsListComponent and PersonalCenterComponent. The specific process is as follows:
Routing to create
- Create a new file app-routing.module.ts and place the view configuration to jump to
import { NgModule } from '@angular/core';
// Import routing modules RouterModule and Routes
import { Routes, RouterModule } from '@angular/router';
// Introduce components that need to be displayed at different urls
import { GoodsListComponent } from './goods-list/goods-list.component';
import { PersonalCenterComponent } from './personal-center/personal-center.component';
// Configure the route array
const routes: Routes = [
{
path: 'goodsList'.// Define the route name
component: GoodsListComponent, // Specify which component to display
},
{
path: 'personalCenter'.// Define the route name
component: PersonalCenterComponent, // Specify which component to display}]; @NgModule({The // forRoot() method creates an NgModule containing all directives, the given route, and the Router service itself.
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
Copy the code
Define your Routes in the Routes array (each route in this array is a JavaScript object with two attributes). The first attribute, PATH, defines the URL path for the route. The second attribute, Component, defines the component to display in the corresponding path.)
- Import the AppRoutingModule in app.module.ts
import { AppRoutingModule } from './app-routing.module';
Copy the code
- Add these routes in app.component.html to control the presentation of navigation
<div class="route-change-container">
<a routerLink="/goodsList">Switch to the item list component</a> <! RouterLink connects the routes you define to the template file.
<a routerLink="/personalCenter">Switch to the personal center component</a>
</div>
<router-outlet></router-outlet> <! -- This directive loads components dynamically by route -->
Copy the code
- First, add two links to the HTML. Assign the link to which the route is to be added to the routerLink property. To display the component when the user clicks on individual links.
- Next, add in the template
<router-outlet>
The label. This element notifies Angular that you can update the app view with the routed component selected. Used like a component, as a placeholder to indicate where the router should display the component.
An introduction to two important apis in routing
ActivatedRoute
Color {#0abb3c}{get routing information} Get routing information, it contains routing parameters, static data… For details, please refer to the ActivatedRoute official website
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; // Introduce the ActivatedRoute
@Component({
selector: 'app-goods-list'.templateUrl: './goods-list.component.html'.styleUrls: ['./goods-list.component.scss']})export class GoodsListComponent implements OnInit {
constructor(
private route: ActivatedRoute, // dependencies are injected into this service
) {}
// Remove the routing information from the URL during the initial lifecycle
public ngOnInit(): void {
// The first way to get parameters
const params = this.route.snapshot.params;
// The second way to get parameters
this.route.params.subscribe(params= > {
console.log(params); }); }}Copy the code
The difference and use of the above two methods to obtain parameters: route.snapshot:
- You need to directly access parameters, mainly obtain
The initial value
To use snapshot without subscribing.route.params.subscribe():
- Params is used when parameters are retrieved for each change or when multiple consecutive navigations are required;
Router
Color {#0abb3c}{#0abb3c}{#0abb3c}{#0abb3c}{#0abb3c}{#0abb3c}{# 0abB3c}{# 0abB3c}{# 0abB3c}
// The Router service class needs to be introduced into the component before it is used
import { Router } from '@angular/router';
Copy the code
- Navigate () This method supports the same type of parameters as the routerLink directive, so their roles are the same;
- NavigateByUrl () absolute route;
- The events method is called before each navigation; (For now)
Route parameters were transmitted and obtained
Two forms of route parameter transmission
1. Use scenario of Params (yes /: ID dynamic routing) : For example, when we click the link of commodity list, we hope to transfer the user information or commodity type information to the component of commodity list through THE URL.
// Routes need to be configured
const routes: Routes = [
{
path: 'goodsList/:id'.// Define the route name
component: GoodsListComponent, // Specify which component to display},];Copy the code
2. queryParams (Yes? Id =xx format) Usage scenario: When we want to pass multiple parameters through the URL, we can choose to pass parameters in this way
Dynamic routing is preferred for 1 parameter, and query is more convenient for more than 2 parameters
Three specific methods for transmitting parameters in a route
1. routerLink
Single parameter:
<a [routerLink]="['/goodsList', id]" routerLinkActive="active-class"> Switch to the item list component </a>// where /goodsListl is the route path I set and id is the parameter to pass
// We can also use this form for multiple parameters, but it seems less intuitive, so we do not recommend using this method for multiple parameters
Copy the code
Multiple parameters:
<a [routerLink]="['/personalCenter']" [queryParams]="{name: 'zs', age: 16}"> Switch to personal center component </a>// The format of the parameters can be self-organized into various objects
Copy the code
RouterLinkActive Tracks whether the link routes on the element are active. And allows you to specify one or more CSS classes to add the element when the link route is active.
2. router.navigate
Navigation is based on the supplied command array and starting route. If no starting route is specified, the absolute navigation starts from the root route
Single parameter:
public goToGoodsListPage(): void {
// The first way
this._router.navigate([`/goodsList/The ${this.id}`]);
// The second method achieves the same effect as the first method
this._router.navigate(['/goodsList'.this.id]);
}
Calling this method in HTML is equivalent to using the routerLink attribute of the A tag
<button (click)="goToGoodsListPage()"> Switch to the item list component </button>Copy the code
Multiple parameters:
public goToPersonalCenterPage(): void {
this._router.navigate(['/personalCenter'] and {queryParams: {name: 'zs'.age: 16}});
}
// call in HTML
<button (click)="goToPersonalCenterPage()"> Switch to the personal center component </button>Copy the code
3. router.navigateByUrl
Absolute paths must be used for navigation based on the URLS provided. Be consistent with router.navigate for single and multiple parameters.
// The first parameter passed is the form of the array, and the first parameter of navigate is the form of the array
// His pass parameter is currently concatenated above the URL
public goToPersonalCenterPage(): void {
this._router.navigateByUrl(`/personalCenter? name=zs&age=16`);
}
Copy the code
Two ways to receive parameters in a route
1. Accept parameters of type Params
import { ActivatedRoute } from '@angular/router';
constructor(
private _route: ActivatedRoute,
) {}
public ngOnInit(): void {
// The first way is to get only the initial value
const param = this.route.snapshot.params;
// The second dynamic fetch method
this.route.params.subscribe(params= > {
console.log(params);
});
}
Copy the code
2. Accept parameters of type queryParams
import { ActivatedRoute } from '@angular/router';
constructor(
private _route: ActivatedRoute,
) {}
public ngOnInit(): void {
// The first way is to get only the initial value
const queryParam = this.route.snapshot.queryParams;
// The second dynamic fetch method
this.route.queryParams.subscribe(params= > {
console.log(params);
});
}
Copy the code
Route redirection
Application scenario: When users are expected to redirect to a page by default in an application, route redirection is required. Redirection components:
- Use the path to redirect the source
- Redirect the target component
- The pathMatch value is used to configure the route
{ path: ' '.redirectTo: '/personalCenter'.pathMatch: 'full' }, // Redirect to 'personalCenter'
Copy the code
PathMatch color{#0abb3c}{pathMatch}pathMatch is a string used to specify a routing matching policy. The options are prefix (the default) and full.
Prefix: starts with the specified path (that is, the value in path is the same as the starting path entered by the user. For example, if path is “ABC”, / ABC /a is ok, but /abcd is not ok); If path is empty, all routes will be matched to the page
/ ABC /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d /abcd/ABC /d If path is empty, the page will be matched only if localhost:4200 is followed by nothing.
Routing order
The Router at the time of matching routing, using a “first come first serve \ color abb3c # {0} {to} first come first served” strategy, so it shall be a specific static routing \ color abb3c # {0} {specific static routing} put in front of specific static routing, Then you can place the default route matching \color{#0abb3c}{default route matching} the default route matching empty path route, wildcard \color{#0abb3c}{wildcard} the wildcard route is the last one (it can match all routes, when no other routes match, The Router will select it.
const routes: Routes = [
// Static route
{
path: 'goodsList/:id'.component: GoodsListComponent,
},
{
path: 'personalCenter'.component: PersonalCenterComponent,
},
// Default empty path routing
{
path: ' '.redirectTo: '/personalCenter'.pathMatch: 'full'
},
// Wildcard route
{ path: '* *'.component: PageNotFoundComponent },
];
Copy the code
Nested routing
As the application becomes more complex, it may be necessary to create relative routes outside the root component, which become child routes, This means that a second
color{#0abb3c}{
}
needs to be added to the project, because it is another one in addition to the AppComponent < the router – outlet > \ color abb3c # {0} {< the router – outlet >} < the router – outlet >.
Color {#0abb3c}{personal details} Personal details page \color{#0abb3c}{personal details page} Personal details page \color{#0abb3c}{personal details page} Personal details page
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GoodsListComponent } from './goods-list/goods-list.component';
import { PersonalCenterComponent } from './personal-center/personal-center.component';
import { PersonalSettingComponent } from './personal-setting/personal-setting.component';
import { PersonalDetailComponent } from './personal-detail/personal-detail.component';
const routes: Routes = [
{
path: 'goodsList/:id'.component: GoodsListComponent,
},
{
path: 'personalCenter'.component: PersonalCenterComponent,
children: [ // Add a children array to store the children route
{
path: 'personalDetail'.component: PersonalDetailComponent,
},
{
path: 'personalSetting'.component: PersonalSettingComponent,
},
]
},
{
path: ' '.redirectTo: '/personalCenter'.pathMatch: 'full'},];// Add a
to the HTML of the personal center to specify where the child pages should be displayed
<div class="personal-center-container">This is the personal center page<a routerLink="./personalDetail">Switch to the personal details page</a>
<a routerLink="./personalSetting">Switch to the profile page</a>
</div>
<router-outlet></router-outlet>
Copy the code
Child routes, like other routes, require both path and Component. The only difference is that you put the child route in the children array of the parent route.
Route lazy loading
You can configure the route definition to lazy-load modules, which means Angular loads modules only when they are needed, not when the app starts.
- Add a module file to the previous two page components and configure loadChildren in Routes instead of Component
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{
path: 'goodsList/:id'.loadChildren: () = > import('./goods-list/goods-list.module')
.then(m= > m.GoodListModule)
},
{
path: 'personalCenter'.loadChildren: () = > import('./personal-center/personal-center.module')
.then(m= > m.PersonalCenterModule)
},
{
path: ' '.redirectTo: '/personalCenter'.pathMatch: 'full'},]; @NgModule({The // forRoot() method creates an NgModule containing all directives, the given route, and the Router service itself.
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
Copy the code
- Add a route module file to the previous two page components and add a route to that component.
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GoodsListComponent } from './goods-list.component';
const routes: Routes = [
{
path: ' '.component: GoodsListComponent
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class GoodsListRoutingModule {}Copy the code
Route guard (only understood)
Route guard is used to prevent unauthorized navigation to certain parts of the application. For more information, visit the route Guard website
- Use CanActivate to handle navigation to a route. // Enter the route
- Use CanActivateChild to handle navigation to a subroute.
- Use CanDeactivate to handle exiting from the current route. // Exiting from the route
- Use Resolve to retrieve route data before route activation.
- Use CanLoad to handle asynchronous navigation to a feature module. A CanActivate will still load a module. A canload will not be loaded if the condition is not met
export class TestGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
// Determine whether the logic of a route can be entered}}Copy the code
{
path: 'test-path'.component: TestComponent,
canActivate: [TestGuard], // Use route guard guard
}
Copy the code
Routing events (only understood)
The Router emits navigation events during each navigation through the router. events property. The scope of these events spans multiple points in time between the beginning and end of the navigation. For more information, please visit the routing event website for more details
Introduction to forms in Angular
The difference between reactive and template-driven forms
responsive | Template driven | |
---|---|---|
Building a form model | Displayed, created in the component class | Implicit, with instructions created |
The data model | Structured and immutable (observable) | Unstructured and mutable (data bidirectional binding) |
The data flow | synchronous | asynchronous |
Form validation | function | instruction |
Common base classes for common forms
Both reactive and template-driven forms are built on the following base classes.
-
The FormControl instance is used to track the value and validation status of a single FormControl.
-
FormGroup is used to track the value and status of a form control group.
-
FormArray is used to track the value and state of an array of form controls. (understand)
Template-driven forms
Depend on the \color{#0abb3c}{depend on the \color{#0abb3c}{directive} instructions in the template to create and manipulate the underlying object model. It is mainly used to add simple forms, which are simpler to use, but not as extensible as reactive forms. When the control value is updated, the associated property value is changed to the new value.
Create a form
<! We can use template reference variables anywhere in the current template. -->
<! These variables provide the ability to access elements directly from the module.
<! The name must be added because all components and controls in the form should have names -->
<form (ngSubmit) ="onSubmit(myform.value);" #myform="ngForm" novalidate>
<label for="name">Name:</label>
<input type="text" name="name" [(ngModel)] ="name">
<label for="password">Password:</label>
<input type="password" name="password" [(ngModel)] ="password">
<button>submit</button>
</form>
Copy the code
Validate input in template-driven forms
<! If we want to verify the above form, the password must not be empty and the name must be at least 2 characters long.
<form (ngSubmit) ="onSubmit(myform);" #myform="ngForm">
<label for="name">Name:</label>
<input type="text" name="name" [(ngModel)] ="name" minlength="2">
<label for="password">Password:</label>
<input type="password" name="password" [(ngModel)] ="password" required>
<button>submit</button>
<! This is done through the hasError method.
<div *ngIf="myform.form.hasError('minlength', 'name')">The length of the name cannot be less than 2 characters</div>
<div *ngIf="myform.form.hasError('required', 'password')">The password cannot be empty</div>
</form>
Copy the code
Reactive forms (emphasis)
Provides direct, explicit access to the underlying form object model \color{# 0ABb3c}{underlying form object model}. They are more robust than template-driven forms, and they are more extensible, reusable, and testable. And control updates are more efficient because instances of FormControl always return a new value and do not update the existing data model. If forms are a critical part of your application or are highly extensible, use reactive forms
Use reactive forms
- Introduce reactive form modules in the module file
import { ReactiveFormsModule } from '@angular/forms';
Copy the code
- Introduce a form group in the component
import { FormGroup, FormControl } from '@angular/forms';
Copy the code
- Create a FormGroup instance and associate the FormGroup model with the view
this.profileForm = new FormGroup({
name: new FormControl(' '),
password: new FormControl(' ')});Copy the code
<form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
<label for="name">First Name: </label>
<input id="name" type="text" formControlName="name">
<label for="password">Last Name: </label>
<input id="password" type="text" formControlName="password">
<button>submit</button>
</form>
Copy the code
Form a nested
A form group can accept a single form control instance color{# 0ABb3c}{single form control instance} a single form control instance and other form group instances as child controls color{# 0ABB3c}{child controls}. This makes complex form models easier to maintain and logically group them together.
- Create a nested form group.
this.profileForm = new FormGroup({
name: new FormControl(' ', [Validators.required]),
password: new FormControl(' '),
// Nested a form group for address in the form
address: new FormGroup({
street: new FormControl(' '),
city: new FormControl(' '),})});Copy the code
- Group the nested form in the template.
<form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
<label for="name">First Name: </label><input id="name" type="text" formControlName="name"> <label for="password">Last Name: </label> <input ID ="password" type="text" formControlName="password"> // Use formGroupName to declare a new form group <div formGroupName="address"> <h3>Address</h3> <label for="street">Street: </label> <input id="street" type="text" formControlName="street"> <label for="city">City: </label> <input ID ="city" type="text" formControlName="city"> </div> <button> </button> </form>Copy the code
Form validation
Control state field
Before we look at form validation, let’s take a look at some of the status fields that Angular provides for forms. These fields help users decide at which stages to perform form validation.
- Touched and untouched
Used to determine whether the user has focus, touched=true if the user has focus. Amanda =false, untouched if it never exists, touched=false; Untouched = true.
- Pristine and dirty
Dirty indicates that the user manipulates form elements; pristine indicates that the user does not manipulate form elements.
- Valid and invalid
If a form element has multiple validation conditions valid is true only if all of the validation conditions are valid. If one of the validation conditions is not valid, invalid is true.
Control state CSS class
Angular automatically maps many control properties as CSS classes color{#0abb3c}{CSS class} to the control element color{#0abb3c}{element}. You can use these classes to style the form control element color{#0abb3c}{control element} according to the form state color{#0abb3c}{state}.
- .ng-valid
- .ng-invalid
- .ng-pending
- .ng-pristine
- .ng-dirty
- .ng-untouched
- .ng-touched
Scenario: For example, we would like the border of the control to be red if it does not meet the validation criteria. Ng-touched:not(form){
&.ng-invalid:not(form){ // This is an example of SCSS
border: 1px solid red
}
}
Copy the code
Steps for form validation
- Import a validator function into the form component. Angular provides built-in validators in the Form Validation Organ network
import { Validators } from '@angular/forms';
// Angular provides built-in validators: min Max Required Email minLength maxLength Pattern...
Copy the code
- Add the validator to the corresponding field in the form.
Scenario: Verify the following items: (1) The name cannot be empty. ② The password cannot be empty, and the minimum length cannot be less than 4; ③ The street in the address should not be empty
this.profileForm = new FormGroup({
name: new FormControl(' ', [Validators.required]),
password: new FormControl(' ', [Validators.required, Validators.minLength(4)),address: new FormGroup({
street: new FormControl(' ', [Validators.required]),
city: new FormControl(' '),})});Copy the code
- Error notification logic in templates
<form [formGroup] ="profileForm" (ngSubmit) ="submitForm(profileForm.value)">
<! -- name -- -- >
<label for="name">Name:</label>
<input id="name" type="text" formControlName="name">
<div [hidden] ="profileForm? .get('name').valid || profileForm? .get('name')? .untouched">
<p [hidden] =! "" profileForm.hasError('required', 'name')">Name is mandatory</p>
</div>
<! - password - >
<label for="password">Password:</label>
<input id="password" type="text" formControlName="password">
<! Do not display error messages when the password is valid or the user has never done much.
<! -- Then determine the specific error notification based on hasError -->
<div [hidden] ="profileForm? .get('password').valid || profileForm? .get('password')? .untouched">
<p [hidden] =! "" profileForm.hasError('minlength', 'password')">The password must contain at least four digits</p>
<p [hidden] =! "" profileForm.hasError('required', 'password')">The password cannot be empty</p>
</div>
<! -- Address form group -->
<div formGroupName="address">
<h3>Address</h3>
<label for="street">Street: </label>
<input id="street" type="text" formControlName="street">
<div [hidden] ="profileForm? .get('address')? .get('street')? .valid || profileForm? .get('address')? .get('street')? .untouched">
<div [hidden] =! "" profileForm.hasError('required', ['address', 'street'])">Streets can't be empty</div>
</div>
<label for="city">City: </label>
<input id="city" type="text" formControlName="city">
</div>
<button>submit</button>
</form>
Copy the code
Custom form validators
Scenario: When filling in the mobile phone number, the user wants to verify that the format of the mobile phone number is correct and can use a custom function to do this
public ngOnInit(): void {
this.profileForm = new FormGroup({
phone: new FormControl(' '[this.mobileValidator])
});
}
public mobileValidator = (control: FormControl): any= > {
const value = control.value;
// The number is regular
const mobileReg = / ^ 0? (13 15 [012356789] [0-9] | | 17 [013678] 18 [0-9] | | 14 [57]) [0-9] {8} $/;
const result = mobileReg.test(value);
// Null is returned for valid values, or invalid returns the validation error object, which is the validation key property named mobileFormat. Values can generally be any value
// mobileFormat is used again to retrieve error messages in templates
return result ? null : {mobileFormat: {info: 'Phone format is not correct'}};
}
// Use in templates
<form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
<input id="phone" type="text" formControlName="phone">
<div>{{profileForm? .get('phone').errors | json}}</div>// You can print out error messages defined in custom functions<div [hidden] ="profileForm? .get('phone').valid || profileForm? .get('phone')? .untouched">
<p [hidden] =! "" profileForm.hasError('mobileFormat', 'phone')">The phone format is incorrect</p>
</div>
<button>submit</button>
</form>
Copy the code
How do I update form data
- use
setValue()
Method to set a new value for a single control. The setValue() method strictly follows the form group structure, andintegrity
Replaces the value of the control.- use
patchValue()
Method can replace the form model with any property defined in the object.
Use the FormBuilder service to generate controls
The FormBuilder service provides some handy ways to generate form controls. FormBuilder creates and returns these instances in the same way behind the scenes, but it’s easier to use.
The service has three methods: Control (), group(), and array(). These methods are factory methods used to generate FormControl, FormGroup, and FormArray, respectively, in the component class.
1. Introduce the FormBuilder class into the component and inject the service
import { FormBuilder } from '@angular/forms';
constructor(private fb: FormBuilder){}Copy the code
2. Generate form content
this.profileForm = this.fb.group({
name: [' '].password: [' ']});/ / is equivalent to
this.profileForm = new FormGroup({
name: new FormControl(' '),
password: new FormControl(' ')});Copy the code
Cross validation across fields (understand only)
const heroForm = new FormGroup({
'name': new FormControl(),
'alterEgo': new FormControl(),
'power': new FormControl()
}, { validators: identityRevealedValidator });
export const identityRevealedValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null= > {
const name = control.get('name');
const alterEgo = control.get('alterEgo');
return name && alterEgo && name.value === alterEgo.value ? { identityRevealed: true } : null;
};
Copy the code
See Angular’s advanced tutorial 2 – (Dependency Injection +RxJS) for the next chapter