want to show more data in another component when view in detail button is clicked (angular 6)

前端 未结 4 722
逝去的感伤
逝去的感伤 2020-11-30 16:00

I am new to angular6, Please do not consider this question as duplicated, as i could not able to find relevant answer so far, I have 2 components incident Component<

相关标签:
4条回答
  • 2020-11-30 16:19

    While, the solution suggested in some of the other answers, namely using a service to broadcast data changes, for example using an RxJS Subject, can make this work and is at times the most natural approach, it should not be your first choice because it introduces shared, mutable application scoped state.

    It should be avoided wherever possible for some of the following reasons:

    1. Using the router, and by implication the URL, to control the rendered components introduces a beneficial decoupling keeping your components cleaner and rendering them independent of their relationship to one another independent of their relative layout in the view tree. This is very advantageous for maintenance and even more so for reusability.

    2. By relying on the changes broadcast through a shared service, you are introducing another source of truth, implicitly relying on the router. That is to say, if the you navigate to the detail route before navigating to the list route, the detail route will not work. In order to work around that, the application becomes much more complex.

    The structurally simplest approach is to have both components retrieve their data independently. This downside is additional HTTP requests and loading time but, unless you are working with very large data structures or your server takes a very long time to process the requests, it is often worth it. At the very least, you should try this approach first.

    Here is what it would look like

    data.service.ts

    import {Injectable} from '@angular/core';
    import {HttpClient} from '@angular/common/http';
    import {map} from 'rxjs/operators';
    import formatIncident from './format-incident';
    import Incident from './incident';
    
    @Injectable({providedIn: 'root'}) export class IncidentService {
      constructor(http: HttpClient) {
        this.http = http;
      }
    
      getIncidents() {
        return this.http.get('api/incidents')
          .pipe(
            map(data => data.Events.map(formatIncident)
          );
      }
      getIncident(id: string) {
        return this.http.get<Incident>(`api/incidents/${id}`).map(formatIncident);
      }
    }
    

    format-incident.ts

    import Incident from './incident';
    
    export default function formatIncident(eventJSON): Incident {
      const unquotedEventJSON = eventJSON.replace(/'/g, '"');
      const objectIdIndex = unquotedEventJSON.indexOf('"_id": ObjectId');
      const eventJSONSansId = unquotedEventJSON.substr(objectIdIndex, 44);
    
      const incident = JSON.parse(eventJSONSansId);
      const id = unquotedEventJSON.substr(0, objectIdIndex);
    
      return {
          ...incident,
          id
        };
    }
    

    incident.ts

    export default interface Incident {
      id: string,
      Title: string;
      Ticket: string;
    }
    

    incidents.component.ts

    import {Component} from '@angular/core';
    import {Observable} from 'rxjs';
    
    @Component({
      selector: 'app-incidents',
      templateUrl: './incidents.component.html'
    })
    export class IncidentsComponent {
      constructor(router: Router, incidentService: IncidentService) {
        this.router = router;
        this.incidentService = incidentService;
      }
    
      ngOnInit() {
        this.incidents$ = this.incidentService.getIncidents();
      }
    
      incidents$?: Observable<Incident>;
    }
    

    incidents.component.html

    <div class="card" *ngFor="let incident of incidents$ | async">
      <div class="card-header">
        <span class="badge">A</span><small>{{incident.Title}}</small>
        <span class="badge">A</span><small>{{incident.Ticket}}</small>
        <div class="card-footer">
            <a class="btn btn-sm btn-link"
                routeLink="/incidents/{{incident.id}}"
                [routerLinkActive]="router.url.match(incident.id)">View in Detail</button>
        </div>
      </div>
    </div>
    

    incident-detail.component.ts

    import {Component} from '@angular/core';
    import {map} from 'rxjs/operators';
    
    @Component({
      selector: 'app-incident-detail',
      templateUrl: './incident-detail.component.html'
    })
    export class IncidentDetailComponent {
      constructor(route: ActivatedRoute, incidentService: IncidentService) {
        route.paramMap.get('incidentId')
          .pipe(
            map(id => incidentService.getIncident(id))
           )
          .subscribe(incident => {
            this.incident = incident;
          });
      }
    
      incident?: Incident;
    }
    

    incident-detail.component.html

    <div class="card"> 
      <div class="card-header">
        <span class="badge">A</span><small>{{incident?.Title}}</small>
        <span class="badge">A</span><small>{{incident?.Ticket}}</small>
      </div>
    </div>
    

    app.module.ts

     import {NgModule} from '@angular/core';
     import {RouterModule} from '@angular/router';    
     import {HttpClientModule} from '@angular/common/http';
     import {CommonModule} from '@angular/common';
    
    @NgModule({
      components: [IncidentsComponent, IncidentDetailComponent],
      imports: [
        CommonModule,
        HttpClientModule,
        RouterModule.forRoot([
          {path: 'incidents', component: IncidentsComponent}, 
          {path: 'incidents/incidentId', component: IncidentDetailComponent}
        ])
       ]
    }) export class AppModule {}
    

    This is a bog standard approach and works well for many situations but there a few for which it is a not a great fit.

    0 讨论(0)
  • 2020-11-30 16:26

    Create a data sharing service first, here's sample code, you should modify according to your need

    Data sharing service

    import { Injectable } from '@angular/core';
    import { BehaviorSubject } from 'rxjs/BehaviorSubject';
    
    @Injectable()
    export class DataSharingService {
        private title = new BehaviorSubject<string>("");
        currentTitle = this.title.asObservable();
    
        setTitle(txt: string){
            this.title.next(txt);
        }
    }
    

    inject this service into your incident component

    Data sender component

    constructor(
        private dataSharingService: DataSharingService
      ) { }
    

    use this service where you want in your incident component before navigation

    this.dataSharingService.setTitle("Your title or data");
    

    Now you surely want to receive data into your incident detail component, for that here's sample code

    Data receiver component

    title: string;
      constructor(private dataSharingService: DataSharingService ) { }
    
      ngOnInit() {
        this.dataSharingService.currentTitle.subscribe(data => {
          this.title = data;
        })
      }
    

    Note: Please modify according to your requirement, this service I made to set and get string title. This service is useful for independent components, without any child-parent relationship.

    0 讨论(0)
  • 2020-11-30 16:38

    We can use the Decorators for making a communication between parent and child components. @Input and @Output are parts of the @angular/core. The @Input decorator is for obtaining the data that is passed from a component. @Output can pass data back from child to parent

    0 讨论(0)
  • 2020-11-30 16:40

    when your incident-detail-component is a child element of your incident-component, you can simply pass the data in as an input variable. Take a look here: https://angular.io/api/core/Input

    0 讨论(0)
提交回复
热议问题