Angular 2+: Pass data to a child component

Hello - I am trying to figure out how to pass data to a child component in Angular 2.

Here is what I have done so far...

The Parent Component is the default app component that comes with the Angular 2 shell when you create a new project.  The child component is main-test.

Based on material I find on-line...the first thing I did was import Input from Angular/core. Then I tried to invoke the Input in the export class as shown below. This is the child component main-test.component.ts

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-main-test',
  templateUrl: './main-test.component.html',
  styleUrls: ['./main-test.component.css']
})
export class MainTestComponent implements OnInit {
 @Input()
 dataPass: number;

  constructor() { }

  ngOnInit() {
  }

}

Open in new window



Then...in an attempt to test things...I tried to pass just one field from the users array from the parent component to the child component. To do this...in my parent component HTML file...I added "<app-main-test [dataPass]="user.id"> </app-main-test>"

app.component.html:

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!
  </h1>
</div>
<div>

<app-main-test [dataPass]="user.id"> </app-main-test>

</div>

Open in new window





Here is the parent .ts file:

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


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'CH Table play';

// books: any[] = [{
//   id: 20
// }]
  users = [
    {
        "firstName": "Clark",
        "lastName": "Kent",
        "job": "Reporter",
        "id": 20
    },
    {
        "firstName": "Bruce",
        "lastName": "Wayne",
        "job": "Business Owner",
        "id": 30
    },
    {
        "firstName": "Peter",
        "lastName": "Parker",
        "job": "Photographer",
        "id": 40
    },
    {
        "firstName": "Tony",
        "lastName": "Stark",
        "job": "Business Owner",
        "id": 25
    }
]
// }
}

Open in new window



At the end of the day, the main goal is to be able to pass the full "users" array to load a table in the child component ...and then use the child selector in the parent components  HTML file to display the table. I want to split it out like this because I will end up having at least 2 child components that will both contain tables that will be displayed based on items/user selections that are not important to this specific question...so I will not bore you with them.

For now...I am just trying to figure out how to pass even one field from the users array  ...just to get the data flow from parent to child working. ...and any tips you might able to provide when doing this with multiple fields (e.g. firstname, uastName, id, etc.) would also be greatly appreciated!

Thanks,
Cynthia HillLead ConsultantAsked:
Who is Participating?
 
Julian HansenConnect With a Mentor Commented:
You seem to have it correct what problems are you having?

I put together a sample as follows (assumes CLI)
ng g component components/main-test

Open in new window

This produced the main-test component which looks like this
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-main-test',
  templateUrl: './main-test.component.html',
  styleUrls: ['./main-test.component.css']
})
export class MainTestComponent implements OnInit {
  constructor() { }

  ngOnInit() {
  }
}

Open in new window

I defined a model as follows
Created folder models
Created file user.model.ts
export interface User {
    id: number,
    firstName: string,
    lastName: string,
    job:string
}

Open in new window

Imported user into main-test and specified an @Input() dataPass of type user
import { Component, Input, OnInit } from '@angular/core';
import { User } from '../../models/user.model';
@Component({
  selector: 'app-main-test',
  templateUrl: './main-test.component.html',
  styleUrls: ['./main-test.component.css']
})
export class MainTestComponent implements OnInit {
@Input() dataPass: User;
  constructor() { }

  ngOnInit() {
  }
}

Open in new window

Note the import of the model
I modified my parent template to do the following
<table class="table">
<ng-container *ngFor="let user of users">
      <tr>
        <th>First Name</th><td>{{user.firstName}}</td>
        <th>Last Name</th><td>{{user.lastName}}</td>
        <th></th>
      </tr>
      <tr>
        <th>Job</th><td>{{user.job}}</td>
        <th>ID</th><td>{{user.id}}</td>
        <td><span class="detailLink" (click)="selectedUser=user">Edit</span></td>
      </tr>
    </ng-container>
</table>
</div>
<app-main-test [dataPass]="selectedUser"></app-main-test>

Open in new window

Note the new column for the Edit that assigns the current user to the variable selectedUser.
Finally I defined selectedUser in the component
export class AppComponent {
  selectedUser:User;

Open in new window


Finally, the main-test view where we display the selected user
<div class="row">
  <div class="col-md-6 col-md-offset-2">
      <h2>User Details</h2>
      <div class="row">
      <div class="col-md-2"><strong>ID</strong></div>
      <div class="col-md-4"> {{dataPass.id}}</div>
    </div>
    <div class="row">
      <div class="col-md-2"><strong>First Name</strong></div>
      <div class="col-md-4">{{dataPass.firstName}}</div>
    </div>
    <div class="row">
      <div class="col-md-2"><strong>Last Name</strong></div>
      <div class="col-md-4">{{dataPass.lastName}}</div>
    </div>
    <div class="row">
      <div class="col-md-2"><strong>Job</strong></div>
      <div class="col-md-4">{{dataPass.job}}</div>
    </div>
  </div>
</div>

Open in new window

You can see the above working here
0
 
Cynthia HillLead ConsultantAuthor Commented:
Hey Julian - Thanks for the response! I will play around with it later this evening.

Question: For the snippet
export class AppComponent {  selectedUser:User;

Open in new window

...that would go in the parent component...right?

Also,..instead of using
 <td><span class="detailLink" (click)="selectedUser=user">Edit</span></td>

Open in new window

to specify which record is displayed in the child component...how can I use an existing pipe filter to do this?

For example...I have a pipe file that looks like this...
app.pipe.ts
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'search'
})
export class SearchPipe implements PipeTransform {

public transform(items: any[], filter: string) {
     if (!filter) return items;
    filter = filter.toLocaleLowerCase();
    return items.filter(item => JSON.stringify(item).toLowerCase().indexOf(filter) !== -1);
  }


}


export const appPipes = [SearchPipe];

Open in new window



and I have this in my parent component to limit the initial table...

<ng-container *ngFor="let user of users | search:searchText">

Open in new window



How would I have the pipe limit the data that is displayed in the child component as well...without having to use a separate edit button?

I greatly appreciate any assistance / info! Thanks!
0
 
Cynthia HillLead ConsultantAuthor Commented:
if the pipe question is too off subject for this thread...i can create a new question...let me know.

Here is what I think would need to happen to get the pipe to work in the child component...
I would need to import the pipe into the child component...something like this...
import { appPipes } from '../app.pipe';

Open in new window



and then it feels like the line of code below (which I think goes in the parent component) could be modified to make it happen...I just do not know what it would need to look like...??
 selectedUser:User;

Open in new window

0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
Julian HansenCommented:
The pipe will filter a set to a (potential) sub-set of the original.

Is the child going to display a single record or multiple?

What is the actual functionality you are targeting?
0
 
Cynthia HillLead ConsultantAuthor Commented:
The child will display one record based on the selection entered into a pipe.

I used a component from github so I could implement typeahead functionality to my search box...which uses the pipe code shared in my earlier post.

The parent component has the code that drives the typeahead search box. Because I plan to have multiple potential table layouts based on a tabbed selection by users ...I do not want the code for my original component (in this case the parent component) to get too long...so I thought I would put each of the potential table layouts (each table would be tied to the tab a user might select)....in a child component so it would be easier to maintain (instead of having one really long 'parent' component).

I have the tabbed code figured out...and the typeahead is working...I just need the parent component to communicate to the child to do two things...
1). allow the child component to pull data from the parent's "users"  array.
2). and if possible also have the value entered for the filter pipe to flow to the child component as well so it will restrict the record that is displayed based on the user entry.

That's why when I saw the code
selectedUser:User;

Open in new window

...it got me all excited thinking...hummm...could I use something like that to declare to the child which item from the array was selected using the pipe. Since the pipe is wrapped with typeahead/auto complete functionality ...the user ends up selecting just one value.

If I am going down the wrong path with trying to get the pipe entry to flow to the child...let me know what search terms you might recommend.

Thanks!
0
 
Julian HansenCommented:
I don't understand the pipe bit - will the pipe guarantee a single record? If not at what point do you decide to display the child?

If the pipe is working off the look ahead why can the child not work off the same value.

I suspect you might be confusing concepts here - pipes are for producing a subset of a list (which may be 1 or 0 items but could be more).

In your case you are wanting to display a single child based on a selection in the parent - but this selection could include more than one record?
0
 
Cynthia HillLead ConsultantAuthor Commented:
Hey Julian - Yep...I could very easily be confusing concepts.

You are right...the child can work off the same pipe and that would be more than sufficient.

In a perfect world...here is what I was trying to do for my learning purposes:
The look ahead is meant to help users narrow down to a single record. They start typing a value they are looking for...when they see the one they want...they click on it from the list of values that appear from the typeahead dropdown...then the child displays the record that is selected from the typeahead.

I'm not sure at all if that is a good approach....its just functionality I was playing with/trying to implement.

I am open to any and all feedback you are willing to share.

I just thought of something I could trying using the previous sample you provided...I will give it a shot. Wish me luck.

As always...I appreciate you sharing your knowledge with me.
0
 
Julian HansenCommented:
My feeling would be you use the TypeAhead / filter to reduce the list of items in the table / list.
When you have a manageable number - you click it (or an edit button) to load that record into the child.

This makes more sense and is more intuitive.
0
 
Cynthia HillLead ConsultantAuthor Commented:
Makes sense.

I've started looking at it...but will not have focused time to play with it until probably this evening.

Thanks!
0
 
Cynthia HillLead ConsultantAuthor Commented:
Its working as described in your post.

Thanks for your assistance!
0
 
Julian HansenCommented:
You are welcome.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.