0

I have an ng-table which is a child component of my main page. When a row is clicked, it sends the information in that row via onCellClick using an EventEmitter. I'm trying to send this information to another child component. This happens to be a button which is the child of a Bootstrap 4 modal which pops up when a button on the main page is clicked. Just having trouble with the receiving and manipulation of that information.This is the main page. The Bootstrap modal pops up whe the center button of the set of three is clicked.Bootstrap modal

HTML of child component table:

<ng-table [config]="config"
      (tableChanged)="onChangeTable(config)"
      (cellClicked)="onCellClick($event)"
      [rows]="rows" [columns]="columns">
</ng-table>

HTML for the child component (this appears in the main page's HTML):

<app-datatable (row)="received($event)"></app-datatable>

Typescript for getting and sending the row's data (this.row is the EvenEmitter. data.row is the actual row that's clicked on):

@Output() row: EventEmitter<any> = new EventEmitter<any>();
public onCellClick(data: any): any {
  let d = data.row.tDataPoint;
  let i = data.row.tICCP;
  let s = data.row.tStartDate;
  let e = data.row.tEndDate;
  let toSend:DataTable = new DataTable(d, i, s, e);
  this.row.emit(toSend);
}

HTML for the button that is the child component of the Bootstrap 4 modal:

<button type="submit" class="btn" data-dismiss="modal" (click)="onClick($event)">Delete</button>

Typescript for the button child component:

selector: 'deletebutton'
@Input() receivedRow:DataTable;
onClick(message:DataTable){
  this.sender.emit('This is from On Click Deletebutton');
  console.log("On Click Deletebutton");
  console.log(this.receivedRow);
  for (let entry in DPS){
    if (DPS[entry].tDataPoint===message.tDataPoint){
    DPS.splice(parseInt(entry),1);
    }
  }
}

HTML of the button child component (this appears in the modal's HTML). This is what should actually be receiving the data from the clicked row as input.

<deletebutton [receivedRow]='row'></deletebutton>

Right now in my onClick method is saying receivedRow is undefined. I feel like what is missing is the coordination between [receivedRow]='row' where I have my deletebutton HTML and the onClick function call in the HTML for that child component. Overall, I just want to click a row, click the button to open the delete Boostrap Modal, and have the correct row be deleted I click the Delete button inside the modal. Let me know if something's not clear or more code is needed.

Is there actually a way to communicate between child components like this using @Input and @Output?

9
  • Your architecture is unclear to me. Maybe post a diagram or give more details. Commented Nov 14, 2016 at 14:30
  • Added screenshots of main page and Bootstrap modal to question. The ng-table HTML is what is in the HTML for the child component. Then I use the app-datatable tag to place that component on the main page since app-datatable is that component's selector. The first set of Typescript is how I send the row's information via EventEmitter. The button HTML is the HTML for the Delete button inside the Bootstrap Modal. This is what I'm trying to send the row's data to. The Typescript after that is attempting to manipulate the row's data based on the @Input. Commented Nov 14, 2016 at 14:52
  • Then the final deletebutton HTML is the HTML that I use to actually render the Delete button in the Bootstrap modal. Let me if this clears things up or you need more information Commented Nov 14, 2016 at 14:54
  • So the delete button is not by row right ? It's for the whole table ? Commented Nov 14, 2016 at 15:01
  • There is only one deletebutton and if I understand your question correctly, it is for the whole table. It is designed to receive the data of whichever row you click on. Commented Nov 14, 2016 at 15:05

2 Answers 2

1

With angular2, your data flow should be :
- down to pass data
- up to send events

So if you really want to go this way, you should have something like that :

diagram

I think there's a better way tho :
For your app AND for your user, it'd be best to have a remove button on each line. This way, it avoid the user to be confused clicking on a row and then click on a remove button and within your code you'll be able to do something like that :

src/app.html :

<table class="table">
  <tr *ngFor="let row of tableData">
    <td *ngFor="let column of row.columns">
      {{ column.name }}
    </td>

    <td (click)="deleteRow(row)"><button>X</button></td>
  </tr>
</table>

<button (click)="addRow()">Add a row</button>

src/app.ts (troncated here to the class only) :

@Component({
  selector: 'app',
  templateUrl: `./src/app.html`,
})
export class App {
  private tableData;
  private cptRow = 1;

  constructor() {
    this.tableData = [
      {
        idRow: `idR${this.cptRow++}`,
        columns: [
          {idColumn: 'idR1C1', name: 'Column 1-1'},
          {idColumn: 'idR1C2', name: 'Column 1-2'},
          {idColumn: 'idR1C3', name: 'Column 1-3'}
        ]
      },
      {
        idRow: `idR${this.cptRow++}`,
        columns: [
          {idColumn: 'idR2C1', name: 'Column 2-1'},
          {idColumn: 'idR2C2', name: 'Column 2-2'},
          {idColumn: 'idR2C3', name: 'Column 2-3'}
        ]
      },
      {
        idRow: `idR${this.cptRow++}`,
        columns: [
          {idColumn: 'idR3C1', name: 'Column 3-1'},
          {idColumn: 'idR3C2', name: 'Column 3-2'},
          {idColumn: 'idR3C3', name: 'Column 3-3'}
        ]
      }
    ];
  }

  deleteRow(row) {
    // we can do this by reference ...
    // this.tableData = this.tableData.filter(r => r !== row);

    // or by ID
    this.tableData = this.tableData.filter(r => r.idRow !== row.idRow);
  }

  addRow() {
    this.tableData.push({
      idRow: `idR${this.cptRow}`,
      columns: [
        {idColumn: `idR${this.cptRow}C1`, name: `Column ${this.cptRow}-1`},
        {idColumn: `idR${this.cptRow}C2`, name: `Column ${this.cptRow}-2`},
        {idColumn: `idR${this.cptRow}C3`, name: `Column ${this.cptRow}-3`}
      ]
    });

    this.cptRow++;
  }
}

Here's a working Plunkr : http://plnkr.co/edit/hNhcdraoDNnI2C92TQvr?p=preview

Now, if you really want to use input/output properties, you should look for tutorials because the structure here seems a bit confused. I can help you to understand that (and it's important to understand it with angular2 !) but maybe you should give me a shout on Gitter/Angular instead of detailing Angular2 flow here :)

Sign up to request clarification or add additional context in comments.

Comments

0

Somewhat of a work around is to place the Delete button component in the HTML for the table component like this:

<ng-table [config]="config"
      (tableChanged)="onChangeTable(config)"
      (cellClicked)="onCellClick($event)"
      [rows]="rows" [columns]="columns">
</ng-table>
<deletebutton [receivedRow]='toSend'></deletebutton>

And still leave the table's tag in the main page's HTML like I had it:

<app-datatable (row)="received($event)"></app-datatable>

And now the row's data is being sent to that Delete button since it is technically a part of the child component of the main page.

Still not able to communicate between child components like I asked in my question though. But this is something close that works.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.