ag-Grid - это корпоративная сетка данных, которая работает с Angular 2. Поскольку ag-Grid работает со многими фреймворками, внутренняя часть сетки должна позволять рендеринг Angular 2 внутри сетки, несмотря на то, что ag-Grid не написан на самом Angular. Это было сделано с использованием динамических компонентов Angular 2, и нам удалось это сделать, по-прежнему поддерживая AOT. В этом блоге подробно рассказывается о том, что мы узнали в процессе.

Установка

Чтобы объяснить, мы представляем простой пример приложения, которое изолирует то, что мы пытаемся сделать. В нашем примере ниже мы собираемся разработать два основных модуля - один будет библиотекой (в нашем случае это была ag-Grid), которая будет отображать массив динамически создаваемых компонентов (аналогично тому, как ag-Grid отображает компоненты Angular внутри сетки. ячейки), а другой будет нашим фактическим приложением.

Конечный результат будет выглядеть так:

Вы можете найти весь код этого примера на GitHub, а живой пример - на GitHub.io.

Еще одно замечание - когда мы возвращаемся к «пользователю» ниже, мы имеем в виду пользователя (или клиента) библиотеки, которую мы пишем.

Библиотека

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

Как видите, это довольно простой компонент - все, что он делает, это отображает текущий cellComponentTypes. Это компоненты, предоставляемые пользователем, и они могут быть любым компонентом Angular 2.

Интересная часть библиотеки находится в Cell компоненте:

Вы заметите, что у нас здесь нет шаблона - это сделано намеренно, поскольку Cell не имеет собственного содержания - все, что он делает, - это обслуживает компонент, предоставленный пользователем. Важной частью этого Компонента являются эти две строки:

let compFactory = this.cfr.resolveComponentFactory(this.componentType);

Эта строка просит ComponentFactoryResolver найти ComponentFactory для предоставленного Компонента. Мы будем использовать эту фабрику для создания фактического компонента:

this.viewContainerRef.createComponent(compFactory);

И это все, что нужно сделать со стороны компонента библиотеки - мы находим фабрику для компонента, а затем создаем новый экземпляр компонента. Легкий!

Чтобы это сработало, нам нужно указать компилятору AOT Angular создать фабрики для компонентов, предоставленных пользователем, иначе ComponentFactoryResolver их не найдет. Мы можем использовать для этого NgModule.entryComponents - это гарантирует, что компилятор AOT создаст необходимые фабрики, но для вас есть более простой способ, особенно с точки зрения пользователей:

Используя здесь ANALYZE_FOR_ENTRY_COMPONENTS, мы можем динамически добавлять несколько компонентов в запись NgModule.entryComponents удобным для пользователя способом.

Приложение

Что касается приложения, первое, что нам нужно сделать, это создать компоненты, которые мы хотим использовать в библиотеке - это может быть любой допустимый компонент Angular 2. В нашем случае у нас есть три похожих Компонента:

@Component({
    selector: 'dynamic-component',
    template: '<div class="img-rounded" style="background-color: lightskyblue;margin: 5px"> Blue Dynamic Component! </div>',
})
export class BlueDynamicComponent {
}

Все эти компоненты отображают небольшой стилизованный текст.

Чтобы зарегистрировать их как в нашем приложении, так и в библиотеке, нам нужно переключиться на модуль приложения:

Мы объявляем наши Компоненты обычным способом, но нам дополнительно необходимо зарегистрировать их в Библиотеке (помните, что это та часть, где они будут добавлены в запись библиотеки NgModule.entryComponent). Мы делаем это в этой части модуля:

GridModule.withComponents([
    BlueDynamicComponent,
    GreenDynamicComponent,
    RedDynamicComponent
])

Наконец, мы можем взглянуть на основной компонент приложения:

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

<button 
  type="button" 
  class="btn btn-primary"  (click)="grid.addDynamicCellComponent(selectedComponentType)"
>
Add Dynamic Grid component
</button>

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

<grid-component #grid></grid-component>

И эта строка - наш библиотечный компонент.

Вот и все - легко писать и использовать (как с точки зрения приложения, так и с точки зрения библиотеки), а также удобство использования AOT (и JIT!).

Преимущества использования AOT

Скорость и размер результирующего приложения при использовании AOT могут быть значительными. В нашем проекте ag-grid-angular-example мы оценили размер получившегося приложения с 3,9 МБ до 2,4 МБ - сокращение чуть менее чем на 40%, без оптимизации по размеру и особо агрессивных действий с накоплением.

С точки зрения скорости время загрузки при использовании AOT значительно больше при запуске - это имеет смысл, учитывая, что Angular не нужно заново компилировать весь код. Взгляните на проект примеров и попробуйте сами версии JIT и AOT!

Если вы решите объединить компоненты Angular 2 с ag-Grid, вы сможете сделать гораздо больше - мощную функциональность, быструю сетку и простую настройку. Чего же ты ждешь?!

Узнайте больше о AG Grid - благодаря поддержке нескольких фреймворков: Angular, Vue, React вы можете выбрать лучшую платформу для своих нужд, и AG Grid будет работать.