简体   繁体   中英

Populating an Angular Material Dialog with data from another component

I have an Angular Material application as a class assignment. The premise is a computer repair shop with a list of services. The user checks the services they want and clicks the Calculate button, and then an invoice pops up with the services the user has chosen and a total cost for those services. I have the list of services set up in one component, and when the user clicks on what they want those object values are captured. I have the Material Dialog for the invoice in another component. I haven't written the code yet that actually adds together the price of the services. My goal right now is for the invoice to list the chosen services. When I click the calculate button, the invoice pops ups but doesn't list any services, so it appears the data from the first component is not reaching the second component. Can anyone help?

Here is the code

fix.ts

export interface Fix {
  id: number;
  name: string;
  price: string;
  checked: boolean;
}

fix.service.ts

import { Observable, of } from 'rxjs';
import { Injectable } from '@angular/core';
import { Fix } from './fix';

@Injectable()
export class FixService {
  fixes: Fix[] = [
    {id: 1, name: "Password Reset", price: "39.99", checked: false},
    {id: 2, name: "Spyware Removal", price: "99.99", checked: false},
    {id: 3, name: "RAM Upgrade", price: "129.99", checked: false},
    {id: 4, name: "Software Installation", price: "49.99", checked: false},
    {id: 5, name: "Tune-up", price: "89.99", checked: false},
    {id: 6, name: "Keyboard Cleaning", price: "45.00", checked: false},
    {id: 7, name: "Disk Clean-up", price: "149.99", checked: false},
  ];

  constructor() { }

  getFix(): Observable<Fix[]> {
    return of(this.fixes);
  }
}

base-layout.component.html

<div class="wrapper">
  <mat-card class="services-panel frm-services-panel">
    <mat-card-header class="frm-services-header">
      <mat-toolbar class="frm-services-toolbar">
        Available Services
      </mat-toolbar>
    </mat-card-header>
    <mat-card-content class="frm-services-body">
      <mat-checkbox *ngFor="let fix of fixes" value="{{fix.name}} {{fix.price}}" [(ngModel)]="fix.checked" (change)="getCheckboxes()">
        <div fxLayout="row">
          <div class="frm-services-name">
            {{ fix.name }}
          </div>
          <div class="rightSide">
            {{ fix.price }}
          </div>
        </div>
      </mat-checkbox>
    </mat-card-content>
    <mat-card-content class="frm-services-inputs">
      <mat-form-field>
        <input matInput placeholder="Cost of Parts">
      </mat-form-field>
      <mat-form-field>
        <input matInput placeholder="Cost of Labor @$50.00/hr">
      </mat-form-field>
      {{ selectedFixes | json }}
    </mat-card-content>
    <mat-card-actions class="frm-login-actions">
      <button mat-raised-button class="btn-login button1" (click)="getInvoice()">Calculate</button>
    </mat-card-actions>
  </mat-card>
</div>

base-layout.component.ts

import { InvoiceSummaryDialogComponent } from './../../pages/invoice-summary-dialog/invoice-summary-dialog.component';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { tap, filter, map } from 'rxjs/operators';
import { Fix } from '../fix';
import { FixService } from '../fix.service';
import { Observable, Subscription } from 'rxjs';
import { MatDialog, MatDialogConfig } from '@angular/material';

@Component({
  selector: 'app-base-layout',
  templateUrl: './base-layout.component.html',
  styleUrls: ['./base-layout.component.scss']
})
export class BaseLayoutComponent implements OnInit, OnDestroy {
  fixes: Fix[];
  subs: Subscription[] = []
  selectedFixes: Fix[] = [];
  constructor(private fixService: FixService, private dialog: MatDialog) { }

  ngOnInit() {
    const sub = this.fixService.getFix()
      .subscribe(fixes => {
        this.fixes = fixes;
      });
      this.subs.push(sub);
  }

  getCheckboxes() {
    this.selectedFixes = this.fixes
      .filter(f => f.checked);
        // return this.selectedFixes;
  }

  getInvoice() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.data = {
      selectedFixes: this.selectedFixes
    }
    const dialogRef = this.dialog.open(InvoiceSummaryDialogComponent, dialogConfig);
    dialogRef.afterClosed().subscribe(
      data => console.log("Dialog output:", data)
    )
  }

  ngOnDestroy() {
    for (const sub of this.subs) {
      if(sub) {
        try {
          sub.unsubscribe();
        } catch {}
      }
    }
  }
}

invoice-summary-dialog.component.html

<!-- <div class="container"> -->
<h2 mat-dialog-title>Invoice</h2>
<mat-dialog-content>
  <ul>
    <li *ngFor="let selectedFix of selectedFixes">
      <div fxLayout="row">
        <div class="frm-invoice-name">
          {{ selectedFix.name }}
        </div>
        <div class="rightSide">
          {{ selectedFix.price }}
        </div>
      </div>
    </li>
  </ul>
  Total:
</mat-dialog-content>
<mat-dialog-actions>
  <button mat-raised-button class="confirm" (click)="confirm()">Confirm</button>
</mat-dialog-actions>
<!-- </div> -->

invoice-summary-dialog.component.ts

@Component({
  selector: 'app-invoice-summary-dialog',
  templateUrl: './invoice-summary-dialog.component.html',
  styleUrls: ['./invoice-summary-dialog.component.scss']
})
export class InvoiceSummaryDialogComponent implements OnInit {
  @Input() selectedFixes;
  constructor(private dialogRef: MatDialogRef<BaseLayoutComponent>,
          @Inject(MAT_DIALOG_DATA) data) { }

  ngOnInit() {
  }

  confirm() {
    this.dialogRef.close();
    location.reload();
  }
}

the data comes here @Inject(MAT_DIALOG_DATA) data . so you could retrieve it in some way like

ngOnInit() {
  this.selectedFixes = this.data.selectedFixes;
}

inside of ngOnInit hook of your InvoiceSummaryDialogComponent.

In dialog component, data received from your base component is not used, so you are not able to display the selected services.

In invoice-summary-dialog.component.html

Replace

 <li *ngFor="let selectedFix of selectedFixes">
      <div fxLayout="row">
        <div class="frm-invoice-name">
          {{ selectedFix.name }}
        </div>
        <div class="rightSide">
          {{ selectedFix.price }}
        </div>
      </div>
    </li>

with

<ng-container *ngIf="data?.selectedFixes">
    <li *ngFor="let selectedFix of data.selectedFixes">
          <div fxLayout="row">
            <div class="frm-invoice-name">
              {{ selectedFix.name }}
            </div>
            <div class="rightSide">
              {{ selectedFix.price }}
            </div>
          </div>
        </li>
</ng-container>

You can pass data through:-

    getInvoice() {
    const dialogRef = this.dialog.open(InvoiceSummaryDialogComponent, 
    this.selectedFixes);
    dialogRef.afterClosed().subscribe(
      data => console.log("Dialog output:", data)
    )
  }

And Get Data (invoice-summary-dialog.component.ts):-

    @Component({
  selector: 'app-invoice-summary-dialog',
  templateUrl: './invoice-summary-dialog.component.html',
  styleUrls: ['./invoice-summary-dialog.component.scss']
})
export class InvoiceSummaryDialogComponent implements OnInit {
  @Input() selectedFixes;
  constructor(private dialogRef: MatDialogRef<BaseLayoutComponent>,
          @Inject(MAT_DIALOG_DATA) data) { }

  ngOnInit() {
   console.log(this.data) // Your data
  }

  confirm() {
    this.dialogRef.close(this.data);//You can return data
    location.reload();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM