Angular 8: pass a data to a router

2020-02-16 05:19发布

问题:

I have page with a list of products, and I want to pass product id to a product/:id router (I don't want to parse it from router url). What options do I have? Can I have something like Input() to a router component?

回答1:

Let me get this right first!

You have a list of items and when you click on one, you need to redirect to a general route that displays the details in reference to the item id? You are looking for a way to pass the item id to the child component without passing it as a route parameter?

This is basically sharing data among components. There are 4 ways of doing that.

Parent to Child: Sharing Data via Input

This is probably the most common and straightforward method of sharing data. It works by using the @Input() decorator to allow data to be passed via the template.

Child to Parent: Sharing Data via ViewChild

ViewChild allows one component to be injected into another, giving the parent access to its attributes and functions. One caveat, however, is that the child won’t be available until after the view has been initialized. This means we need to implement the AfterViewInit lifecycle hook to receive the data from the child.

Child to Parent: Sharing Data via Output() and EventEmitter

This approach is ideal when you want to share data changes that occur on things like button clicks, form entries, and other user events.

In the parent, you can create a function to receive the message and set it equal to the message variable.

In the child, declare a messageEvent variable with the Output decorator and set it equal to a new event emitter. Then create a function named sendMessage that calls emit on this event with the message you want to send. Lastly, create a button to trigger this function.

The parent can now subscribe to this messageEvent that’s outputted by the child component, then run the receive message function whenever this event occurs.

Unrelated Components: Sharing Data with a Service (Recommended)

When passing data between components that lack a direct connection, such as siblings, grandchildren, etc, you should you a shared service. When you have data that should always be in sync, I find the RxJS BehaviorSubject very useful in this situation.

following is an example on the last approach!

shared-service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class DataService {

  private messageSource = new BehaviorSubject('default message');
  currentMessage = this.messageSource.asObservable();

  constructor() { }

  changeMessage(message: string) {
    this.messageSource.next(message)
  }

}

parent.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'app-parent',
  template: `
    {{message}}
  `,
  styleUrls: ['./sibling.component.css']
})
export class ParentComponent implements OnInit {

  message:string;

  constructor(private data: DataService) { }

  ngOnInit() {
    //subscribing to the updated data set
    this.data.currentMessage.subscribe(message => this.message = message)
  }

}

sibling.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'app-sibling',
  template: `
    {{message}}
    <button (click)="newMessage()">New Message</button>
  `,
  styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {

  message:string;

  constructor(private data: DataService) { }

  ngOnInit() {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

  newMessage() {
    // triggering the shared service method
    this.data.changeMessage("Hello from Sibling")
  }

}

I hope this approach works.

Good Luck!



回答2:

import { Router } from '@angular/router';

constructor(private router: Router) { }

Use as a path Variable

In app.routes.ts

{ path: 'product/:id' , component: ProductComponent}

How to use in html file

<a [routerLink]="['/product', product.id ]">Your link<a>

Here product.id is the value you wants to pass

How to use in in typescript file

this.router.navigate(['/product', this.product.id]);

Here this.product.id is the value you wants to pass

Use as a optional parameter

In app.routes.ts

{ path: 'product' , component: ProductComponent}

How to use in html file

<a [routerLink]="['/product', { id: product.id} ]">Your link<a>

Here product.id is the value you wants to pass

How to use in in typescript file

this.router.navigate(['/product',{ id : this.product.id} ]);

Here this.product.id is the value you wants to pass

Use as a Query parameter

In app.routes.ts

{ path: 'product' , component: ProductComponent}

How to use in html file

<a [routerLink]="['/product']" [queryParams]="{ id: product.id}">Your link<a>

Here product.id is the value you wants to pass

How to use in in typescript file

this.router.navigate(['/product'], { queryParams: { id : this.product.id}});

Here this.product.id is the value you wants to pass