Ag-Grid предоставляет функции для добавления флажков и раскрывающихся списков, но пока я работал над добавлением элементов формы в таблицу, в некоторых сценариях это не давало мне необходимой гибкости.
Поэтому я переключился на FormArrays, которые я всегда использую в любой обычной «таблице» или таблице начальной загрузки.
Я использую очень простой пример отображения списка авторов и книг, написанных этими авторами, в таблице Ag-Grid.
Ниже приведены данные, которые мы собираемся использовать. Это массив объектов, экспортированных из books.ts.
Каждый объект описывает тип книги, нескольких авторов, написавших книги в этом жанре, написанные ими книги и цену каждой книги.
Наши цели будут следующими:
- Заполните приведенные выше данные в таблице 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, посмотрите на скриншот ниже.
- allBooksFormGroupсодержит allBooksFormArray. Это соответствует массиву books, который содержит 2 объекта. Точно так же FormArray содержит 2 FormGroups, соответствующие двум объектам.
- Каждый объект в массиве 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 частей:
- Сельскохозяйственный стол
<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. Подпишитесь на нашубесплатную еженедельную рассылку новостей здесь.