Встроенный редактируемый шаблон Angular Mat Table не работает для пустой ячейки данных

У меня есть таблица Angular Mat со встроенным редактированием. С приведенным ниже кодом встроенное редактирование отлично работает для матовой ячейки с записью, но для ячейки с нулевыми значениями или пустой записью встроенное редактирование не работает. я был бы рад, если бы даже пустая ячейка мата была обновлена ​​​​и отредактирована с некоторым значением. Любой обходной путь, который позволит выполнить это требование введите здесь описание изображения

таблица-основной-example.html

  <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
    
        <!--- Note that these columns can be defined in any order.
            The actual rendered columns are set as a property on the row definition" -->
    
        <!-- Position Column -->
        <ng-container matColumnDef="position">
            <th mat-header-cell *matHeaderCellDef> No. </th>
            <td mat-cell *matCellDef="let element"> {{element.position}} </td>
        </ng-container>
    
        <!-- Name Column -->
        <ng-container matColumnDef="name">
            <th mat-header-cell *matHeaderCellDef> Name </th>
            <td mat-cell *matCellDef="let element;let index = index">
                <editable (update)="updateField(index, 'name')">
                    <ng-template viewMode>
                        {{element.name}}
                    </ng-template>
                    <ng-template editMode>
                        <mat-form-field class="example-full-width">
                            <input matInput [formControl]="getControl(index, 'name')">
                            <mat-error *ngIf="getControl(index, 'name').hasError('required')">
                                Field is <strong>required</strong>
                            </mat-error>
                        </mat-form-field>
                        <!-- <input  [formControl]="getControl(index, 'name')" focusable editableOnEnter> -->
                    </ng-template>
                </editable>
            </td>
    
    
        </ng-container>
    
        <!-- Weight Column -->
        <ng-container matColumnDef="weight">
            <th mat-header-cell *matHeaderCellDef> Weight </th>
            <td mat-cell *matCellDef="let element;let index = index">
                <editable (update)="updateField(index, 'weight')">
                    <ng-template viewMode>
                        {{element.weight}}
                    </ng-template>
                    <ng-template editMode>
                        <input  [formControl]="getControl(index, 'weight')" focusable editableOnEnter>
            </ng-template>
                </editable>
            </td>
        </ng-container>
    
        <!-- Symbol Column -->
        <ng-container matColumnDef="symbol">
            <th mat-header-cell *matHeaderCellDef> Symbol </th>
            <td mat-cell *matCellDef="let element;let index = index">
                <editable (update)="updateField(index, 'symbol')">
                    <ng-template viewMode>
                        {{element.symbol}}
                    </ng-template>
                    <ng-template editMode>
                        <input  [formControl]="getControl(index, 'symbol')" focusable editableOnEnter>
            </ng-template>
                </editable>
            </td>
        </ng-container>
    
        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
    </table>

таблица-основной-example.ts

import { Component } from '@angular/core';
import { FormControl, FormArray, FormGroup, Validators } from '@angular/forms';

import {CoreService} from './services/core.service';

/**
 * @title Basic use of `<table mat-table>`
 */
@Component({
  selector: 'table-basic-example',
  styleUrls: ['table-basic-example.css'],
  templateUrl: 'table-basic-example.html',
})
export class TableBasicExample {
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = this.core.list$;
  controls: FormArray;

  constructor(private core: CoreService){}

  ngOnInit() {
   
    const toGroups = this.core.list$.value.map(entity => {
      return new FormGroup({
        position:  new FormControl(entity.position, Validators.required),
        name: new FormControl(entity.name, Validators.required), 
        weight: new FormControl(entity.weight, Validators.required),
        symbol: new FormControl(entity.symbol, Validators.required)
      },{updateOn: "blur"});
    });

    this.controls = new FormArray(toGroups);

  }


  updateField(index, field) {
    const control = this.getControl(index, field);
    if (control.valid) {
      this.core.update(index,field,control.value);
    }

   }

  getControl(index, fieldName) {
    const a  = this.controls.at(index).get(fieldName) as FormControl;
    return this.controls.at(index).get(fieldName) as FormControl;
  }

}

edit-mode.directive.ts

import { Directive, TemplateRef } from '@angular/core';

@Directive({
  selector: '[editMode]'
})
export class EditModeDirective {
  constructor(public tpl: TemplateRef<any>) { }
}

editable.component.ts

import { Component, ContentChild, HostListener, ElementRef, EventEmitter, Output, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { ViewModeDirective } from './view-mode.directive';
import { EditModeDirective } from './edit-mode.directive';
import { NgControl } from '@angular/forms';
import { fromEvent, Subject } from 'rxjs';
import { switchMap, takeUntil, filter, take, switchMapTo } from 'rxjs/operators';
import { untilDestroyed } from 'ngx-take-until-destroy';

@Component({
  selector: 'editable',
  template: `
    <ng-container *ngTemplateOutlet="currentView"></ng-container>
  `,
  styleUrls: ['./editable.component.css']
})
export class EditableComponent {
  @ContentChild(ViewModeDirective) viewModeTpl: ViewModeDirective;
  @ContentChild(EditModeDirective) editModeTpl: EditModeDirective;
  @Output() update = new EventEmitter();

  editMode = new Subject();
  editMode$ = this.editMode.asObservable();

  mode: 'view' | 'edit' = 'view';


  constructor(private host: ElementRef) {
  }

  ngOnInit() {
    this.viewModeHandler();
    this.editModeHandler();
  }

  toViewMode() {
    this.update.next();
    this.mode = 'view';
  }

  private get element() {
    return this.host.nativeElement;
  }

  private viewModeHandler() {
    fromEvent(this.element, 'dblclick').pipe(
      untilDestroyed(this)
    ).subscribe(() => { 
      this.mode = 'edit';
      this.editMode.next(true);
    });
  }

  private editModeHandler() {
    const clickOutside$ = fromEvent(document, 'click').pipe(
      filter(({ target }) => this.element.contains(target) === false),
      take(1)
    )

    this.editMode$.pipe(
      switchMapTo(clickOutside$),
      untilDestroyed(this)
    ).subscribe(event => this.toViewMode());
  }

  get currentView() {
    return this.mode === 'view' ? this.viewModeTpl.tpl : this.editModeTpl.tpl;
  }

  ngOnDestroy() {
  }

}

редактируемый.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { EditableComponent } from './editable.component';
import { ViewModeDirective } from './view-mode.directive';
import { EditModeDirective } from './edit-mode.directive';
import { FocusableDirective } from './focusable.directive';
import { EditableOnEnterDirective } from './edit-on-enter.directive';
import { MaterialModule } from 'app/material/material.module';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { ClickOutsideModule } from 'ng-click-outside';

@NgModule({
    declarations: [],
    imports: [
        CommonModule,
        MaterialModule,
        FormsModule,
        ReactiveFormsModule,
        ClickOutsideModule
    ],
    exports: [
    ]
})

export class EditableModule { }

вид-mode.directive.ts

import { Directive, TemplateRef } from '@angular/core';

@Directive({
  selector: '[viewMode]'
})
export class ViewModeDirective {

  constructor(public tpl: TemplateRef<any>) { }

}

person subash    schedule 06.10.2020    source источник


Ответы (1)


Я нашел вас с проблемой, которая у меня была. После некоторого расследования и просмотра вашего кода мы сделали ту же ошибку.

Мы забыли объявить все директивы.

declarations: [
    ....
    EditModeDirective,
    EditableOnEnterDirective,
    ViewModeDirective,
    EditableOnClickDirective,
    FocusableDirective
  ],

Ничто в Angular не показывает, что директива не пропущена. Я вроде понимаю почему.

person AFetter    schedule 22.10.2020
comment
Я столкнулся с той же проблемой, похоже, у меня есть 4 из 5 директив, но я не смог найти EditableOnClickDirective. Поделитесь, как выглядит ваш? - person plattitude; 26.01.2021
comment
@plattitude, давайте наоборот, поделитесь своим кодом, и я помогу вам с этим. - person AFetter; 27.01.2021