How to pass data between ListView and a tree of components


#1

Hi guys! I have a doubt about how to pass data between a tree of components.
I have a ListView when your item has clicked it needs to be pass data to your parent component GridList

I have the following structure of templates inside the room-list.component.html. BOTH area using the directive <my-selector></my-selector>.

-| room-list (ng-template using a directive
—| grid-list (loading all tables data)
-----| table-list (ListView)
-----| sale-blank (ng-template using a directive
---- | sale-new (ng-template using a directive
---- | sale-show (ng-template using a directive

The problem is when an item is clicked I need to pass its data to some GridList child components.

Here the TableList component:

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

import {Table} from '../../typings/TRoom';


@Component({
  selector: 'table-list',
  moduleId: module.id,
  templateUrl: './table-list.component.html'
})

export class TableListComponent {
  @Input() tables: Array<Table>;
  @Output() tableItem: Table;

  onItemTap(item: Table): void {
    this.tableItem = item;

    console.dir('==== TableItem clicked: ', this.tableItem);
  }
}

The table-list.component.html:

<ListView [items]="tables">
  <ng-template let-table="item">
    <StackLayout class="p-10" (tap)="onItemTap(table)">
      <Label [text]="table.number"></Label>
    </StackLayout>
  </ng-template>
</ListView>

The GridList component:

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

import {Room} from '../../typings/TRoom';


@Component({
  selector: 'grid-list',
  moduleId: module.id,
  templateUrl: './grid-list.component.html'
})

export class GridListComponent {
  @Input() room: Room;
}

This is the grid-list.component.html:

<GridLayout columns="50,*">
  <StackLayout row="0" col="0">
    <table-list [tables]="room.tables"></table-list>
  </StackLayout>

  <ng-template [ngIf]="!tableItem">
    <StackLayout class="p-t-10" row="0" col="1">
      <sale-blank></sale-blank>
    </StackLayout>
  </ng-template>
  
  <ng-template [ngIf]="!!tableItem && tableItem.status === 1">
    <StackLayout class="p-t-10" row="0" col="1">
      <sale-new [sale]="tableItem"></sale-new>
    </StackLayout>
  </ng-template>

  <ng-template [ngIf]="!!tableItem && tableItem.status === 2">
    <StackLayout class="p-t-10" row="0" col="1">
      <sale-show [sale]="tableItem"></sale-show>
    </StackLayout>
  </ng-template>
</GridLayout>

In this moment, when I clicked nothing happens on the screen.
On the console I get the data correctly from the onItemTap(item) method.

JS: ==== TableItem clicked:  {
JS:   "id": 3,
JS:   "number": 3,
JS:   "roomId": 1,
JS:   "status": 2
JS: }


JS: ==== TableItem clicked:  {
JS:   "id": 1,
JS:   "number": 1,
JS:   "roomId": 1,
JS:   "status": 1
JS: }

I believe it’s possible to do that easy but I don’t know about it.
Please I need your help to do that better.


#2

I solved following the steps:

On TableListComponent:

  • Imported EventEmitter from '@angular/core'.
  • Changed tableItem @Output() to new EventEmitter object
  • on onItemTap() method changed this.tableItem to send item object.

The grid-list.component.html has the <table-list> directive, so:

  • Calls the onTableItem($event) event emitted from TableListComponent

The GridListComponent needs to receive the tableItem from this event, so we need to:

  • to receive @Input('tableItem') table object
  • to implement onTableItem(item) method
  • this.table on onTableItem(item) needs to receive item object data

Now the grid-list.component.html is able to read table object data from ListView item tapped.

The changes are as follows

The GridListComponent changed:

@Input('tableItem') table: Table;

  onTableItem(item) {
    this.table = item;

    console.dir('==== received table item: ', this.table);
  }

The grid-list.component.html changed:

<GridLayout columns="50,*">
  <StackLayout row="0" col="0">
    <table-list (tableItem)="onTableItem($event)" [tables]="room.tables"></table-list>
  </StackLayout>

  <ng-template [ngIf]="!table">
    ... sale-blank directive
  </ng-template>
  
  <ng-template [ngIf]="!!table && table.status === 1">
    ... sale-new directive
  </ng-template>

  <ng-template [ngIf]="!!table && table.status === 2">
    ... sale-show directive
  </ng-template>
</GridLayout>

The TableListComponent changed:

export class TableListComponent {
  @Input() tables: Array<Table>;
  @Output() tableItem: EventEmitter<Table> = new EventEmitter();

  onItemTap(item: Table): void {
    this.tableItem.emit(item);
  }
}

References