Top
In theme we are using Abstract Elements for calling small widgets. so It will easy to use and user freindlly from developer perspective.
<button type="button" class="btn btn-primary">Primary Button</button>
<button type="button" class="btn btn-secondary">Secondary Button</button>
<button type="button" class="btn btn-success">Success Button</button>
<button type="button" class="btn btn-info">Info Button</button>
<button type="button" class="btn btn-warning">Warning Button</button>
<button type="button" class="btn btn-danger">Danger Button</button>
<button type="button" class="btn btn-light">Light Button</button>
To use another types button you have to link the related css file according to types of buttons in a head tag
<button type="button" class="btn btn-secondary">Secondary Button</button>
<button type="button" class="btn btn-success">Success Button</button>
<button type="button" class="btn btn-info">Info Button</button>
<button type="button" class="btn btn-warning">Warning Button</button>
<button type="button" class="btn btn-danger">Danger Button</button>
<button type="button" class="btn btn-light">Light Button</button>
<span class="badge badge-secondary">Secondary</span>
<span class="badge badge-success">Success</span>
<span class="badge badge-info">Info</span>
<span class="badge badge-warning text-dark">Warning</span>
<span class="badge badge-danger">Danger</span>
<span class="badge badge-light text-dark">Light</span>
<span class="badge badge-dark tag-pills-sm-mb">Dark</span>
<div class="alert alert-secondary" role="alert">This is a light alert—check it out!</div>
<div class="alert alert-success" role="alert">This is a success alert—check it out!</div>
<div class="alert alert-info" role="alert">This is a danger alert—check it out!</div>
<div class="alert alert-warning" role="alert">This is a secondary alert—check it out!</div>
<div class="alert alert-danger" role="alert">This is a warning alert—check it out!</div>
<div class="alert alert-light" role="alert">This is a dark alert—check it out!</div>
<div class="alert alert-dark" role="alert">This is a dark alert—check it out!</div>
<button type="button" class="btn btn-primary example-popover mr-1" data-bs-toggle="popover" title="Popover title" data-bs-content="And here's some amazing content. It's very engaging. Right?">Click to toggle popover</button>
<a tabindex="0" class="example-popover btn btn-secondary" role="button" data-bs-toggle="popover" data-bs-trigger="focus" title="Popover title" data-bs-content="And here's some amazing content. It's very engaging. Right?">Dismissible popover</a>
<button type="button" data-bs-trigger="hover" class="example-popover btn btn-success" data-container="body" data-bs-toggle="popover" data-bs-placement="bottom" title="Popover title" data-offset="-20px -20px" data-bs-content="Vivamus sagittis lacus vel augue laoreet rutrum faucibus." >On Hover Tooltip</button>
<!--popover js-->
<script src="../assets/js/popover-custom.js"></script>
// tooltip.html //
<button class="example-popover btn btn-primary" type="button" data-bs-placement="top" title="Popover title" ngbTooltip="Basic Tooltip">Hover Me</button>
// tooltip.html //
import { Component } from '@angular/core';
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-tooltip',
standalone: true,
imports:[NgbTooltipModule],
templateUrl: './tooltip.html',
styleUrls: ['./tooltip.scss']
})
export class Tooltip {
}
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum
Lorem Ipsum is simply dummy text of the printing and typesetting Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum
<div class="card-body">
<ngbNav #nav="ngbNav" [activeId]="1" class="nav nav-tabs">
<li class="nav-item" [ngbNavItem]="1">
<a class="nav-link active" ngbNavLink</a>
<ng-template ngbNavContent>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has
been
the industry's standard dummy text ever since the 1500s, when an unknown printer took a
galley
of type and scrambled it to make a type specimen book. It has survived not only five
centuries,
but also the leap into electronic typesetting, remaining essentially unchanged. It was
popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum
passages,
and more recently with desktop publishing software like Aldus PageMaker including versions
of
Lorem Ipsum</p>
</ng-template>
</li>
<li ngbDropdown class="nav-item dropdown">
<a class="nav-link dropdown-toggle bg-transparent border-none" (click)="isShow = !isShow" ngbDropdownToggle>Dropdown</a>
<div class="dropdown-menu" ngbDropdownMenu [ngClass]="isShow ? 'd-block':'d-none'">
<button class="dropdown-item" ngbDropdownItem>Action</button>
<button class="dropdown-item" ngbDropdownItem>Another action</button>
<button class="dropdown-item" ngbDropdownItem>Something else here</button>
<div class="dropdown-divider"></div>
<button class="dropdown-item" ngbDropdownItem>Separated link</button>
</li>
<li class="nav-item" [ngbNavItem]="2">
<a class="nav-link" ngbNavLink>Profile</a>
<ng-template ngbNavContent>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has
been
the industry's standard dummy text ever since the 1500s, when an unknown printer took a
galley
of type and scrambled it to make a type specimen book. It has survived not only five
centuries,
but also the leap into electronic typesetting, remaining essentially unchanged. It was
popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum
passages,
and more recently with desktop publishing software like Aldus PageMaker including versions
of
Lorem Ipsum
</p>
</ng-template>
</li>
<li class="nav-item" [ngbNavItem]="3">
<a class="nav-link" ngbNavLink>Contact</a>
<ng-template ngbNavContent>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has
been
the industry's standard dummy text ever since the 1500s, when an unknown printer took a
galley
of type and scrambled it to make a type specimen book. It has survived not only five
centuries,
but also the leap into electronic typesetting, remaining essentially unchanged. It was
popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum
passages,
and more recently with desktop publishing software like Aldus PageMaker including versions
of
Lorem Ipsum
</p>
</ng-template>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div [ngbNavOutlet]="nav" class="mt-4">
</div>
</div>
<ng-container ngbAccordion [closeOthers]="true">
<div class="card" ngbAccordionItem *ngFor="let item of basicAccordion" [collapsed]="item.panel !== 'First'">
<div class="card-header" id="headingOne" ngbAccordionHeader>
<h5 class="mb-0">
<button class="btn btn-link ps-0" ngbAccordionButton>{{item.title}}</button>
</h5>
</div>
<div class="collapse show" ngbAccordionCollapse>
<div class="card-body" ngbAccordionBody>{{item.description}}</div>
</div>
</div>
</ng-container>
import { Component } from '@angular/core';
import * as data from '../../../../shared/data/data/ui-kits/accordion';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';
@Component({
selector: 'app-basic-accordion',
standalone: true,
imports:[NgbAccordionModule],
templateUrl: './basic-accordion.html',
styleUrls: ['./basic-accordion.scss']
})
export class BasicAccordion {
public basicAccordion = data.basicAccordion;
}
export const basicAccordion = [
{
id: "static-1",
panel: "First",
title: "Collapsible Group Item #1",
description:
"Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolfmoon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.",
},
{
id: "static-2",
title: "Collapsible Group Item #2",
panel: "Second",
description:
"Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolfmoon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.",
},
{
id: "static-3",
title: "Collapsible Group Item #3",
panel: "Third",
description:
"Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolfmoon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.",
},
];
Installing and usage
npm i ngx-bar-rating
// rating.html
<bar-rating class="star" [(rate)]="cssRate" [max]="5"></bar-rating>
// rating.ts
import { Component } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
import { FaIconLibrary, FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { faStar as farStar } from '@fortawesome/free-regular-svg-icons';
import { faStar, faStarHalfAlt, faTimesCircle } from '@fortawesome/free-solid-svg-icons';
@Component({
selector: 'app-rating',
standalone: true,
imports:[FontAwesomeModule,BarRatingModule],
templateUrl: './rating.html',
styleUrls: ['./rating.scss']
})
export class Rating {
public cssRate = 2.6;
}
Installing and usage
npm i sweetalert2
// sweet-alert2.html
<button class="btn btn-primary sweet-1" type="button" (click)="basicAlert()">Basic</button>
// sweet-alert2.ts
import { Component } from '@angular/core';
import Swal from 'sweetalert2';
@Component({
selector: 'app-sweet-alert2',
standalone: true,
imports:[],
templateUrl: './sweet-alert2.html',
styleUrls: ['./sweet-alert2.scss']
})
export class SweetAlert2 {
basicAlert() {
Swal.fire('Hello world!')
}
}
Installing and usage
npm i ngx-slider-v2
// range-slider.html //
<ngx-slider [(value)]="default" [options]="options"></ngx-slider>
// range-sliders.ts //
import { Component } from '@angular/core';
import { NgxSliderModule, Options } from '@angular-slider/ngx-slider';
@Component({
selector: 'app-range-slider',
standalone: true,
imports:[NgxSliderModule],
templateUrl: './range-slider.html',
styleUrls: ['./range-slider.scss']
})
export class RangeSlider {
public default: number = 100;
public options: Options = {
floor: 0,
ceil: 200
};
}
Installing and usage
npm i ngx-dropzone
// dropzone.html
<dropzone body [config]="imageConfig" " [message]="text"></dropzone>
// dropzone.ts
import { Component } from '@angular/core';
import { DropzoneConfigInterface, DropzoneModule } from 'ngx-dropzone-wrapper';
@Component({
selector: 'app-dropzone',
standalone: true,
imports: [DropzoneModule],
templateUrl: './dropzone.html',
styleUrls: ['./dropzone.scss']
})
export class Dropzone {
public imageConfig: DropzoneConfigInterface = {
clickable: true,
url: 'https://httpbin.org/post',
addRemoveLinks: true,
uploadMultiple: false,
};
public text = 'Drop files here or click to upload.
(This is just a demo dropzone. Selected files are not actually uploaded.)';
}
Installing and usage
npm i @danielmoncada/angular-datetime-picker
//html //
<input class="form-control datetimepicker-input digits" type="text" [owlDateTimeTrigger]="dt" [owlDateTime]="dt">
<owl-date-time #dt></owl-date-time>
//ts //
import { Component } from '@angular/core';
import { OwlDateTimeModule, OwlNativeDateTimeModule } from '@danielmoncada/angular-datetime-picker';
@Component({
selector: 'app-date-time-picker',
standalone : true,
imports:[OwlDateTimeModule, OwlNativeDateTimeModule],
templateUrl: './date-time-picker.html',
styleUrls: ['./date-time-picker.scss']
})
export class DateTimePicker {
}
Installing and usage
npm i @ng-bootstrap/ng-bootstrap
A typeahead example that gets values from a static <code>string[]</code>
<ul>
<li><code>debounceTime</code> operator</li>
<li>kicks in only if 2+ characters typed</li>
<li>limits to 10 results</li>
</ul>
<label for="typeahead-basic">Search for a state:</label>
<input id="typeahead-basic" type="text" class="form-control" [(ngModel)]="model" [ngbTypeahead]="search" />
<hr />
<pre>Model: {{ model | json }}</pre>
import { CommonModule } from '@angular/common';
import { Component, viewChild } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbTypeahead, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable, OperatorFunction, debounceTime, distinctUntilChanged, map } from 'rxjs';
import { FormattedResults } from './formatted-results/formatted-results';
import { GlobalConfigurationOfTypeaheads } from './global-configuration-of-typeaheads/global-configuration-of-typeaheads';
import { OpenOnFocus } from './open-on-focus/open-on-focus';
import { PreventManualEntry } from './prevent-manual-entry/prevent-manual-entry';
import { SelectOnExact } from './select-on-exact/select-on-exact';
import { TemplateForResult } from './template-for-result/template-for-result';
import { WikipediaSearch } from './wikipedia-search/wikipedia-search';
import * as data from '../../../../shared/data/data/forms/form-widgets';
@Component({
selector: 'app-typeaherd',
imports: [
NgbTypeaheadModule,
FormattedResults,
GlobalConfigurationOfTypeaheads,
OpenOnFocus,
PreventManualEntry,
SelectOnExact,
TemplateForResult,
WikipediaSearch,
CommonModule,
FormsModule,
],
templateUrl: './typeaherd.html',
styleUrls: ['./typeaherd.scss'],
})
export class Typeaherd {
public model: string;
public states = data.states;
readonly instance = viewChild('instance');
search: OperatorFunction = (text$: Observable) =>
text$.pipe(
debounceTime(200),
distinctUntilChanged(),
map(term =>
term.length < 2
? []
: this.states.filter(v => v.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10),
),
);
}
| # | First | Last | Handle |
|---|---|---|---|
| 1 | Mark | Otto | @mdo |
| 2 | Jacob | Thornton | @fat |
| 3 | Larry the Bird | ||
Installing and usage
npm i bootstrap
<table class="table">
<thead>
<tr>
<th scope="col"># </th>
<th scope="col">First </th>
<th scope="col">Last </th>
<th scope="col">Handle </th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1 </th>
<td>Mark </td>
<td>Otto </td>
<td>@mdo </td>
</tr>
<tr>
<th scope="row">2 </th>
<td>Jacob </td>
<td>Thornton </td>
<td>@fat </td>
</tr>
<tr>
<th scope="row">3 </th>
<td colspan="2">Larry the Bird </td>
<td>@twitter </td>
</tr>
</tbody>
</table>
Installing and usage
npm i @ng-bootstrap/ng-bootstrap
// data.ts
import { Country } from './country';
export const tableData: Table[] = [
{
id: 1,
name: 'Tiger Nixon',
position: 'System Architect',
office: 'Edinburgh',
age: '61',
startDate: '2011/04/25',
salary: '$320,800',
},
{
id: 2,
name: 'Garrett Winters',
position: 'Accountant',
office: 'Tokyo',
age: '63',
startDate: '2011/07/25',
salary: '$170,750',
},
{
id: 3,
name: 'Ashton Cox',
position: 'Junior Technical Author',
office: 'San Francisco',
age: '66',
startDate: '2009/01/12',
salary: '$86,000',
},
{
id: 4,
name: 'Cedric Kelly',
position: 'Senior Javascript Developer',
office: 'Edinburgh',
age: '22',
startDate: '2012/03/29',
salary: '$433,060',
},
{
id: 5,
name: 'Airi Satou',
position: 'Accountant',
office: 'Tokyo ',
age: '33',
startDate: '2008/11/28',
salary: '$162,700',
},
{
id: 6,
name: 'Brielle Williamson',
position: 'Integration Specialist',
office: 'New York ',
age: '61',
startDate: '2012/12/02',
salary: '$372,000',
},
{
id: 7,
name: 'Herrod Chandler',
position: 'Sales Assistant',
office: 'San Francisco',
age: '59',
startDate: '2012/08/06',
salary: '$137,500',
},
{
id: 8,
name: 'Rhona Davidson',
position: 'Integration Specialist',
office: 'Tokyo',
age: '55',
startDate: '2010/10/14',
salary: '$327,900',
},
{
id: 9,
name: 'Colleen Hurst',
position: 'Javascript Developer',
office: 'San Francisco',
age: '39',
startDate: '2009/09/15',
salary: '$205,500',
},
{
id: 10,
name: 'Sonya Frost',
position: 'Software Engineer',
office: 'Edinburgh',
age: '23',
startDate: '2008/12/13',
salary: '$103,600',
},
{
id: 11,
name: 'Jena Gaines',
position: 'Office Manager',
office: 'London',
age: '30',
startDate: '2008/12/19',
salary: '$90,560',
},
{
id: 12,
name: 'Quinn Flynn',
position: 'Support Lead',
office: 'Edinburgh',
age: '22',
startDate: '2013/03/03',
salary: '$342,000',
},
{
id: 13,
name: 'Charde Marshall',
position: 'Regional Director',
office: 'San Francisco',
age: '36',
startDate: '2008/10/16',
salary: '$470,600',
},
{
id: 14,
name: 'Donna Snider',
position: 'Customer Support',
office: 'New York',
age: '27',
startDate: '2011/01/25',
salary: '$112,000',
},
];
// service.ts
import { DecimalPipe } from '@angular/common';
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable, Subject, debounceTime, delay, of, switchMap, tap } from 'rxjs';
import { tableData } from '../data/data/tables/datatable';
import { SortColumn, SortDirection } from '../directive/sort-datatable.directive';
import { Table } from '../interface/datatable';
interface SearchResult {
basicTable: Table[];
total: number;
}
interface State {
page: number;
pageSize: number;
searchTerm: string;
sortColumn: SortColumn;
sortDirection: SortDirection;
}
const compare = (v1: string | number, v2: string | number) => v1 < v2 ? -1 : v1 > v2 ? 1 : 0;
function sort(basicTable: Table[], column: SortColumn, direction: string): Table[] {
if (direction === '' || column === '') {
return basicTable;
} else {
return [...basicTable].sort((a: any, b: any) => {
const res = compare(a[column], b[column]);
return direction === 'asc' ? res : -res;
});
}
}
@Injectable({
providedIn: 'root'
})
export class TablesService {
private _loading$ = new BehaviorSubject(true);
private _search$ = new Subject();
private _tables$ = new BehaviorSubject([]);
private _total$ = new BehaviorSubject(0);
private _state: State = {
page: 1,
pageSize: 10,
searchTerm: '',
sortColumn: '',
sortDirection: ''
};
constructor(private pipe: DecimalPipe) {
this._search$
.pipe(
tap(() => this._loading$.next(true)),
debounceTime(200),
switchMap(() => this._search()),
delay(200),
tap(() => this._loading$.next(false))
)
.subscribe(result => {
this._tables$.next(result.basicTable);
this._total$.next(result.total);
});
this._search$.next();
console
}
get basicTable$() { return this._tables$.asObservable(); }
get total$() { return this._total$.asObservable(); }
get loading$() { return this._loading$.asObservable(); }
get page() { return this._state.page; }
get pageSize() { return this._state.pageSize; }
get searchTerm() { return this._state.searchTerm; }
set page(page: number) { this._set({ page }); }
set pageSize(pageSize: number) { this._set({ pageSize }); }
set searchTerm(searchTerm: string) { this._set({ searchTerm }); }
set sortColumn(sortColumn: SortColumn) { this._set({ sortColumn }); }
set sortDirection(sortDirection: SortDirection) { this._set({ sortDirection }); }
private _set(patch: Partial) {
Object.assign(this._state, patch);
this._search$.next();
}
private _search(): Observable {
const { sortColumn, sortDirection, pageSize, page, searchTerm } = this._state;
// 1. sort
let basicTable = sort(tableData, sortColumn, sortDirection);
// 2. filter
const total = basicTable.length;
// 3. paginate
basicTable = basicTable.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
return of({ basicTable, total });
}
}
//interface.ts
export interface Table {
id: number;
name: string;
position: string;
office: string;
startDate: string;
salary: string;
age: string;
}
// table-complete.html
<div class="table-responsive">
<div class="dataTables_wrapper no-footer">
<form>
<div class="mb-3 row justify-content-end">
<span class="col col-form-label text-end" *ngIf="service.loading$ | async">Loading...</span>
<label for="table-complete-search" class="col-xs-3 col-sm-auto col-form-label">Search:</label>
<div class="col-xs-3 col-sm-auto">
<input id="table-complete-search" type="text" class="form-control" name="searchTerm"
[(ngModel)]="service.searchTerm">
</div>
</div>
<table class="display dataTable no-footer">
<thead>
<tr>
<th scope="col" sortable="name" (sort)="onSort($event)">Name</th>
<th scope="col" sortable="position" (sort)="onSort($event)">position</th>
<th scope="col" sortable="office" (sort)="onSort($event)">Office</th>
<th scope="col" sortable="age" (sort)="onSort($event)">Age</th>
<th scope="col" sortable="startDate" (sort)="onSort($event)">Start Date</th>
<th scope="col" sortable="salary" (sort)="onSort($event)">Salary</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of basicTable$ | async">
<td scope="row">
<ngb-highlight [result]="item.name" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="item.position" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="item.office" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="item.age" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="item.startDate" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ngb-highlight [result]="item.salary" [term]="service.searchTerm"></ngb-highlight>
</td>
<td>
<ul class="action">
<li class="edit"> <i class="icon-pencil-alt"></i></li>
<li class="delete" (click)="deleteData(item.id)"><i class="icon-trash"></i></li>
</ul>
</td>
</tr>
</tbody>
</table>
<div class="d-flex justify-content-between mt-3">
<select class="form-select" style="width: auto" name="pageSize" [(ngModel)]="service.pageSize">
<option [ngValue]="10">10 items per page</option>
<option [ngValue]="25">25 items per page</option>
<option [ngValue]="50">50 items per page</option>
<option [ngValue]="100">100 items per page</option>
</select>
<ngb-pagination class="ms-3" [collectionSize]="(total$ | async)!" [(page)]="service.page"
[pageSize]="service.pageSize">
</ngb-pagination>
</div>
</form>
</div>
</div>
// table-complete.ts
import { CommonModule, DecimalPipe } from '@angular/common';
import { Component, inject, viewChildren } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { NgbPaginationModule, NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable } from 'rxjs';
import {
SortDatatableDirective,
SortEvent,
} from '../../../shared/directive/sort-datatable.directive';
import { Table } from '../../../shared/interface/datatable';
import { TablesService } from '../../../shared/services/tables.service';
@Component({
selector: 'app-data-tables',
templateUrl: './data-tables.html',
styleUrls: ['./data-tables.scss'],
providers: [TablesService, DecimalPipe],
imports: [
FormsModule,
SortDatatableDirective,
NgbPaginationModule,
CommonModule,
FormsModule,
NgbTypeaheadModule,
],
})
export class DataTables {
public basicTable$: Observable;
public total$: Observable;
public service = inject(TablesService);
readonly headers = viewChildren(SortDatatableDirective);
constructor() {
this.basicTable$ = this.service.basicTable$;
this.total$ = this.service.total$;
}
onSort({ column, direction }: SortEvent) {
this.headers().forEach(header => {
if (header.sortable() !== column) {
header.currentDirection.set('');
}
});
this.service.sortColumn = column;
this.service.sortDirection = direction;
}
deleteData(id: number) {
this.basicTable$.subscribe((data: Table[]) => {
data.map((elem: Table, i: number) => {
elem.id == id && data.splice(i, 1);
});
});
}
}
// sortable.directive.ts
import { Directive, HostBinding, HostListener, input, output, signal } from '@angular/core';
import { Table } from '../interface/datatable';
export type SortColumn = keyof Table | '';
export type SortDirection = 'asc' | 'desc' | '';
const rotate: { [key: string]: SortDirection } = { asc: 'desc', desc: '', '': 'asc' };
export interface SortEvent {
column: SortColumn;
direction: SortDirection;
}
@Directive({
selector: '[th[sortable]]',
host: {
'[class.asc]': 'direction === "asc"',
'[class.desc]': 'direction === "desc"',
'(click)': 'rotate()',
},
})
export class SortDatatableDirective {
readonly direction = input('');
readonly sortable = input('');
public currentDirection = signal(this.direction());
readonly sort = output();
@HostBinding('class.asc')
get isAsc() {
return this.currentDirection() === 'asc';
}
@HostBinding('class.desc')
get isDesc() {
return this.currentDirection() === 'desc';
}
@HostListener('click')
rotateColumn() {
this.currentDirection.set(rotate[this.currentDirection()]);
this.sort.emit({ column: this.sortable(), direction: this.currentDirection() });
}
}
Supplemental
Charts
Installing and usage
npm i ng-apexcharts
// basic-aria-chart.html //
<apx-chart
[chart]="basicAriaCharts.chart"
[dataLabels]="basicAriaCharts.dataLabels"
[stroke]="basicAriaCharts.stroke"
[fill]="basicAriaCharts.fill"
[series]="basicAriaCharts.series"
[title]="basicAriaCharts.title"
[colors]="basicAriaCharts.colors"
[labels]="basicAriaCharts.labels"
[xaxis]="basicAriaCharts.xaxis"
[yaxis]="basicAriaCharts.yaxis"
[subtitle]="basicAriaCharts.subtitle"
[legend]="basicAriaCharts.legend">
</apx-chart>
// basic-aria-chart.ts //
import { Component } from '@angular/core';
import * as data from '../../../../shared/data/charts/apex-chart'
import { NgApexchartsModule } from 'ng-apexcharts';
@Component({
selector: 'app-basic-aria-chart',
standalone: true,
imports:[NgApexchartsModule],
templateUrl: './basic-aria-chart.html',
styleUrls: ['./basic-aria-chart.scss']
})
export class BasicAriaChart {
public basicAriaCharts = data.basicAriaCharts;
}
// apex-chart.ts //
import {
AreaSpalineChart
} from '../../interface/charts/apex-charts';
let primary = localStorage.getItem('primary_color') || '#3e5fce';
let secondary = localStorage.getItem('secondary_color') || '#ffce00';
export let basicAriaCharts: BasicChart = {
chart: {
height: 350,
type: 'area',
zoom: {
enabled: false,
},
toolbar: {
show: false,
},
},
dataLabels: {
enabled: false,
},
stroke: {
curve: 'straight',
},
series: [
{
name: 'STOCK ABC',
data: [
8107.85, 8128.0, 8122.9, 8165.5, 8340.7, 8423.7, 8423.5, 8514.3, 8481.85, 8487.7, 8506.9,
8626.2, 8668.95, 8602.3, 8607.55, 8512.9, 8496.25, 8600.65, 8881.1, 9340.85,
],
},
],
title: {
text: 'Fundamental Analysis of Stocks',
align: 'left',
},
subtitle: {
text: 'Price Movements',
align: 'left',
},
labels: [
'13 Nov 2017',
'14 Nov 2017',
'15 Nov 2017',
'16 Nov 2017',
'17 Nov 2017',
'20 Nov 2017',
'21 Nov 2017',
'22 Nov 2017',
'23 Nov 2017',
'24 Nov 2017',
'27 Nov 2017',
'28 Nov 2017',
'29 Nov 2017',
'30 Nov 2017',
'01 Dec 2017',
'04 Dec 2017',
'05 Dec 2017',
'06 Dec 2017',
'07 Dec 2017',
'08 Dec 2017',
],
xaxis: {
type: 'datetime',
},
yaxis: {
opposite: true,
},
legend: {
horizontalAlign: 'left',
},
colors: [primary],
};
Supplemental
Installing and usage
npm i ng2-google-charts
// aria-chart1.html //
<google-chart [data]="areaChart1"></google-chart>
//aria-chart1.ts //
import { Component } from '@angular/core';
import * as data from '../../../../shared/data/charts/google-chart';
import { Ng2GoogleChartsModule } from 'ng2-google-charts';
@Component({
selector: 'app-aria-chart1',
standalone: true,
imports:[Ng2GoogleChartsModule],
templateUrl: './aria-chart1.html',
styleUrls: ['./aria-chart1.scss']
})
export class AriaChart1 {
public areaChart1 = data.areaChart1;
}
// google-chart-data.ts //
import { GoogleChartType } from "ng2-google-charts";
let primary_color = localStorage.getItem('primary_color') || '#3e5fce';
let secondary_color = localStorage.getItem('secondary_color') || '#ffce00';
export var areaChart1 = {
chartType: 'AreaChart',
dataTable: [
['Year', 'Sales', 'Expenses'],
['2013', 1000, 400],
['2014', 1170, 460],
['2015', 660, 1120],
['2016', 1030, 540]
],
options: {
title: 'Company Performance',
hAxis: { title: 'Year', titleTextStyle: { color: '#333' } },
vAxis: { minValue: 0 },
width: '100%',
height: 400,
colors: [primary_color, secondary_color],
},
};
Supplemental
Installing and usage
npm i ng2-charts
//bars-charts.html//
<canvas baseChart class="chart"
[data]="barChart"
[datasets]="barChart.datasets"
[options]="barChart.barOptions"
>
</canvas>
//bars-charts.ts//
import { Component } from '@angular/core';
import * as data from '../../../../shared/data/charts/chatjs';
import { BaseChartDirective } from 'ng2-charts';
@Component({
selector: 'app-bars-charts',
standalone: true,
imports: [BaseChartDirective],
templateUrl: './bars-charts.html',
styleUrls: ['./bars-charts.scss']
})
export class BarsCharts {
public barChart = data.barChart;
}
// chartjs-data.ts //
let primary_color = localStorage.getItem('primary_color') || '#3e5fce';
let secondary_color = localStorage.getItem('secondary_color') || '#ffce00';
// Bar Graph
export const barChart = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
responsive: false,
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(43, 94, 94, 0.4)',
borderColor: primary_color,
borderWidth: 2,
data: [35, 59, 80, 81, 56, 55, 40],
},
{
label: 'My Second dataset',
borderColor: secondary_color,
backgroundColor: 'rgba(192, 98, 64, 0.4)',
borderWidth: 2,
data: [28, 48, 40, 19, 86, 27, 90],
},
],
barOptions: [
{
scaleBeginAtZero: true,
scaleShowGridLines: true,
scaleGridLineColor: 'rgba(0,0,0,0.1)',
scaleGridLineWidth: 1,
scaleShowHorizontalLines: true,
scaleShowVerticalLines: true,
barShowStroke: true,
barStrokeWidth: 2,
barValueSpacing: 5,
barDatasetSpacing: 1,
},
],
};
Supplemental
Installing and usage
npm i ng-chartist
// chart1.html
<x-chartist
[configuration]="chart1">
</x-chartist>
// chart1.ts
import { Component } from '@angular/core';
import * as data from '../../../../shared/data/charts/chartlist';
import { ChartistModule } from 'ng-chartist';
@Component({
selector: 'app-chart1',
standalone: true,
imports:[ChartistModule],
templateUrl: './chart1.html',
styleUrls: ['./chart1.scss']
})
export class Chart1 {
public chart1 = data.chart1;
}
// chartlist chart data
import * as Chartist from 'chartist';
import { LineChartConfiguration } from 'ng-chartist';
export const chart1: LineChartConfiguration = {
type: 'Line',
data: {
labels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'],
series: [
[12, 9, 7, 8, 5, 4, 6, 2, 3, 3, 4, 6],
[4, 5, 3, 7, 3, 5, 5, 3, 4, 4, 5, 5],
[5, 3, 4, 5, 6, 3, 3, 4, 5, 6, 3, 4],
[3, 4, 5, 6, 7, 6, 4, 5, 6, 7, 6, 3],
],
},
options: {
low: 0,
showArea: false,
fullWidth: true,
height: 250,
},
};
Supplemental
Maps
Installing and usage
npm i @angular/google-maps
// google-map.html
<google-map width="100%" height="500px" [zoom]="zoom">
<map-marker *ngFor="let marker of markers" [position]="marker.position" [label]="marker.label">
</map-marker>
</google-map>
// google-map.ts
import { Component } from '@angular/core';
import { GoogleMapsModule } from '@angular/google-maps';
interface IMarkerPosition {
lat: number;
lng: number;
}
interface IMarkerLabel {
color: string;
text: string;
}
interface IGoogleMapMarkers {
position: IMarkerPosition;
label: IMarkerLabel;
}
@Component({
selector: 'app-google-map',
imports: [GoogleMapsModule],
templateUrl: './google-map.html',
styleUrls: ['./google-map.scss'],
})
export class GoogleMaps {
public asiaMapOptions: google.maps.MapOptions = {
center: { lat: 47.5162, lng: 100.2167 },
zoom: 3,
};
public worldMapOption: google.maps.MapOptions = {
center: { lat: 0, lng: 0 },
zoom: 2,
};
public usaMapOptions: google.maps.MapOptions = {
center: { lat: 37.0902, lng: -95.7129 },
zoom: 4,
};
public indiaMapOptions: google.maps.MapOptions = {
center: { lat: 20.5937, lng: 78.9629 },
zoom: 4,
};
public markers: IGoogleMapMarkers[];
public zoom: number;
constructor() {
this.markers = [];
this.markers.push({
position: {
lat: 32.4279,
lng: 53.688,
},
label: {
color: 'black',
text: 'Iran',
},
});
this.markers.push({
position: {
lat: 33.9391,
lng: 67.71,
},
label: {
color: 'black',
text: 'Afghanistan',
},
});
this.markers.push({
position: {
lat: 23.0225,
lng: 72.5714,
},
label: {
color: 'black',
text: 'Ahmadabad',
},
});
}
}
Supplemental
Installing and usage
npm i @asymmetrik/ngx-leaflet
// leaflet-map.html
<div class="map-height" leaflet [leafletOptions]="options1"></div>
// leaflet-map.ts
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { LeafletModule } from '@bluehalo/ngx-leaflet';
import * as L from 'leaflet';
@Component({
selector: 'app-leaflet-map',
imports: [CommonModule, LeafletModule],
templateUrl: './leaflet-map.html',
styleUrls: ['./leaflet-map.scss'],
})
export class LeafletMap {
options1 = {
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '...',
}),
],
zoom: 5,
center: L.latLng(46.879966, -121.726909),
};
//Second map
layersControl = {
baseLayers: {
'Open Street Map': L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '...',
}),
'Open Cycle Map': L.tileLayer('http://{s}.tile.opencyclemap.org/cycle/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '...',
}),
},
overlays: {
'Big Circle': L.circle([46.95, -122], { radius: 5000 }),
'Big Square': L.polygon([
[46.8, -121.55],
[46.9, -121.55],
[46.9, -121.7],
[46.8, -121.7],
]),
},
};
options2 = {
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 50,
attribution: '...',
}),
],
zoom: 5,
center: L.latLng(46.879966, -121.726909),
};
//Third map
map: L.Map;
options3 = {
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '',
}),
],
zoom: 7,
center: L.latLng(47.482023, -1),
};
//Forth map
map4: L.Map;
homeCoords = {
lat: 23.810331,
lon: 90.412521,
};
popupText = 'Some popup text';
markerIcon = {
icon: L.icon({
iconSize: [25, 41],
iconAnchor: [10, 41],
popupAnchor: [2, -40],
iconUrl: 'assets/images/marker-icon.png',
shadowUrl: 'assets/images/marker-shadow.png',
}),
};
options4 = {
layers: [
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '',
}),
],
zoom: 5,
center: L.latLng(this.homeCoords.lat, this.homeCoords.lon),
};
initMarkers() {
const popupInfo = `${this.popupText}`;
L.marker([this.homeCoords.lat, this.homeCoords.lon], this.markerIcon)
.addTo(this.map4)
.bindPopup(popupInfo);
}
onMapReady4(map: L.Map) {
this.map4 = map;
this.initMarkers();
}
}
Supplemental
Editors
Installing and usage
npm i ngx-editor
// ngx-editors.html
<ngx-editor-menu [editor]="editor"> </ngx-editor-menu>
<ngx-editor [editor]="editor" [ngModel]="html" [disabled]="false" [placeholder]="'Type here...'"></ngx-editor>
// ngx-editors.ts
import { Component } from '@angular/core';
import { Editor } from 'ngx-editor';
@Component({
selector: 'app-ngx-editors',
templateUrl: './ngx-editors.html',
styleUrl: './ngx-editors.scss'
})
export class NgxEditors {
public editor: Editor;
public html = '';
ngOnInit(): void {
this.editor = new Editor();
}
ngOnDestroy(): void {
this.editor.destroy();
}
}
Supplemental
Installing and usage
@kolkov/angular-editor
// mde-editors.html
<angular-editor [placeholder]="'Enter text here...'" [(ngModel)]="htmlContent"></angular-editor>
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { AngularEditorModule } from '@kolkov/angular-editor';
@Component({
selector: 'app-mde-editors',
standalone: true,
imports:[AngularEditorModule,FormsModule],
templateUrl: './mde-editors.html',
styleUrls: ['./mde-editors.scss']
})
export class MdeEditors {
public htmlContent = '';
}
Supplemental