2

I have a table that is populated using the *ngFor directive. A user can click on each cell in the table and edit it's value by virtue of the 'contentEditable' attribute. The current implementation updates the data in the table but doesn't update the data in the component. Is it possible to update the data in the component when the user changes the data in the cell with tools native to angular 2? If so, how?

This is the html file:

<table id="data-table" class="table table-striped">
    <thead>
      <tr>
        <th *ngFor="let round of rounds">{{ round.title }}</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let player of players">
        <td contenteditable="true">{{ player.name }}</td>
        <td contenteditable="true">{{ player.round1 }}</td>
        <td contenteditable="true">{{ player.round2 }}</td>
        <td contenteditable="true">{{ player.round3 }}</td>
      </tr>
    </tbody>
  </table>

This is the component:

import { Component, OnInit } from '@angular/core';
import { BooksAndRunService } from '../books_and_run.service';



@Component({
  moduleId: module.id,
  selector: 'books-and-run-play',
  templateUrl: './books_and_run_play.component.html',
  styleUrls: ['./books_and_run_play.component.css'],
})


export class BooksAndRunPlayComponent implements OnInit {
  constructor(private booksAndRunService: BooksAndRunService) { }
  currentRound = 1;

  rounds = [
    {title: ""},
    {title: "Round 1"},
    {title: "Round 2"},
    {title: "Round 3"},
    {title: "Round 4"},
    {title: "Round 5"},
    {title: "Round 6"},
    {title: "Round 7"},
  ]

  players = [
    {
      name: "Bob",
      round1: 0,
      round2: 0,
      round3: 0,
      round4: 0,
      round5: 0,
      round6: 0,
      round7: 0,
    },
    {
      name: "Joe",
      round1: 0,
      round2: 0,
      round3: 0,
      round4: 0,
      round5: 0,
      round6: 0,
      round7: 0,
    },
    {
      name: "Jim",
      round1: 0,
      round2: 0,
      round3: 0,
      round4: 0,
      round5: 0,
      round6: 0,
      round7: 0,
    },
    {
      name: "Sarah",
      round1: 0,
      round2: 0,
      round3: 0,
      round4: 0,
      round5: 0,
      round6: 0,
      round7: 0,
    },
    {
      name: "Jane",
      round1: 0,
      round2: 0,
      round3: 0,
      round4: 0,
      round5: 0,
      round6: 0,
      round7: 0,
    },
    {
      name: "Jill",
      round1: 0,
      round2: 0,
      round3: 0,
      round4: 0,
      round5: 0,
      round6: 0,
      round7: 0,
    },
  ];



  ngOnInit(): void {
    // this.players = this.booksAndRunService.getPlayers();

  }

}

1 Answer 1

2

When using contenteditable="true" you don't get the ngModel attribute, therefore you need to create your own 2 way data binding as such:

<td contenteditable="true" [textContent]="player.name"   (input)="player.name = $event.target.textContent"></td>

Alternatively you can do this

<td contenteditable="true" [textContent]="player.name"   (input)="onContentChanged($event)"></td>

and then in your component class

onContentChanged(event : Event)
    {
        let playerName : string = event.target.textContent;

        .... Do stuff here ....
    }
Sign up to request clarification or add additional context in comments.

2 Comments

Awesome this works, thanks! Just curious, is this creating an event listener on every cell in the table?
Yes you will have to do this for each element that uses contenteditable="true" if you want to have 2 way data binding. So yeah when ngFor finishes you will end up with an event listener for each element, however that shouldn't be a problem. Just be careful, not to mistake which properties of the object you are calling and that's all :)

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.