2

I'm using <mat-radio-button> list. When I click first and then I click second than I click first back. When I click the first radio button back it not function. And then when I click delete button, it deletes first and second.

I provided the code below and a Demo link for your reference.

HTML

    <div class="example-container mat-elevation-z8">
  <mat-chip class="pointer" mat-raised-button color="primary" (click)="removeSelectedRows()">
    Remove Selected Rows
  </mat-chip>
  <mat-table #table [dataSource]="dataSource">

    <!-- Checkbox Column -->
    <ng-container matColumnDef="select">
      <mat-header-cell *matHeaderCellDef>
        <!-- <mat-checkbox (change)="$event ? masterToggle() : null"
                      [checked]="selection.hasValue() && isAllSelected()"
                      [indeterminate]="selection.hasValue() && !isAllSelected()">
        </mat-checkbox> -->
      </mat-header-cell>
      <mat-cell *matCellDef="let row">
        <mat-radio-button (click)="$event.stopPropagation()"
                      (change)="$event ? selection.toggle(row) : null"
                      [checked]="selection.isSelected(row)">
        </mat-radio-button>
      </mat-cell>
    </ng-container>

    <!-- Position Column -->
    <ng-container matColumnDef="position">
      <mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.position}} </mat-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container matColumnDef="name">
      <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
    </ng-container>

    <!-- Weight Column -->
    <ng-container matColumnDef="weight">
      <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell>
    </ng-container>

    <!-- Symbol Column -->
    <ng-container matColumnDef="symbol">
      <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"
             (click)="selection.toggle(row)">
    </mat-row>
  </mat-table>

    <mat-paginator #paginator
                 [pageSize]="3"
                 [pageSizeOptions]="[5, 10, 20]"
                 >
  </mat-paginator>

</div>

Component

    displayedColumns = ['select', 'position', 'name', 'weight', 'symbol'];
  data = Object.assign( ELEMENT_DATA);
  dataSource = new MatTableDataSource<Element>(this.data);
  selection = new SelectionModel<Element>(true, []);


  @ViewChild(MatPaginator) paginator: MatPaginator;

  ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
  }

  constructor(){
    console.log(this.data);
  }

  /** Whether the number of selected elements matches the total number of rows. */
  isAllSelected() {
    const numSelected = this.selection.selected.length;
    const numRows = this.dataSource.data.length;
    return numSelected === numRows;
  }

  removeSelectedRows() {
    console.log(this.selection.selected)
     this.selection.selected.forEach(item => {
      let index: number = this.data.findIndex(d => d === item);
      console.log(this.data.findIndex(d => d === item));
      this.dataSource.data.splice(index,1);

      this.dataSource = new MatTableDataSource<Element>(this.dataSource.data);
    });
    this.selection = new SelectionModel<Element>(true, []);
    console.log(this.selection)
  }

  /** Selects all rows if they are not all selected; otherwise clear selection. */
  masterToggle() {
    this.isAllSelected() ?
      this.selection.clear() :
      this.dataSource.data.forEach(row => this.selection.select(row));
  }
}

Thanks and Regards.

INDRAJITH EKANAYAKE
  • 3,894
  • 11
  • 41
  • 63
swapy
  • 126
  • 4
  • 11

2 Answers2

1

Your problem here is that you're trying to use selection.selected which returns an array of all the rows that selected when in fact you want to only delete a single value from the table. If we want the user to be able to delete only a single row at a time, we only need to worry about the last row that was selected by the user. We can get rid of $event.stopPropagation so that whether the user clicks on the radio button or the row, the same event is triggered.

<mat-cell *matCellDef="let element; let i = index">
    <mat-radio-button [checked]="selectedIndex === i">
    </mat-radio-button>
</mat-cell>

...

<mat-row *matRowDef="let row; let i = index; columns: displayedColumns;" (click)="selectedIndex = i">
</mat-row>

Then in your component

selectedIndex: number;

removeSelectedRows() {
    let index: number = this.selectedIndex;
    this.dataSource.data = [...this.dataSource.data.slice(0, index), ...this.dataSource.data.slice(index + 1)];
    this.selectedIndex = null; // This will not be required when position is used to delete element
}

I've tried not to change too much in your code and do this using slice but IMO it would be better to use a unique value within Element like position and use filter to filter out the selected position from the dataSource.data.

<mat-cell *matCellDef="let element">
    <mat-radio-button [checked]="selectedPosition === element.position">
    </mat-radio-button>
</mat-cell>

...

<mat-row *matRowDef="let row; columns: displayedColumns;" (click)="selectedPosition = row.position">
</mat-row>

In the component

selectedPosition: number;

removeSelectedRows() {
    this.dataSource.data = this.dataSource.data.filter(element => element.position !== this.selectedPosition);
}

Here is a working example on StackBlitz.

nash11
  • 8,220
  • 3
  • 19
  • 55
1

If you are deleting one row at a time it's no point of using radio buttons. I have done a few changes in your code and create output according to your requirement,

Note: even though it is bad practice if you want to use radio buttons This is the answer

<mat-chip class="pointer" mat-raised-button color="primary" (click)="removeSelectedRows(element)">
        Remove Selected Rows
    </mat-chip>
    <mat-table #table [dataSource]="dataSource">


        <!-- Checkbox Column -->
        <ng-container matColumnDef="select">
            <mat-header-cell *matHeaderCellDef>
            </mat-header-cell>
            <mat-cell *matCellDef="let element;let i = index; ">
                <mat-radio-button (click)="rowIndex(i)">
                </mat-radio-button>
            </mat-cell>
        </ng-container>

in your component replace your delete function with following code,

index: number;
rowIndex(i){
this.index=i;
}

removeSelectedRows(element) {
      this.dataSource.data.splice(this.index,1);
      this.dataSource._updateChangeSubscription();
  }

Hope this will help. Don't forget to accept the answer. Thanks

This is working Stackblitz project

INDRAJITH EKANAYAKE
  • 3,894
  • 11
  • 41
  • 63
  • 1
    Thank you so much for your answer... i feel so bad – swapy Aug 27 '19 at 07:40
  • 1
    what's the issue this is perfect to the point and easy to understand and this is working perfectly – INDRAJITH EKANAYAKE Aug 27 '19 at 09:00
  • @swapy edited my answer this is compliely working plese can you look again – INDRAJITH EKANAYAKE Aug 27 '19 at 09:10
  • could you give me link stackblitz that you make gif image? – swapy Aug 27 '19 at 09:39
  • @IndrajithEkanayake - please don't pressurize the questioner to accept your answer. That is up to the questioner to decide. Instead justify how your answer is better than the others. While `_updateChangeSubscription` will work, it is doing a lot of other things under the hood which you don't need to do for just simply adding a row. So while your answer may seem easy to understand, remember you are calling a function which has code in it. So what you could easily do in 1 line of code is now 30 odd lines easily. – nash11 Aug 28 '19 at 05:52
  • Please don't get me wrong, this isn't out of spite. We're all here to learn. If you can justify how your answer is better, you can get my upvote as well :) – nash11 Aug 28 '19 at 05:56
  • @swapy - This method is also rerendering your `paginator` and `sort` which is not required. – nash11 Aug 28 '19 at 06:05