Поработав с Angular Material 2, в какой то момент пришел к выводу, что продукт сыроват для полета фантазии и некоторые вещи (badge, vertical tabs, data-grid) либо реализованы с минимальным функционалом, либо In progress, planned.
Вечером, придя домой, начал искать что нибудь, что мог бы предложить тимлиду как альтернативу для следующего проекта. Тут то я и заметил, что angular.io разжился табом Resources. Это было пару месяцев назад.
Там среди прочих довольно таки полезных вещей, команда разработчиков Angular, добавила продукт от не менее известной компании, чьи разработки я уважаю и с щенячьим восторгом всегда рад лишний раз поковырять — VmWare. Ребята сделали весьма и весьма достойный продукт — Clarity.
Решил для себя, написать статью на тему Clarity, но просто писать обзор — не хотелось, решил сделать что то вроде starter-kit на случай если кому то понадобится быстро сделать админку. Также, будет активно использоваться Highcharts, Angular Flex-layout и i18n библиотека ngx-translate
Для нетерпеливых: github, demo
Говнокода много, и если встретится подобное, просьба понять, простить и написать комментарий, буду премного благодарен :)
Не буду углубляться в процесс установки Node.js, angular-cli и положу под спойлер инструкцию, на случай если кто-то только начал знакомство с Angular.
Выполняем команду для установки angular-cli:
npm install -g @angular/cli
после чего генерируем наш проект:
ng new ngClarity
Итак, у нас уже есть Hello World, далее необходимо подготовить среду, установить пакеты и сконфигурировать наш angular:
Установка
Ставим пакет иконок:
npm install clarity-icons --save
Пакет с полифиллами:
npm install @webcomponents/custom-elements@1.0.0 --save
Добавляем все установленное в конфиг файл .angular-cli.json
"styles": [
"styles.css",
"../node_modules/clarity-icons/clarity-icons.min.css"
],
"scripts": [
"../node_modules/@webcomponents/custom-elements/custom-elements.min.js",
"../node_modules/clarity-icons/clarity-icons.min.js"
],
Дополняем наш Angular модулем clarity-ui:
npm install clarity-ui --save
Лезем обратно в в конфиг файл .angular-cli.json и дописываем путь к стилям clarity-ui:
"styles": [
"styles.css",
"../node_modules/clarity-icons/clarity-icons.min.css",
"../node_modules/clarity-ui/clarity-ui.min.css"
],
Ставим пакет clarity-angular:
npm install clarity-angular --save
Добавляем импорт в наш app.module.ts:
import { ClarityModule } from "clarity-angular";
И объявляем в imports:
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
ClarityModule
],
providers: [],
bootstrap: [AppComponent]
})
Для тех кто привык обращаться только к официальной документации, есть ссылка.
i18n
Далее, думаю стоит описать установку и настройку модуля i18n(используется библиотека ngx-translate), тут ничего необычного, но все же уделим внимание, возможно кому то понадобится:
Ставим либу:
npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save
идем в наш app.module.ts и дополняем его импортами:
import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
имплементация http фактории, которая будет подгружать наши translations файлы:
export function HttpLoaderFactory(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
создаем два файла, en.json и ru.json в директории /assets/i18n/
и ставим точку в этом деле, добавляя модуль в imports нашего @NgModule:
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
В итоге, мы имеем начальную конфигурацию ngx-translate, и теперь можем объявить в app.component.ts наш TranslationService, который будет подгружать json файлы из директории /assets/i18n
import {Component, OnInit} from '@angular/core';
import {TranslateService} from "@ngx-translate/core";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
constructor(public translate: TranslateService){}
ngOnInit(){
this.translate.addLangs(["en", "ru"]);
this.translate.setDefaultLang('en');
let browserLang = this.translate.getBrowserLang();
if (browserLang.match( /en|ru/ )) {
this.translate.use( browserLang );
} else {
this.translate.use( 'en' );
}
}
}
Роутинг
Cоздаем роутинг сервис для нашего проекта. В директории /app создаем файл routing.module.ts и конфигурируем наш AppRoutingModule:
import {NgModule}from '@angular/core';
import {Routes, RouterModule}from '@angular/router';
const appRoutes: Routes = [
{
path: '',
redirectTo: '/',
pathMatch: 'full',
}
];
@NgModule({
imports: [
RouterModule.forRoot(
appRoutes
)
],
exports: [
RouterModule
]
})
export class AppRoutingModule {}
для инициализации, в app.module.ts, добавляем импорт AppRoutingModule в наш @NgModule.
Компоненты
Создаем три пустых пока что компонента: DashboardComponent, SettingsComponent и PageNotFoundComponent. Внутри app создаем директорию pages, и из под нее запускаем:
ng generate component dashboard
ng generate component settings
ng generate component pageNotFound
наш angular/cli создаст три директории с указанными именами, создаст внутри директорий все необходимое для компонента и обновит app.module.
Иногда angular/cli может неправильно резолвить пути до файлов, и в случае возникновения ошибок, нужно перепроверить импорты и пути к файлам в app.module.
Далее, заходим в наш routing.module.ts и редактируем роуты для новоиспеченных компонентов:
const appRoutes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
},
{
path: 'settings',
component: SettingsComponent,
},
{
path: '',
redirectTo: 'dashboard',
pathMatch: 'full'
},
{
path: '**',
component: PageNotFoundComponent
}
];
Cтроим каркас нашего приложения. Заходим в app.component.html и начинаем:
<clr-main-container>
<clr-header class="header-3">
<div class="branding">
<a href="..." class="nav-link">
<span class="title">ngClarity</span>
</a>
</div>
<div class="header-actions">
<clr-dropdown>
<button class="nav-icon" clrDropdownTrigger>
<clr-icon shape="world"></clr-icon>
<clr-icon shape="caret down"></clr-icon>
</button>
<clr-dropdown-menu *clrIfOpen clrPosition="bottom-right">
<a *ngFor="let lang of translate.getLangs()" (click)="translate.use(lang)" clrDropdownItem>{{lang}}</a>
</clr-dropdown-menu>
</clr-dropdown>
<clr-dropdown>
<button class="nav-icon" clrDropdownTrigger>
<clr-icon shape="user"></clr-icon>
<clr-icon shape="caret down"></clr-icon>
</button>
<clr-dropdown-menu *clrIfOpen clrPosition="bottom-right">
<a href="..." clrDropdownItem>{{ 'profile' | translate }}</a>
<a href="..." clrDropdownItem>{{ 'logout' | translate }}</a>
</clr-dropdown-menu>
</clr-dropdown>
</div>
</clr-header>
<div class="alert alert-app-level"></div>
<div class="content-container">
<div class="content-area">
<router-outlet></router-outlet>
</div>
<clr-vertical-nav [clrVerticalNavCollapsible]="true" [clr-nav-level]="1">
<a clrVerticalNavLink routerLink="/dashboard" routerLinkActive="active" class="nav-link">
<clr-icon clrVerticalNavIcon shape="dashboard"></clr-icon>{{ 'dashboard' | translate }}
</a>
<a clrVerticalNavLink routerLink="/settings" routerLinkActive="active" class="nav-link">
<clr-icon clrVerticalNavIcon shape="cog"></clr-icon>{{ 'settings' | translate }}
</a>
</clr-vertical-nav>
</div>
</clr-main-container>
Останавливаться на каждом из директив не будем, для этого есть хорошо написанная документация. Каркас более менее готов, далее можно будет уже работать с компонентами.
Highcharts
Устанавливаем труд товарища cebor, который создал ангуляровскую директиву для Highcharts: angular-highcharts
npm install --save angular-highcharts highcharts
Далее, идем в наш app.module добавляем импорт и объявляем наш модуль, добавив его в imports:
import { ChartModule } from 'angular-highcharts';
@NgModule({
imports: [
ChartModule
]
})
Flex-Layout
Теперь возьмемся за flex-layout:
npm install @angular/flex-layout --save
и по традиции, в app.module.ts
import { FlexLayoutModule } from '@angular/flex-layout';
@NgModule({
imports: [
FlexLayoutModule
]
})
Теперь, идем в наш dashboard.component.ts объявляем импорты:
import * as Highcharts from 'highcharts';
import * as HichartsExporting from 'highcharts/modules/exporting';
import * as Hicharts3d from 'highcharts/highcharts-3d.js';
HichartsExporting(Highcharts);//объявляем модуль exporting
Hicharts3d(Highcharts);//объявляем модуль 3d
В dashboard.component.html рисуем наши блоки, где разместим графики:
<div style="padding: 1em;" fxLayout="row" fxLayout.xs="column" fxLayout.sm="column" fxLayoutWrap fxLayoutGap="1rem" fxLayoutAlign="center">
<div class="card" fxLayout="column" fxLayout.xs="column" fxFlex="49" fxLayout.sm="column" style="padding: 5px;">
<div class="card-block" id="chart1"></div>
</div>
<div class="card" fxLayout="column" fxLayout.xs="column" fxFlex="49" fxLayout.sm="column" style="padding: 5px;">
<div class="card-block" id="chart2"></div>
</div>
</div>
и код самого компонента, в dashboard.component.ts:
import { Component, OnInit } from '@angular/core';
import * as Highcharts from 'highcharts';
import * as HichartsExporting from 'highcharts/modules/exporting';
import * as Hicharts3d from 'highcharts/highcharts-3d.js';
HichartsExporting(Highcharts);
Hicharts3d(Highcharts);
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
constructor() { }
ngOnInit() {
Highcharts.chart('chart1', {
chart: {
type: 'column'
},
title: {
text: 'Schedules work progress'
},
credits: {
enabled: false
},
xAxis: {
categories: ['line 1', 'line 2', 'line 3', 'line 4'],
labels: {
skew3d: true,
style: {
fontSize: '16px'
}
}
},
yAxis: {
allowDecimals: false,
min: 0,
title: {
text: 'Total count',
skew3d: true
}
},
tooltip: {
headerFormat: '<b>{point.key}</b><br>',
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.percentage:.0f}%)<br/>'
},
plotOptions: {
column: {
stacking: 'normal',
depth: 40,
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white'
}
}
},
series: [
{name: 'Left', data: [10, 58, 23, 8]},
{name: 'Done', data: [27, 98, 44, 65]},
{name: 'Alert', data: [8, 4, 65, 78]}
]
});
Highcharts.chart('chart2', {
chart: {
type: 'pie',
options3d: {
enabled: true,
alpha: 45,
beta: 0
}
},
title: {
text: 'Browser market shares at a specific website, 2014'
},
credits: {
enabled: false
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
depth: 35,
dataLabels: {
enabled: true,
format: '{point.name}'
}
}
},
series: [{
type: 'pie',
name: 'Browser share',
data: [
['Firefox', 45.0],
['IE', 26.8],
{
name: 'Chrome',
y: 12.8,
sliced: true,
selected: true
},
['Safari', 8.5],
['Opera', 6.2],
['Others', 0.7]
]
}]
});
}
}
Сейчас уже можно будет увидеть, что в итоге получилось: demo
На этом, первая часть завершается. Вторая часть статьи будет более детально разбирать компоненты Clarity и реализовывать их в проекте, исходники которого здесь: github
Автор: Adilet Abdi