Trigger functions on a universal component from the nested component

I am currently working on an Angular project with two components, one being a generic component where the table is defined and the other being a component that invokes this table by passing the required data.

However, I encountered an issue where the table generates a delete button for each record, but the delete function is part of the specific component, not the generic one.

My question is: Is there a way to only call the table.component and then trigger the delete function?

Below is the code for the generic component, table.component.html:

<mat-table [dataSource]="dataSource" matSort class="m-3 mat-elevation-z4">

    <ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">

        <ng-container *ngIf="column != 'actions'">
            <mat-header-cell *matHeaderCellDef mat-sort-header> {{ column | titlecase }} </mat-header-cell>
            <mat-cell *matCellDef="let element">{{ element[column] }}</mat-cell>
        </ng-container>

        <ng-container *ngIf="column == 'actions'">
            <mat-header-cell *matHeaderCellDef> Actions </mat-header-cell>
            <mat-cell *matCellDef="let row;let i = index" class="container-button">
            <button at-icon-button matTooltip="Delete" (click)="testDelete(dataSource.data[i])">
                <mat-icon>delete_forever</mat-icon>
            </button>
            </mat-cell>
        </ng-container>

    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>

</mat-table>

And here is the code for the table.component.ts file:

@Input('dataSource') public dataSource: MatTableDataSource<any>;
@Input('displayedColumns') public displayedColumns: string[];

As for the child component, test1.component.html:

<app-table-edit
  [dataSource]="dataSource"
  [displayedColumns]="displayedColumns">  
</app-table-edit>

The test1.component.ts file contains the following code:

public dataSource: MatTableDataSource<Company>;

const company = [
   {
      "name":"test2Dyn",
      "phoneNumber":null,
      "province":null
   },
   {
      "name":"test3Prov",
      "phoneNumber":null,
      "province":"Álava"
   }
]

this.dataSource = new MatTableDataSource(company);

public displayedColumns: string[] = ['name','phoneNumber','province','actions']

In addition, we have the generic service responsible for invoking endpoints, api.service.ts:

constructor(
    private httpClient: HttpClient,
    private tConstructor: { new (m: Partial<T>, ...args: unknown[]): T },
    protected apiUrl: string
  ) {}

public delete(id: number): Observable<void> {
    return this.httpClient.delete<void>(`${this.apiUrl}/${id}`);
  }

Lastly, we have the service specific to the child component, test1.service.ts:

constructor(
    private http: HttpClient
  ) {
    super(http, Company, 'http://localhost:8080/company');
  }

So, my main issue lies in finding the best approach to call the delete() service when the delete button in the table is clicked. Any suggestions would be greatly appreciated!

Answer №1

In the table.component.ts file, an Output is defined

@Output() onDelete=new EventEmitter<any>()

This is utilized in the .html file as shown below:

    <button at-icon-button matTooltip="Delete" (click)="onDelete.emit(row)">
        <mat-icon>delete_forever</mat-icon>
    </button>

Thus, the test1.component.html now contains:

<app-table-edit
  [dataSource]="dataSource"
  [displayedColumns]="displayedColumns"> 
  (onDelete)="delete($event)" 
</app-table-edit>

And when an element is deleted in test1.component.ts:

delete(item:any)
{
  this.delete<void>(`${this.apiUrl}/${item.id}`).subscribe(_=>{
     //when delete we remove the element from the dataSource
     
     this.company=this.company.filter(x=>x.id!=item.id);
     this.dataSource = new MatTableDataSource(this.company);
  });
}

NOTE:Update code after validation.

Answer №2

It seems like you're in need of assistance with implementing a basic service. Check out the angular services documentation for more information.

To use your generic service in table.component.ts, simply include it in the constructor like this:

table.component.ts:

constructor(private myService: MyService) {}

You can then utilize the delete function provided by the service in this manner:

 function testDelete(data)
 {
      this.myService.delete(data.id) // keep in mind that the id may be accessed differently
      .subscribe(() => (console.log(this.response)));
 }

In this example, I am logging any responses you may receive, but for deletes, you might only want to display errors. Refer to this link for more details https://rxjs.dev/guide/subscription

Answer №3

If you're looking for a versatile solution, I recommend checking out this dynamic datatable that is demonstrated here.

You can find the implementation of the datatable in action on this page:

<bs-datatable #table [settings]="settings" [data]="artists" (reloadData)="loadArtists()">
  <div *bsDatatableColumn="{ sortable: true, name: 'Name' }">
    1. Artist
  </div>
  <div *bsDatatableColumn="{ sortable: true, name: 'YearStarted' }">
    2. Year started
  </div>
  <div *bsDatatableColumn="{ sortable: true, name: 'YearQuit' }">
    3. Year quit
  </div>

  <ng-template bsRowTemplate let-artist>
    <tr>
      <td class="text-nowrap">{{ artist.name }}</td>
      <td class="text-nowrap">{{ artist.yearStarted }}</td>
      <td class="text-nowrap">{{ artist.yearQuit }}</td>
      <td class="text-nowrap">
        <button (click)="doSomething()">Delete</button>
      </td>
    </tr>
  </ng-template>
</bs-datatable>

Key points to consider:

  • The use of *bsDatatableColumn acts as equivalent to
    <ng-template bsDatatableColumn><div>...</div></ng-template>
    , setting the template on the BsDatatableComponent.
  • <ng-template bsRowTemplate let-artist>
    can alternatively be expressed as
    <tr *bsRowTemplate="{ artist: $implicit }">

The function of the BsRowTemplateDirective involves binding the row template to the BsDatatableComponent, facilitating structured presentation.

@Directive({ selector: '[bsRowTemplate]' })
export class BsRowTemplateDirective {
  constructor(private datatableComponent: BsDatatableComponent, templateRef: TemplateRef<any>) {
    this.datatableComponent.rowTemplate = templateRef;
  }
}

Within the BsDatatableComponent, template projection is enacted through:

 <ng-container *ngTemplateOutlet="rowTemplate; context: { $implicit: item }"></ng-container>

However, orchestrating the migration of your code snippet to relocate the row template may present challenges.

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

Is there a way to incorporate an external JavaScript file into a .ts file without the need for conversion?

I have an external JavaScript file that I need to utilize in a .ts file without performing any conversion. Does anyone know how to use it within TypeScript without the need for conversion? ...

Comparing vue.component to using import statements inside a component

After setting up a vue2 library using vue-cli, I have numerous components included in the index.ts file as shown below: import MyComponent1 from './components/MyComponent1.vue'; import MyComponent2 from './components/MyComponent2.vue'; ...

Internal Server Error in Angular 2+ and Laravel Integration

Facing an issue with a post request from Angular to Laravel where I am encountering an Internal Server Error, although it works perfectly fine in Postman. api.php <?php use Illuminate\Http\Request; Route::post('/addHouse&ap ...

Unassigned variable in need of initialization within Angular 2

There seems to be an issue with the two-way data binding not functioning correctly. I am trying to retrieve the data using {user | json}, but I encounter an error when using [(ngModel)] = "user.username". Data Model export interface UserModel { ...

The Proper Way to Position _app.tsx in a Next.js Setup for Personalized App Configuration

I've been working on a Next.js project and I'm currently trying to implement custom app configuration following the guidelines in the Next.js documentation regarding _app.tsx. However, I'm encountering some confusion and issues regarding the ...

An Unexpected Error Occurred While Importing HttpClientModule in Angular's Tour of Heroes

Currently, I am working through the Angular tutorial for beginners. You can find the tutorial here. Following the instructions to import the HttpClientModule, I encountered the error message below. I need assistance with this issue. I am running npm on a ...

The JSX element with type 'Component' does not support any construct or call signatures at this time

I am facing an issue with the following code snippet const pageArea = (Component:ReactNode,title:string) => ({ ...props }) => { return ( <> <div> { Component && (<Component { ...

Issue with HTML-Files and Angular: ESLint is throwing an error where it cannot read properties of undefined (reading '0'). This error occured during the linting process

I'm currently working on a new project using Angular 15 and I've integrated ESLint to help with error checking. So far, it's been effective for .ts files, fixing errors when I save them. However, I encountered an issue where ESLint wasn&apo ...

Triggering ngSubmit function when button is clicked inside an Ionic alert

My ionic app is up and running, utilizing a template driven form in Angular to gather user input. I'm using ngSubmit to pass this data to my ts.file. My challenge lies in triggering the ngSubmit function through a 'No and save data' button w ...

Encountering an issue with Angular Flex Layout after including the layout module

Upon adding FlexLayoutModule to the imports section of my app.module.ts, I encountered the following error: ERROR: The target entry-point "@angular/flex-layout" is missing dependencies: - @angular/core - @angular/common - rxjs - @angular/pla ...

In Vue3, automatically infer a type for a slotProp based on the modelValue

In simplifying the component I aim to create, I have created the following code structure: // MyComp.vue <script setup lang="ts"> import { PropType, defineProps, defineEmits } from 'vue'; const props = defineProps({ modelVal ...

Running Jenkins in a Docker container to initiate the process of building an Angular application within a

Recently, I began my journey of learning Jenkins and successfully launched it on Docker. Now, I have a project built in Angular along with a Dockerfile created to produce a Docker image. However, when attempting to start the process from Jenkins, an erro ...

What is the process for switching views by tapping on a button?

Currently, I am working on a registration form that consists of 3 steps. I need to change the view of the form to another view when clicking the Next button. I have been attempting to achieve this in Angular 2 by using routing, but it seems to be replacin ...

Invalid NPM package detected while deploying: @types

As I try to set up my first application with Azure's continuous development, I am facing some issues. The app is a standard template from Visual Studio 2017 MVC net core 2.0, using React. After pushing the app to my GitHub repository and configuring a ...

The program failed to retrieve the 'messages' property as it was undefined

I encountered an issue while trying to push a response from an HTTP service onto an array. The error message reads as follows: Cannot read property 'messages' of undefined The problematic section lies within my chat.component.ts file: import { ...

Enhance your Angular Material Table with split headers and sticky header capabilities

I am having an issue with the header of my Angular Material table. I need help adding a sticky header feature. I tried using sticky: true, but it's not working for my first column since I have hidden it. Additionally, the first row is displaying the ...

Is it possible for me to create a union type that connects parameters and responses in a cohesive manner

I'm interested in creating a custom type that functions can use to indicate to callers that an input parameter of a specific type corresponds to a certain output type. For instance, consider the following scenario: type ResponseMap = { requestPath: ...

Encountered a technical issue while attempting to assign a value in Angular

In my Angular application, I have defined an object called Task: export class Task { taskId: number; description: string; date: string; project: Project; } Within a component, I am working on implementing a method that will add a new task. To ac ...

Ways to display JSON data in Angular 2

My goal is to display a list of JSON data, but I keep encountering an error message ERROR TypeError: Cannot read property 'title' of undefined. Interestingly, the console log shows that the JSON data is being printed. mydata.service.ts import { ...

Error in VS Code related to Vue Array Prop JSDoc TypeScript: The properties of type 'ArrayConstructor' are not found in type 'MyCustomType[]'

After reading the article "Why I no longer use TypeScript with React and why you might want to switch too", I decided to work on a Vue CLI project using ES6 without TypeScript. Instead, I enabled type checking in Visual Studio Code by utilizing JSDoc / @ty ...