Представляємо бібліотеку right-angled, конструктор гридов для angular2



Сьогодні хочемо розповісти про те, як ми вирішили віддати борг open source спільноти і створили бібліотеку right-angled. Тільки вчора ми перевели її в статус beta і вирішили поділитися цією чудовою новиною з Хабрасообществом c самим першим.

Що робить right-angled
В першу чергу, дана бібліотека призначена для побудови гридов (aka списків, aka таблиць) у додатках на angular 2.

По-друге, це дуже просунута модель selection. Працює не обов'язково в зв'язці з гридами. Це просто selection. Чого завгодно.

Ще однією (поки не до кінця сформованій) ідеєю є декларативна настройка властивостей компонентів для:

  • зберегти
  • відновлення
  • скидання в значення за замовчуванням
  • відправки в параметри запиту на сервер
без написання коду вручну.

Безкоштовно?
Так, right-angled поширюється за ліцензією MIT. Вихідний код бібліотеки доступний на github.

Також ми розмістили на github-pages демо-додаток, детально описує можливості бібліотеки з живими демо і прикладами коду. Якщо вам раптом захочеться подивитися на исходники демо-додатки, вони тут.

Навіщо ми зробили ще одну бібліотеку гридов"?
Коли ми вибирали для роботи наявні бібліотеки гридов під angular 2, то прийшли до висновку, що вони занадто важкі і складні. Наприклад, шаблон найпростішого гріду з типовою бібліотекою гридов для angular 2 виглядає приблизно так:

<grid-component [dataSource]="data">
<grid-column-component fieldName="Id" title="Id">
</grid-column-component>
<grid-column-component fieldName="Name" title="Name">
</grid-column-component>
<grid-column-component field="Price" title="Price" width="230">
</grid-column-component>
<grid-column-component field="IsDiscounted" title="Is Discounted" width="120">
<row-template let-dataItem>
<input type="checkbox" [checked]="dataItem.IsDiscounted" />
</row-template>
</grid-column-component>
</grid-component>

В даному шаблоні занадто мало HTML і занадто багато «бібліотеки гридов». Багато компонентів, багато налаштувань, занадто багато того, що доведеться запам'ятати.

Ця складність здалася нам зайвої при сучасному підході до розробки. І ми вирішили спробувати зробити щось легковажне і приємне.

Також, наслідком першого недоліку є другою – верстка, яку генерують подібні компоненти.

Грід – це досить складний контрол. І HTML, що генерується такими компонентами, не завжди виглядає добре будучи вбудованим в кінцеве додаток. Не кажучи вже про те, що цей HTML може бути просто відверто поганим.

Зворотного крайністю є універсальна розмітка, яка враховує всі можливі варіанти, але така розмітка не завжди отрісовиваємих швидко і завжди важко стилізується. Можна витратити багато годин на стилізацію, а грід все одно буде виглядати в вашому дизайні як «не рідна».

Проста стилізація, до речі, є одним з найбільш важливих моментів, оскільки «клоновані» сайти в стилі bootstrap замовників вже давно не влаштовують. І кожен новий проект – це нерідко і новий, унікальний дизайн.

Осмисливши все вище сказане, ми вирішили створити свою бібліотеку, і закласти в неї наступні принципи:

1. Мінімум компонентів

Бібліотека повинна містити мінімум компонентів і вбудовуватися в верстку кінцевого програми, а не генерувати свою. Те ж саме стосується стилів — right-angled не містить будь-яких css і зовнішній вигляд вашого додатки залишається цілком за вами.

Нижче наведено приклад шаблону найпростішого списку. Як ви можете помітити, це звичайна верстка з використанням bootstrap (його використання зовсім не обов'язково, він узятий просто для прикладу) і зовсім небагато кастомних директив.

<table class="table table-striped" [rtList]="getData" #list="rtList">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Price in USD</th>
<th>Is Discounted</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of list.items">
<td>{{item.Id}}</td>
<td>{{item.Name}}</td>
<td>{{item.Price}}</td>
<td><input type="checkbox" [checked]="item.IsDiscounted" /></td>
</tr>
</tbody>
</table>

Такий шаблон виглядає досить простим, оскільки ми не стали додавати в нашу бібліотеку такі поняття як «рядок», «стовпчик», «шаблон перегляду», «шаблон редагування» та інші, такі звичні для бібліотек гридов. Подібні абстракції (а разом з ними і компоненти) часто додаються до бібліотеки гридов. Але, на наш погляд, вони є надмірними і вносять непотрібну складність.

2. Проста функціональність

Щоб «мінімум компонентів» не перетворився в «мінімум функціоналу», ми укомплектували бібліотеку набором функціональних сервісів. На них спираються компоненти самої бібліотеки і їх же користувач може впровадити у свої компоненти за допомогою Dependency Injection, щоб реалізувати потрібну поведінку самостійно.

Якщо ж робити окремі компоненти ліниво, то доступ до цих сервісів можна отримати прямо в шаблоні, звертаючись до директив-хостам. Всього таких директив чотири — rtList з функціоналом списків, rtSelectionArea з функціоналом роботи з selection і компоненти rt-buffered-pager rt-pager-pager для роботи з paging.

Наприклад, замість готового pager-а з купою опцій, ми обійшлися примітивними компонентами-обгортками і парою допоміжних директив. І склали детальний приклад, допомагає користувачеві бібліотеки реалізувати власний повнофункціональний pager.

Нижче ви можете побачити код шаблону списку із фінального прикладу quick tour нашої програми. Додано:

  • selection
  • сортування
  • фільтри
  • кнопки для завантаження даних/скасування запиту/скидання параметрів
  • згаданий вище вище paging
  • серіалізація стану списку query string
В даному шаблоні ми як раз звертаємося до сервісів описаним вище «ледачим» способом — безпосередньо в шаблоні.

Шаблон вийшов пухкий, але адже і функціоналу додано чимало. І це по колишньому досить-таки чистий, стилизуемый HTML, який до того ж дуже легко розбити на компактні і переиспользуемые компоненти (демо-додатку цього не зроблено для простоти сприйняття прикладу).

<form>
<div class="row">
<div class="col-md-4 col-sm-6">
<div class="form-group">
<label>Airport name</label>
<input type="text" class="form-control" [(ngModel)]="airportName" name="airportName" />
</div>
</div>
<div class="col-md-4 col-sm-6">
<div class="form-group">
<label>Country</label>
<input type="text" class="form-control" [(ngModel)]="countryName" name="countryName" />
</div>
</div>
<div class="col-md-4 col-sm-6">
<div class="form-group">
<input (click)="list.loadData()" [disabled]="list.busy" type="submit" class="btn btn-load" title="Load data" />
<input (click)="list.cancelRequests()" [disabled]="list.ready" type="button" class="btn btn-cancel" title="Cancel loading"
/>
<button (click)="list.resetSettings()" [disabled]="list.busy" type="button" class="btn btn-reset" title="Reset settings"></button>
</div>
</div>
</div>
</form>
<div class="table-responsive">
<table class="table table-striped" [rtList]="getAirports" #list="rtList" [loadOnInit]="false" rtDemoSerializeToQueryString
(onListInit)="onListInit($event)">
<thead>
<tr>
<th><span rtSort="iataCode">IATA</span></th>
<th><span rtSort="name">Airport name</span></th>
<th><span rtSort="countryName">Country</span></th>
</tr>
</thead>
<tbody rtSelectionArea>
<tr *ngFor="let airport of list.items" [class.selected]="rts.selected" [rtSelectable]="airport" #rts="rtSelectable">
<td>{{airport.iataCode}}</td>
<td>{{airport.name}}</td>
<td>{{airport.countryName}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">
<rt-demo-paged-footer>
</rt-demo-paged-footer>
</td>
</tr>
</tfoot>
</table>
</div>

Напевно не все в цьому шаблоні виглядає зрозумілим. Але, щоб зберегти статтю компактною, ми не стали копіювати сюди опис функціоналу з демо-програми, тому всі пояснення можна подивитися в ньому.

3. Мінімум залежностей

right-angled не залежить від таких бібліотек, як bootstrap, jquery, jquery UI і т. п. Дані бібліотеки, безумовно, гарні і корисні, але рішення про їх використання краще приймати кінцевому користувачу бібліотеки. А при реалізації гридов без них цілком можна обійтися.

Єдиною залежністю, крім angular, є написана нами ж бібліотека e2e4, яка постачає абстрактні від конкретних presentation фреймворків сервісу для реалізації всього функціоналу.

e2e4, в свою чергу, взагалі не має залежностей. Але, якщо ви працюєте в браузері, не підтримує es6, то вам знадобиться який-небудь es6 полифил. Наприклад, es6 shim або core js. Втім, shim і так потрібен для роботи angular.

Подальший план
Тільки вчора ми бібліотеку перевели в статус бети, тому роботи ще дуже багато. Найближчі плани такі:

  1. Стабілізувати бібліотеку і вивести її в реліз.
  2. Перевести демо-додаток на англійську мову і скласти повноцінну документацію з подальшим виведенням бібліотеки у світове співтовариство.
  3. Доопрацювати демо-додаток, витягнувши назовні всі можливості нашої бібліотеки, оскільки пара фіч поки ще захована.
Ще ми хочемо звернутися до спільноти з проханням
Якщо ви помітили помилку чи вам щось здалося незрозумілим, будь ласка, напишіть нам про це. Особливо це стосується демо-додатки. Ми чудово розуміємо, що написати хорошу, виразну документацію, це справжня майстерність, яким ми поки не володіємо досконало.

Крім створення issue на github, ви можете зв'язатися з автором статті і головним розробником бібліотеки тут, на Хабре. Також ви можете підписатися в twitter аккаунт right-angled, в якому ми будемо публікувати новини про нашу бібліотеку.

На цьому прощаємося. Спасибі за увагу :)
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.