Angular 2: Using Component Input to Pass Nested Arrays

4,019 views
Skip to first unread message

Timothy Sandberg

unread,
Mar 24, 2016, 4:50:13 PM3/24/16
to AngularJS
I have this scenario: I'm using TypeScript, and I want to pass a "Transport" object that contains an array of "Electrics" nested within an array of "Cars" from a parent component to its child component.  

How do I access a particular "Electric" for purposes of rendering in the html like this:

<html> 
   Model
   <input [(ngModel)="transport.cars.find(c => c.isActive == true).electrics.find(e => e.isActive == true).modelName"] />
<html>

*******

@View({
    template: template,
    directives: [
        ChildComponent,
})
export class ParentComponent{
  transport: Transport;

  sendTheTransport(){
     this.transport = setThisObjectWithData();
  }
}

Parent template:
<div>
<child [transport]="transport"></child>
</div>

export class ChildComponent{
  @Input() transport: Transport;

Is there a way to intercept the object before the partial HTML is rendered?  This is not scalable: 
<html> 
   Model
   <input [(ngModel)="transport.cars[0].electrics[2].modelName"] />
<html>

Timothy Sandberg

unread,
Mar 25, 2016, 2:30:21 AM3/25/16
to AngularJS
Here's a plnkr for this scenario: http://plnkr.co/9lBZiLNGOSSd3zsgiRhW

Günter Zöchbauer

unread,
Mar 25, 2016, 5:26:34 AM3/25/16
to AngularJS
That's a timing issue. `@Input() transport:Transport` doesn't yet have a value when Angular tries to evaluate the binding `transport.cars[0].electrics[1].name` the first time.
`@Input() transport:Transport` is only set after `ngOnInit() { ... }

To work around use the elvis operator

transport?.cars[0].electrics[1].name

This the evaluation returns `null` when `transport` is null and `.cars...` isn't tried unless `transport !== null`

Sander Elias

unread,
Mar 25, 2016, 8:58:12 AM3/25/16
to AngularJS
Hi Timothy,

You can use the elvis operator as Günter mentioned. However I taste from your question that you actually want to run some logic on the moment the data comes in. For this you can use the ngOnChanges lifecycle hook. something like this:

import {Component, Input} from 'angular2/core';
import {Transport} from "./models/Transport";

@Component({
  selector
: "child",
 
template: `<h2>In Child Component</h2>
  <h3>Electric Cars</h3>
  <br/>
  This is not an ideal solution: <b>transport.cars[0].electrics[1].name</b> yields:
  <br/>
  {{electricCar}}
    `

})

export class ChildComponent {
 
@Input() transport: Transport;


  ngOnChanges
() {
   
this.electricCar=this.transport.cars[0].electrics[1].name;
 
}
 
}


Here I use a local variable to put the desired string in the view. If you need to edit, make it a reference to an array or an object, otherwise your changes will get lost.

Regards
Sander

Timothy Sandberg

unread,
Mar 25, 2016, 1:31:04 PM3/25/16
to AngularJS
Thank you, Gunter, for your thoughtful answer.  It's a great source of comfort to find helpful folks to share their expertise.  I see that your solution works, but for my situation, Sander has revealed to me a nice way dirty-check my arrays.  

I think both of your responses should be added to the Angular.io documentation.  Once you get past the basic idea of how Input() works, you'll be confronted with this problem:  passing complex objects between components. There's really no mention on how to implement a solution.  You guys have filled that gap.  Thanks!! 
 
Reply all
Reply to author
Forward
0 new messages