Removing Chosen Row in Angular - A Step-by-Step Guide

My issue involves a <mat-radio-button> list. I am encountering an error where the first radio button stops functioning after toggling between the first and second buttons. Additionally, when I click the delete button, it deletes both the first and second rows simultaneously.

For further details, I have included the relevant code below along with a Demo link for your convenience.

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-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));
  }
}

Thank you for your attention to this matter.

Answer №1

The issue at hand is the use of selection.selected, which returns an array of all selected rows when the intention is to delete only a single value from the table. To allow users to delete one row at a time, the focus should be on the last row selected by the user. Removing $event.stopPropagation ensures that clicking either the radio button or row triggers the same event.

<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>

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; // Not required if 'position' is used for deletion
}

While keeping changes minimal and utilizing slice, consider using a unique value like position within each element and filter out the selected position from 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);
}

For a functional demo, visit StackBlitz.

Answer №2

Instead of using radio buttons when deleting one row at a time, consider making some adjustments to your code to meet your needs accordingly.

Keep in mind that although using radio buttons for this purpose may not be the best practice, it can still be an option if needed.

<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>

To update your component and improve the delete functionality, replace your existing delete function with the following code:

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

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

Hopefully, these changes will be beneficial to you. Don't forget to show appreciation by accepting the answer. Thank you!

Explore the working Stackblitz project here

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guaranteeing uniform date structure within JSON entities

Scenario: Working on a new approval system using Angular 8, Spring Boot 2.2.3, and either Oracle 12.1 or PostgreSQL 12.3 Instead of normalizing the form structure, we plan to store metadata in JSON format in our database. The values filled in the form wil ...

The Angular 8 click event operates like a JavaScript onload function

I have integrated my angular application into an iframe portlet. On the parent JSP page, there is a form with an invisible submit button. Clicking this button opens a popup window from an external application. I am attempting to trigger the click event o ...

Location of the bundled Webpack index.html file while running locally on a Nativescript WebView

I am currently working on a hybrid app project that involves both NativeScript and Angular. To integrate the two, I have set up a WebView and consolidated all my Angular project files into a folder within my NativeScript project. As part of this setup, I ...

I am unable to properly display the OpenLayers map until I resize the window

This is how I configured the map: this.map = new Map({ target: 'map', layers: [new TileLayer({source: new OSM()}) ], view: new View({ center: [0, 0], zoom: 16, }) }); When I first load the page, it looks like this: before res ...

When comparing two identical strings, the result is not true

Currently, I am conducting a comparison between the value of a checkbox and the values within an array of strings. The process involves printing out each comparison for analysis, as shown below: checkSkillLevel(index: number, level: string){ console.log(t ...

A guide on resolving deprecated warnings for typographical errors

Every time I try to npm install I am bombarded with numerous errors. typings WARN deprecated 9/9/2016: "registry:dt/node#6.0.0+20160831021119" is deprecated (updated, replaced or removed) My experiences with typescript have been nothing but a series ...

The Angular Material date picker unpredictably updates when a date is manually changed and the tab key is pressed

My component involves the use of the Angular material date picker. However, I have encountered a strange issue with it. When I select a date using the calendar control, everything works fine. But if I manually change the date and then press the tab button, ...

The Angular authentication guard is encountering issues resolving all parameters

I am attempting to create an auth.guard.service but I am encountering an error Can't resolve all parameters for AuthGuard: (?, [object Object]).. Here is the code snippet for the service: import { Observable } from 'rxjs/Observable'; // imp ...

Customized object property names for an array of generic object types

I am working with an object in Typescript that has a data property structured like this: type MyThing = { data: { options: { myKey: string, myValue: string }[], key: 'myKey', value: 'myValue' } } I want ...

Updating an Angular 2 project for the MEAN Stack development platform

A few weeks back, I embarked on an Angular2 project by following the "Tour of Heroes" tutorial. As I progressed, my project grew in complexity with routers, rest services, and hundreds of lines of code. Now, as I look to transition my project to the MEAN ...

Integrate a marker onto a Leaflet map within a separate Angular component

In my Angular project, I created a const map variable in my mapComponent to add custom markers on a map. Now I'm wondering how I can achieve the same functionality from different Angular components while using the same map instance? ...

JavaScript 2 add or remove a class to the keyboard when opening or closing

As I work on developing an app in Ionic 2, I am facing a challenge where the background image needs to change when the keyboard is opened and closed in an input field. <ion-content padding class="bg_gogreen"> <ion-list> <ion-item class=" ...

What is the best way to trigger an event within an Angular app using RxJS in version 10?

As I venture into the world of Angular10, I find myself experimenting with a Canvas and honing my skills in drawing on it. Let's refer to the object drawn on the canvas as a "Foobar" - my Angular10 code for drawing Foobars is coming along nicely. Util ...

How to handle type errors when using properties in Vue3 Single File Components with TypeScript

I've hit a roadblock while attempting to utilize properties in Vue3. Despite trying various methods, I keep facing issues during the type-check phase (e.g.: yarn build). The project I'm working on is a fresh Vue3-ts project created using Vite. B ...

Calling a typed function with conditional types in Typescript from within another function

In my attempt to create a conditional-type function, I stumbled upon this question on Stack Overflow. Unfortunately, it seems that the approach doesn't work well with default values (regardless of where the default value is placed). Following the advi ...

How about utilizing a map with arrays for this object?

Currently, I am delving into the realms of JS and TypeScript with a focus on generating separate React components for specific items. Allow me to introduce you to an example object: var regions = { NA: ["US", "ABC1"], EU: ["GB", "LX", "IT"], F ...

Encountering an "error: not assignable to type" message while attempting to modify a field in Prisma

As a newcomer to Prisma, I am facing an issue while trying to update a field based on a foreign key. The error message I receive is: Type '{ authorId: number; }' is not assignable to type 'PatientWhereUniqueInput'. Here is my schema f ...

Issues with two-way binding in Ionic 4 and Electron causing errors

Summary: Utilizing Ionic 4 and Electron. Implementing code in my partym.page.html as illustrated below: <ion-item> <ion-label>Name1</ion-label> <ion-input type="text" [(ngModel)]="name1"></ion-input> </ion-item&g ...

Encountering an error while attempting to combine the .Where and .OrderBy functions in Angular fire

I've spent the entire day attempting to make this work. It seems to function with one of the components, but not with both of them together. I keep getting a console error indicating that I must create an index in Firestore. However, I require my data ...

What is the correct way to invoke a function from an external JavaScript file using TypeScript?

We are currently experimenting with incorporating Typescript and Webpack into our existing AngularJS project. While I have managed to generate the webpack bundle, we are facing an issue at runtime where the program is unable to locate certain functions in ...