Объединив два комментария, я создал этот stackblitz
Я использовал таблицу материалов, потому что мне лень форматировать таблицу.Как уже отмечалось, единственное, что нам нужно для использования таблицы матов, это поставить в качестве источника данных элементы управления массива форм
dataSource = this.myformArray.controls;
Столбцы таблицы становятся похожими на
<ng-container matColumnDef="surname">
<th mat-header-cell *matHeaderCellDef> Surname </th>
<td mat-cell *matCellDef="let element">
<input arrow-div [formControl]="element.get('surname')">
</td>
</ng-container>
Да, просто используя [formControl] = element.get ('nameOfField')
Забавная работа - сделать так, чтобы клавиши со стрелками работали для перемещения между "ячейками".Я использую директиву.Но поскольку я ненавижу создавать директиву с @Output()
, я использую вспомогательный сервис.
Если мы не используем сервис, наш .html выглядит как
<input arrow-div [formControl]="element.get('id')" (arrowEvent)="move($event)">
<input arrow-div [formControl]="element.get('name')" (arrowEvent)="move($event)">
<input arrow-div [formControl]="element.get('surname')" (arrowEvent)="move($event)">
...
Если мы используем сервис, наш html становится более прозрачным
<input arrow-div [formControl]="element.get('id')" >
<input arrow-div [formControl]="element.get('name')" >
<input arrow-div [formControl]="element.get('surname')" >
...
И в приложениимы подписываемся на службу.
Служба проста
export class KeyBoardService {
keyBoard:Subject<any>=new Subject<any>();
sendMessage(message:any)
{
this.keyBoard.next(message)
}
}
, просто предмет и метод для отправки значения субъекту.
Директива слушает только еслиКлавиша со стрелкой вниз и отправить ключ отправителю.Ну, я отправляю объект типа {element: ..., acction: ..} для отправки дополнительной информации.
export class ArrowDivDirective {
constructor( private keyboardService:KeyBoardService,public element:ElementRef){}
//@Output() arrowEvent:EventEmitter<any>=new EventEmitter();
@HostListener('keydown', ['$event']) onKeyUp(e) {
switch (e.keyCode)
{
case 38:
this.keyboardService.sendMessage({element:this.element,action:'UP'})
break;
case 37:
if (this.element.nativeElement.selectionStart<=0)
{
this.keyboardService.sendMessage({element:this.element,action:'LEFT'})
e.preventDefault();
}
break;
case 40:
this.keyboardService.sendMessage({element:this.element,action:'DOWN'})
break;
case 39:
if (this.element.nativeElement.selectionStart>=this.element.nativeElement.value.length)
{
this.keyboardService.sendMessage({element:this.element,action:'RIGTH'})
e.preventDefault();
}
break;
}
}
}
Ну, я принимаю во внимание, когда вы в первый раз или в начале ввода отправляете или нет клавишу, когда мы нажимаем lfet и стрелку вправо.
app.componentнужно только подписаться на сервис и использовать ViewChildren для хранения всех входных данных.Будь осторожен!порядок просмотра детей в матричной таблице изменяется сверху вниз и слева направо
@ViewChildren(ArrowDivDirective) inputs:QueryList<ArrowDivDirective>
constructor(private keyboardService:KeyBoardService){}
ngOnInit()
{
this.keyboardService.keyBoard.subscribe(res=>{
this.move(res)
})
}
move(object)
{
const inputToArray=this.inputs.toArray()
const rows=this.dataSource.length
const cols=this.displayedColumns.length
let index=inputToArray.findIndex(x=>x.element===object.element)
switch (object.action)
{
case "UP":
index--;
break;
case "DOWN":
index++;
break;
case "LEFT":
if (index-rows>=0)
index-=rows;
else
{
let rowActual=index%rows;
if (rowActual>0)
index=(rowActual-1)+(cols-1)*rows;
}
break;
case "RIGTH":
console.log(index+rows,inputToArray.length)
if (index+rows<inputToArray.length)
index+=rows;
else
{
let rowActual=index%rows;
if (rowActual<rows-1)
index=(rowActual+1);
}
break;
}
if (index>=0 && index<this.inputs.length)
{
inputToArray[index].element.nativeElement.focus();
}
}
* ОБНОВЛЕНИЕ Если мы хотим добавить динамически столбцы, добавьте две новые переменные (плюсthe "displayColumns"
displayedColumns: string[] = ['name','surname','delete'];
displayedHead:string[]=['Name','Surname']
displayedFields:string[] = ['name','surname'];
И наша таблица становится такой:
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- All columns -->
<ng-container *ngFor="let col of displayedFields;let i=index" [matColumnDef]="col">
<th mat-header-cell *matHeaderCellDef> {{displayedHead[i]}} </th>
<td mat-cell *matCellDef="let element">
<input arrow-div [formControl]="element.get(col)">
</td>
</ng-container>
<!---column delete-->
<ng-container matColumnDef="delete">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element;let i=index;">
<button arrow-div mat-button (click)="delete(i)">delete</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
Новая функция для добавления столбца должна добавить FormControl к каждой FormGroup массива, актуализировать переменные displayColumns,displayHead и displayFields
addColumn()
{
let newField="Column"+(this.displayedFields.length+1)
this.myformArray.controls.forEach((group:FormGroup)=>{
group.addControl(newField,new FormControl())
})
this.displayedHead.push(newField)
this.dataSource = [...this.myformArray.controls];
this.displayedFields.push(newField);
this.displayedColumns=[...this.displayedFields,"delete"];
}
В этом еще один стек Я добавляю эту функцию (также как удалить строку и как создать новую строку)