The best way to collect data from multiple compone

2019-07-29 01:47发布

I am relatively new to Angular, and I understand my question might be very primitive, but please advice me the best solution in my case.

I have a Stepper (from Angular Material); the contents of each step are inside different components; in all the steps we collect data from a customer using multiple input fields.

The code looks like below.

Stepper:

<mat-horizontal-stepper #stepper>
  <mat-step [stepControl]="stepOne">
    <ng-template matStepLabel><span class="someClass">Customer Information</span></ng-template>

    <step-one></-step-one>

  </mat-step>
  <mat-step [stepControl]="stepTwo">
    <ng-template matStepLabel><span class="someClass">Payment Information</span></ng-template>

    <step-two></step-two>

  </mat-step>
    ...
  <mat-step>
    <ng-template matStepLabel><span class="someClass">Confirmation</span></ng-template>

    <confirmation></confirmation>

  </mat-step>
</mat-horizontal-stepper>

Contents (lots of fields like this):

  <mat-form-field class="dcp-input-field">
    <input matInput placeholder="First Name" formControlName="name" [errorStateMatcher]="matcher">
      ...
  </mat-form-field>

What I want, is to collect all the data in the last "confirmation" controller, to show it to the customer. I know there are various ways of communication between components, but which one is the best in this case? I've tried using service, but something went wrong.

Please just send me a link to any reference that can answer my question, it should be enough.

Thanks in advice.

4条回答
家丑人穷心不美
2楼-- · 2019-07-29 01:58

A service is not the correct solution in your case.

You should have the data object in parent component and pass it as an input to all child components (steps).

Edit:

Sample code:

Parent:

Define the data object in the parent Component:

data = {};

Pass data object to step-one child component in parent template:

<mat-horizontal-stepper #stepper>
  <mat-step [stepControl]="stepOne">
    <ng-template matStepLabel><span class="someClass">Customer Information</span></ng-template>
    <step-one [data]="data"></-step-one>
  </mat-step>
  ...

Child:

Define the @Input data object to receive from parent:

@Input() data: {};


Summary: This way, all children will work with the parent's data object, and once submitted in parent component, the data is there.

查看更多
迷人小祖宗
3楼-- · 2019-07-29 02:08

You could write a service that holds variables for you, on each step you set the variables within the service to the data you need to hold. Then when you complete your stepper all the data within the service will be ready and waiting.

here are the Angular docs for this. Docs

With that service, set up a function that returns all the data you need in the order you require, and subscribe to it with the final step, as seen here. Subscriptions

Then you should have all of your data when you need it at the end of the stepper.

Just remember that when you have finished using your data to clear all the variables held within the service to avoid any issues with the stepper returning the wrong data.

查看更多
beautiful°
4楼-- · 2019-07-29 02:21

If you want to do it using viewChild you can act this way:

First child component

import { Component } from '@angular/core';

@Component({
  selector: 'cmp-1',
  template: ''
})
export class Cmp1Component  {
  public data: any[] = [
    {
      name: "component 1",
      action: "something",
      status: "alive"
    }
  ]
}

Second child component

import { Component } from '@angular/core';

@Component({
  selector: 'cmp-2',
  template: ''
})
export class Cmp2Component  {
  public data: any[] = [
    {
      name: "component 2",
      action: "something else",
      status: "not alive"
    }
  ]
}

Main component the use ViewChildren to get data

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChild('cmp1') component1: Cmp1Component;
  @ViewChild('cmp2') component2: Cmp2Component;
}

the related html and css

<cmp-1 #cmp1></cmp-1>
<cmp-2 #cmp2></cmp-2>

<h1>Here's the data from the components</h1>

<hr>

<h3>Component 1</h3>

<div class="box">
  <div class="item" *ngFor="let data of component1.data">
    <div>{{data.name}}</div>
    <div>{{data.action}}</div>
    <div>{{data.status}}</div>
  </div>
</div>

<hr>

<h3>Component 2</h3>

<div class="box">
  <div class="item" *ngFor="let data of component2.data">
    <div>{{data.name}}</div>
    <div>{{data.action}}</div>
    <div>{{data.status}}</div>
  </div>
</div>

.box{
  display: flex;
  flex-direction: column;
}

NOTE I haven't checked if both of component exists, in this example, because I know it for sure since it's just all in a static context. Be sure to check them if you eneded before doing some logic.

Working stackblitz: https://stackblitz.com/edit/angular-n1tunk

查看更多
别忘想泡老子
5楼-- · 2019-07-29 02:21

Two ways that i know and would recommend.

  1. Your Stepper is in the Parent Component and every Step has a child-omponent with an Output-binding. You parent gets the change on those variables component-interaction

  2. A service which each child Component sends it data to and where your building your array/object. Then later send it from the service to the parent.

i would recommend the first solution with output-bindings

查看更多
登录 后发表回答