Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing Input fields inside Angular Material table

I've been trying for days to get data from input fields inside an Angular Material Table.

I am basically populating a table with values that come from an API, however whenever we don't get any date, in my case a course doesn't have a scheduled date set, i am inserting a text box where the value should be displayed so the user can set a date for that specific course.

Like this: Example Note: Sorry for the censoring, work related names had to be removed.

This is my html code:

<mat-card>
    <form  #traineeForm="ngForm">
      <mat-form-field>
        <input  readonly matInput type="text" name="name" [ngModel] = "trainee.name"  #name="ngModel">
      </mat-form-field>
      <mat-form-field>
        <input readonly matInput email type="text"  name="email" [ngModel] = "trainee.email" #email="ngModel">
      </mat-form-field>
      <mat-form-field>
        <input readonly matInput type="text"  name="type" [ngModel] = "trainee.type" #type="ngModel">
      </mat-form-field>
      <button mat-raised-button color ="primary" type ="submit">Edit</button>
      <button mat-raised-button color ="warn" type ="submit" (click)="onDelete(trainee.id)">Delete</button>
    </form>
  </mat-card>
<br>
  <mat-card>
    
      <table mat-table [dataSource]="courses" class="mat-elevation-z8">
      
      <ng-container matColumnDef="courseOrderID">
        <th mat-header-cell *matHeaderCellDef>Course Order ID</th>
        <td mat-cell *matCellDef="let element"> {{element.courseOrderID}}</td>
      </ng-container>
      
       <ng-container matColumnDef="title">
          <th mat-header-cell *matHeaderCellDef>Course Title </th>
          <td mat-cell *matCellDef="let element"> {{element.title}}</td>
      </ng-container>
      <ng-container matColumnDef="description">
          <th mat-header-cell *matHeaderCellDef>Course Description </th>
          <td mat-cell *matCellDef="let element"> {{element.description}}</td>
       </ng-container>
      <ng-container matColumnDef="duration">
          <th mat-header-cell *matHeaderCellDef>Duration </th>
          <td mat-cell *matCellDef="let element"> {{element.duration}}</td>
      </ng-container>
      <ng-container matColumnDef="scheduledDate">
        <th mat-header-cell *matHeaderCellDef>Scheduled Date </th>
      <td mat-cell *matCellDef="let element">
         <mat-form-field>
              <input matInput [matDatepicker]="picker" placeholder="Choose a date">
              <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
              <mat-datepicker #picker></mat-datepicker>
          </mat-form-field>
         {{element.scheduledDate}}</td>
      </ng-container>
      <ng-container matColumnDef="trainer">
          <th mat-header-cell *matHeaderCellDef>Trainer </th>
          <td mat-cell *matCellDef="let element">
              <mat-form-field><input matInput color="warn" *ngIf="!element.trainer"></mat-form-field> {{element.trainer}}</td>
      </ng-container>
      <ng-container matColumnDef="save">
          <th mat-header-cell *matHeaderCellDef></th>
          <td mat-cell *matCellDef="let element">
              <button mat-raised-button color ="primary" type ="submit" (click)="onSaveAssignment(trainee, element, picker)">Save</button></td>
      </ng-container>
      <tr mat-header-row *matHeaderRowDef="coursesdisplayColumns">
      </tr>
      <tr mat-row *matRowDef="let courses; columns: coursesdisplayColumns"></tr>
      </table>
      <br>
 
      </mat-card>

And this is my TypeScript code:

import { Trainee } from '../trainees.model';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { TraineesService } from '../../trainees.service';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { Course } from '../../courses/courses.model';
import { CoursesService } from '../../courses.service';
import { Assignment } from '../../assignments/assignments.model';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-trainee-details',
  templateUrl: './trainee-details.component.html',
  styleUrls: ['./trainee-details.component.css']
})


export class TraineeDetailsComponent implements OnInit, OnDestroy {
  
  private traineeId: string;
  trainee: Trainee;
  assignment: Assignment;
  courses: Course[] = [];
  coursesdisplayColumns = ['courseOrderID', 'title','description','duration','scheduledDate','trainer','save'];
  
  constructor(public traineeService: TraineesService, public route: ActivatedRoute, public coursesService: CoursesService){}

  ngOnInit() {
    this.route.paramMap.subscribe((paramMap: ParamMap) => {
      if(paramMap.has('traineeId')){
        this.traineeId = paramMap.get('traineeId');
        this.trainee = this.traineeService.getTrainee(this.traineeId);
      }
    });
    this.coursesService.getCoursesByJob(this.trainee.job);
    this.coursesService.getCoursesUpdateListener().subscribe((courses: Course[]) =>{
      this.courses = courses;
    });
  }

  onDelete(traineeId: string)
  {
    this.traineeService.deleteTrainee(traineeId);
  }
  onSaveAssignment(trainee: Trainee, selectedCourse: Course, dateForm: Date){
  
    console.log(trainee.id);
    console.log(selectedCourse.description);
    console.log(dateForm);
  }
  ngOnDestroy() {

  }
}

When i call onSaveAssignment(), the trainee ID and course ID are getting logged in the console correctly as those are defined in typescript, but I have no ideea how should i bring that date selected in the interface, i tried with ng-model but it did not work and I had to define a form for each input and still did not work.

Is there any way to get that values from inputs on each row when the Save button is pressed ?

Or if i put 1 button for all of them is there any way to do a foreach on every input value in the interface ?

like image 907
ACristian24 Avatar asked Aug 27 '18 08:08

ACristian24


1 Answers

You can get the values with ngModel by creating an object containing all values using the index as attribute.

In you component, put an object:

public myDates : any = {};

Then use ngModel with the index for your input date:

<ng-container matColumnDef="scheduledDate">
  <th mat-header-cell *matHeaderCellDef>Scheduled Date </th>
  <td mat-cell *matCellDef="let element; let i = index">
    <mat-form-field>
      <input matInput [(ngModel)]="myDates[i]" [matDatepicker]="picker" placeholder="Choose a date">
      <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-datepicker #picker></mat-datepicker>
    </mat-form-field>
  </td>
</ng-container>

For each row, it will add an attribute to the object myDates. Using index permits to guarantee uniqueness. Your object will look like: {1: date1, 2: date2 ...}.

Then you can get the value by knowing the index of the row. You can get it directly when clicking on the button:

<ng-container matColumnDef="save">
  <th mat-header-cell *matHeaderCellDef></th>
  <td mat-cell *matCellDef="let element; let i = index">
    <button mat-raised-button color ="primary" type ="submit" (click)="onSaveAssignment(trainee, element, myDates[i])">Save</button>
  </td>
</ng-container>
like image 50
Powkachu Avatar answered Nov 05 '22 19:11

Powkachu