Ag-Grid предоставляет функции для добавления флажков и раскрывающихся списков, но пока я работал над добавлением элементов формы в таблицу, в некоторых сценариях это не давало мне необходимой гибкости.

Поэтому я переключился на FormArrays, которые я всегда использую в любой обычной «таблице» или таблице начальной загрузки.

Я использую очень простой пример отображения списка авторов и книг, написанных этими авторами, в таблице Ag-Grid.

Ниже приведены данные, которые мы собираемся использовать. Это массив объектов, экспортированных из books.ts.

Каждый объект описывает тип книги, нескольких авторов, написавших книги в этом жанре, написанные ими книги и цену каждой книги.

Наши цели будут следующими:

  1. Заполните приведенные выше данные в таблице Ag-Grid, как показано ниже. Мы отобразили тип книги и список авторов, написавших книги под этим конкретным типом книги. Мы использовали переключатели для отображения списка авторов.

2. Всякий раз, когда я нажимаю на автора, написанные им книги будут отображаться в столбце Книги. Каждая строка в таблице независима от других строк.

В этом примере я отобразил книгу и ее цену в 1 столбце, но его можно расширить, добавив еще один столбец с названием «Цена». При выборе конкретной книги ее цена будет отображаться в столбце Цена.

Перейдем к классу AppComponent.

На это может быть довольно сложно смотреть, но если рассматривать один метод за раз, он окажется довольно простым.

Начнем с хука жизненного цикла ngOnInit.

books.books.forEach((data) => {
data.authors.forEach((author: any) => {
author.isSelected = false;
});
});

Сначала мы перебираем массив книг, экспортированный из books.ts. Как видите, свойство authors в JSON представляет собой еще один массив объектов. Каждый объект содержит имя автора и список книг, написанных автором.

На снимке экрана приложения, показанном ранее, перед именем автора стоит переключатель. Чтобы зафиксировать выбранное или невыбранное состояние переключателя, мы добавили дополнительное свойство isSelected для каждого объекта в свойстве authors. Изначально все переключатели не будут выбраны.

this.allBooksFormGroup = new FormGroup({
allBooks: new FormArray(this.loadData()),
});

allBooksFormGroup — это наша корневая группа FormGroup. Чтобы понять, как мы собираемся структурировать JSON в FormArrays, FormGroups и FormControls, посмотрите на скриншот ниже.

  1. allBooksFormGroupсодержит allBooksFormArray. Это соответствует массиву books, который содержит 2 объекта. Точно так же FormArray содержит 2 FormGroups, соответствующие двум объектам.
  2. Каждый объект в массиве books содержит 2 свойства: тип и авторы. Свойство type содержит строковые данные, а свойство authors представляет собой массив объектов. Точно так же каждая FormGroup будет содержать 1 элемент FormControl: bookType и 1 элемент FormArray: authorList.

Теперь, когда теория ясна, давайте проверим, как два вышеуказанных пункта реализуются в коде. Массив allBooksFormArray заполняется из loadData(). Этот метод возвращает массив с именем data, который содержит 2 FormGroups, которые, в свою очередь, содержат 1 FormControl bookType и 1 FormArray authorsList.

loadData() {
let data: any = [];
books.books.forEach((item) => {
data.push(
new FormGroup({
bookType: new FormControl(item.type),
authorsList: new FormArray(this.loadAuthors(item.authors)),
})
);
});
return data;
}

3. Собственно авторами является массив объектов. Каждый объект содержит 3 свойства: name, isSelected и books. Свойство name содержит строковые данные, isSelected содержит логические данные, а свойство books представляет собой массив объектов. Аналогично, FormArray authorsList будет содержать несколько FormGroups, и каждая FormGroup будет содержать 2 FormControls: authorName и isSelected и 1 FormArray: bookList.

authorsListFormArray заполняется с помощью loadAuthors().

loadAuthors(authors) {
let data: any = [];
authors.forEach((author: any) => {
data.push(
new FormGroup({
authorName: new FormControl(‘’),
isSelected: new FormControl(author.isSelected),
bookList: new FormArray(this.loadBooks(author.books)),
})
);
});
return data;
}

4. Наконец, массив books — это массив объектов. Каждый объект содержит 2 свойства: название и цена. свойство name содержит строковые данные, а свойство price содержит числовые данные. Точно так же bookListFormArray будет содержать 2 элемента управления FormControl: bookName и bookPrice.

bookListFormArray заполняется с помощью loadBooks().

loadBooks(bookList) {
let data: any = [];
bookList.forEach((book: any) => {
data.push(
new FormGroup({
bookName: new FormControl(‘’),
bookPrice: new FormControl(book.price),
})
);
});
return data;
}

На этом структурирование формы из JSON завершено. Давайте проверим оставшиеся 2 пункта, которые мы делаем в ngOnInit().

this.rowData = books.books;
this.columnDefs = [{
headerName: ‘Book Type’,
field: ‘type’,
},
{
headerName: ‘Authors’,
cellRendererFramework: ReusableGridComponent,
cellRendererParams: {
ngTemplate: this.authorList,
},
},
{
headerName: ‘Books’,
cellRendererFramework: ReusableGridComponent,
cellRendererParams: {
ngTemplate: this.authorList,
},
},
];

rowData содержит данные JSON для отображения в таблице Ag-Grid, а columnDefs содержит определения для 3 столбцов в таблице.

Обратите внимание на использование ReusableGridComponent для отображения списка переключателей в столбце "Авторы и книги". Этот компонент очень полезен для передачи собственного ‹ng-template› в таблицу. Вскоре мы увидим, как FormArray, FormGroup и FormControls будут использоваться в ‹ng-template›.

Шаблон компонента ReusableGridComponent:

<ng-container
[ngTemplateOutlet]=”template”
[ngTemplateOutletContext]=”context”
></ng-container>

Я бы посоветовал проверить приведенную ниже историю для получения более подробной информации о том, как работает этот компонент.



Наконец, давайте перейдем к шаблону AppComponent.

Опять же, на это может быть довольно страшно смотреть, но на самом деле это не так. Этот шаблон состоит всего из 2 частей:

  1. Сельскохозяйственный стол
<ag-grid-angular
[columnDefs]=”columnDefs”
[defaultColDef]=”defaultColDef”
class=”ag-theme-alpine”
[rowData]=”rowData”
(gridReady)=”onGridReady($event)”
(firstDataRendered)=”dataRendered($event)”
style=”width:100vh;height:100vw”>
</ag-grid-angular>

2. ‹ng-template› со ссылкой authorList, чтобы отобразить список авторов с переключателем в столбце Авторы, а также список книг, написанных автором, вместе с их ценами. в столбце Книги. Мы используем один шаблон для обеих колонок.

Всякий раз, когда мы нажимаем переключатель, соответствующий автору, выполняется toggleRadio(). Статус переключателя выбран/не выбран управляется свойством isSelected в JSON. Таким образом, когда переключатель выбран, мы устанавливаем для свойства isSelected, соответствующего переключателю, значение true, а когда он не выбран, мы устанавливаем для свойства значение false.

toggleRadio(bookTypeIndex, authorIndex) {
this.allBooksFormGroup.get(‘allBooks’).controls.forEach((control, controlIndex) => {
if (controlIndex === bookTypeIndex) {
control.get(‘authorsList’).controls.forEach((authControl,
authControlIndex) => {
if (authControlIndex === authorIndex) {
authControl.get(‘isSelected’).patchValue(true);
} else {
authControl.get(‘isSelected’).patchValue(false);
}
});
}
});
}

Чтобы обеспечить отображение только книг выбранного автора, мы использовали в шаблоне описанный ниже метод canShow().

Мы сравнили список книг выбранного автора со списком книг других авторов, чтобы отобразить правильный список книг.

canShow(bookTypeIndex, bookDetail) {
let canShow = false;
let selectedAuthor: any = {};
let allBookDetails = this.allBooksFormGroup.get(‘allBooks’).controls;
allBookDetails.forEach((formGroup, formGroupIndex) => {
if (formGroupIndex === bookTypeIndex) {
selectedAuthor = formGroup.get(‘authorsList’).value.find((item) => item.isSelected);
}
});
if (selectedAuthor) {
canShow =
Array.isArray(selectedAuthor.bookList) && Array.isArray(bookDetail.value) &&
selectedAuthor.bookList.length === bookDetail.value.length &&
selectedAuthor.bookList.every((val, index) => val === bookDetail.value[index]);
}
return canShow;
}

Вы можете проверить весь код, работающий по ссылке ниже.



Прежде чем закрыть историю, если вы предпочитаете раскрывающийся список, а не переключатель в столбце Авторы , вы можете проверить реализацию по ссылке StackBlitz ниже. Концепция та же, что и в приведенном выше примере, но с небольшими изменениями в шаблоне.



Больше контента на plainenglish.io. Подпишитесь на нашубесплатную еженедельную рассылку новостей здесь.