Top

Component


Abstract Elements

In theme we are using Abstract Elements for calling small widgets. so It will easy to use and user freindlly from developer perspective.

Basic UI Elements

<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

PrimarySecondarySuccessInfoWarningDangerLightDark

<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>
Dismissible popover

<button class="btn btn-primary example-popover" type="button" placement="left"  popoverTitle="Basic Popover" ngbPopover="If the package restore doesn't help, you can look at the Output window in the Visual Studio.">Hurry Up! </button>
<button class="example-popover btn btn-warning" type="button" placement="bottom" popoverTitle="Hover Popover" data-offset="-20px -20px"  ngbPopover=" Several utility instruction sets have been featured in the Bootstrap 4 to promote very easy learning for beginners in the business of web building.">Hover tooltip</button>
<a class="btn btn-lg btn-secondary" tabindex="0" role="button" placement="right" popoverTitle="Dismissible popover"  ngbPopover="You are able to even develop and suggest improvements to the Bootstrap 4 before its final version is delivered.">Dismissible popover</a>
  
// tooltip.component.html //

  <button class="example-popover btn btn-primary" type="button" data-bs-placement="top" title="Popover title" 
  ngbTooltip="Basic Tooltip">
  Hover Me
  </button>
                                

  // tooltip.component.ts //
  
  @Component({
    selector: 'tooltip',
    templateUrl: './tooltip.component.html'
  })
  export class TooltipComponent {
    name = 'World';
  }
                                

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" ngbNavLink>Home</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>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]="4">
      <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>
                                
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 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.
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 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.
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 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.
  <div ngbAccordion [closeOthers]="true">
	@for (item of items; track item) {
		<div ngbAccordionItem [collapsed]="item !== 'First'">
			<h2 ngbAccordionHeader>
				<button ngbAccordionButton>{{ item }}</button>
			</h2>
			<div ngbAccordionCollapse>
				<div ngbAccordionBody>
					<ng-template>
						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
						wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.
						Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan
						excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt
						you probably haven't heard of them accusamus labore sustainable VHS.
					</ng-template>
				</div>
			</div>
		</div>
	}
</div>
// ts code

import { Component } from '@angular/core';
import { NgbAccordionModule } from '@ng-bootstrap/ng-bootstrap';

@Component({
	selector: 'ngbd-accordion-static',
	standalone: true,
	imports: [NgbAccordionModule],
	templateUrl: './accordion-static.html',
})
export class NgbdAccordionStatic {
	items = ['First', 'Second', 'Third'];
}



Advance UI Elements

Installing and usage

npm i ngx-bar-rating

// rating.component.html

<bar-rating class="bar" [(rate)]="faRate" [max]="10" [theme]="'horizontal'" [showText]="true"></bar-rating>

                                

// rating.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-rating-bar',
  templateUrl: './rating-bar.component.html',
  styleUrls: ['./rating-bar.component.scss']
})

export class RatingBarComponent {
  public faRate = 7;
}


Supplemental

Installing and usage

npm i sweetalert2

  // sweet-alert2.component.html
  <button class="btn btn-primary sweet-1" type="button" (click)="basicAlert()">Click it!</button>
                                

  // sweet-alert2.component.ts 
  
  import { Component } from '@angular/core';
  import Swal from 'sweetalert2';
  
  @Component({
    selector: 'app-basic',
    templateUrl: './basic.component.html',
    styleUrls: ['./basic.component.scss']
  })
  
  export class BasicComponent {
    basicAlert(){
      Swal.fire({
        title : 'Welcome! to the Yuri theme',
        confirmButtonColor : 'var(--theme-deafult)',
      })
    }
  }
                                
Supplemental

Installing and usage

npm i @angular-slider/ngx-slider

                                
  // range-slider.component.html //
  <ngx-slider [(value)]="value" [options]="options"></ngx-slider>
                                

  // range-slider.components.ts //
  
import { Component } from '@angular/core';
import { Options } from 'ngx-slider-v2';

@Component({
  selector: 'app-default-slider',
  templateUrl: './default-slider.component.html',
  styleUrls: ['./default-slider.component.scss']
})

export class DefaultSliderComponent {

  public value: number = 550;
  public options: Options = {
    floor: 100,
    ceil: 1000,
  };
}
                                
Supplemental

Installing and usage

npm i ngx-dropzone
// dropzone.component.html
  <ngx-dropzone (change)="onSelect($event)">
            <ngx-dropzone-label>Drag & Drop your files or Browse</ngx-dropzone-label>
            @for (f of files; track f) {
            <ngx-dropzone-preview [removable]="true" (removed)="onRemove(f)">
                <ngx-dropzone-label>{{ f.name }} ({{ f.type }})</ngx-dropzone-label>
            </ngx-dropzone-preview>
            }
  </ngx-dropzone>

  // dropzone.component.ts
  
  public files: File[] = [];

  onSelect(event: NgxDropzoneChangeEvent) {
    this.files.push(...event.addedFiles);
  }

  onRemove(event: File) {
		this.files.splice(this.files.indexOf(event), 1);
	}
  
  
Supplemental

Forms

Installing and usage

npm i @ng-bootstrap/ng-bootstrap
//forms-widgets.module.ts //
import { NgbCalendar, NgbDatepickerModule, NgbDateStruct } from '@ng-bootstrap/ng-bootstrap';
import { FormsModule } from '@angular/forms';

@Component({
	selector: 'ngbd-datepicker-basic',
	standalone: true,
	imports: [NgbDatepickerModule, FormsModule],
	templateUrl: './datepicker-basic.html',
})

export class NgbdDatepickerBasic {
	model: NgbDateStruct;
}

                       
                   
//date-time-picker.component.html //
                                  
  <ngb-datepicker #dp [(ngModel)]="model" (navigate)="date = $event.next" />
                                
Supplemental

Installing and usage

npm i @ng-bootstrap/ng-bootstrap

<input id="typeahead-basic" type="text" class="form-control" [(ngModel)]="model" [ngbTypeahead]="search" />

import { Component } from '@angular/core';
import { NgbTypeaheadModule } from '@ng-bootstrap/ng-bootstrap';
import { Observable, OperatorFunction } from 'rxjs';
import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators';
import { FormsModule } from '@angular/forms';
import { JsonPipe } from '@angular/common';

const states = [
	'Alabama',
	'Alaska',
	'American Samoa',
	'Arizona',
	'Arkansas',
	'California',
	'Colorado',
	'Connecticut',
	'Delaware',
	'District Of Columbia',
	'Federated States Of Micronesia',
	'Florida',
	'Georgia',
	'Guam',
	'Hawaii',
	'Idaho',
	'Illinois',
	'Indiana',
	'Iowa',
	'Kansas',
	'Kentucky',
	'Louisiana',
	'Maine',
	'Marshall Islands',
	'Maryland',
	'Massachusetts',
	'Michigan',
	'Minnesota',
	'Mississippi',
	'Missouri',
	'Montana',
	'Nebraska',
	'Nevada',
	'New Hampshire',
	'New Jersey',
	'New Mexico',
	'New York',
	'North Carolina',
	'North Dakota',
	'Northern Mariana Islands',
	'Ohio',
	'Oklahoma',
	'Oregon',
	'Palau',
	'Pennsylvania',
	'Puerto Rico',
	'Rhode Island',
	'South Carolina',
	'South Dakota',
	'Tennessee',
	'Texas',
	'Utah',
	'Vermont',
	'Virgin Islands',
	'Virginia',
	'Washington',
	'West Virginia',
	'Wisconsin',
	'Wyoming',
];

@Component({
	selector: 'ngbd-typeahead-basic',
	standalone: true,
	imports: [NgbTypeaheadModule, FormsModule, JsonPipe],
	templateUrl: './typeahead-basic.html',
	styles: `.form-control { width: 300px; }`,
})
export class NgbdTypeaheadBasic {
	model: any;

	search: OperatorFunction = (text$: Observable) =>
		text$.pipe(
			debounceTime(200),
			distinctUntilChanged(),
			map((term) =>
				term.length < 2 ? [] : states.filter((v) => v.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10),
			),
		);
}


Supplemental

Tables
# First Last Handle
1 Mark Otto @mdo
2 Jacob Thornton @fat
3 Larry the Bird @twitter

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>
  
Supplemental

Installing and usage

npm i @ng-bootstrap/ng-bootstrap
           
// data.ts

export const basicDataTable: 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',
  },
];
                                
                                  

// countries.service.ts

import { Injectable, PipeTransform } from '@angular/core';
import { Table, basicDataTable } from '../data/data/table/data-table';
import { BehaviorSubject, Observable, Subject, debounceTime, delay, of, switchMap, tap } from 'rxjs';
import { DecimalPipe } from '@angular/common';
import { SortColumn, SortDirection } from '../directives/basic-data-table.directive';

interface SearchResult {
	baiscTable: Table[];
	total: number;
}

interface State {
	page: number;
	pageSize: number;
	searchTerm: string;
	sortColumn: SortColumn;
	sortDirection: SortDirection;
}

function sort(baiscTable: Table[], column: SortColumn, direction: string): Table[] {
	if (direction === '' || column === '') {
		return baiscTable;
	} else {
		return [...baiscTable].sort((a, b) => {
			const res = compare(a[column], b[column]);
			return direction === 'asc' ? res : -res;
		});
	}
}

const compare = (v1: string | number, v2: string | number) => (v1 < v2 ? -1 : v1 > v2 ? 1 : 0);

function matches(table: Table, term: string, pipe: PipeTransform) {
	return (
		table.name.toLowerCase().includes(term.toLowerCase()) ||
		table.position.toLowerCase().includes(term.toLowerCase()) ||
		table.office.toLowerCase().includes(term.toLowerCase()) ||
		table.startDate.toLowerCase().includes(term.toLowerCase()) ||
		table.salary.toLowerCase().includes(term.toLowerCase()) ||
		pipe.transform(table.age).includes(term) 
	)
}

@Injectable({
	providedIn: 'root'
})

export class BasicDataTableService {

	private _loading$ = new BehaviorSubject(true);
	private _search$ = new Subject();
	private _orderList$ = new BehaviorSubject([]);
	private _total$ = new BehaviorSubject(0);
	private _basic: 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._orderList$.next(result.baiscTable);
				this._total$.next(result.total);
			});
		this._search$.next();
	}
	get basicDataTable$() {
		return this._orderList$.asObservable();
	}
	get total$() {
		return this._total$.asObservable();
	}
	get loading$() {
		return this._loading$.asObservable();
	}
	get page() {
		return this._basic.page;
	}
	get pageSize() {
		return this._basic.pageSize;
	}
	get searchTerm() {
		return this._basic.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._basic, patch);
		this._search$.next();
	}
	private _search(): Observable {
		const { sortColumn, sortDirection, pageSize, page, searchTerm } = this._basic;

		// 1. sort
		let baiscTable = sort(basicDataTable, sortColumn, sortDirection);

		// 2. filter
		baiscTable = baiscTable.filter((list) => matches(list, searchTerm, this.pipe));
		const total = baiscTable.length;

		// 3. paginate
		baiscTable = baiscTable.slice((page - 1) * pageSize, (page - 1) * pageSize + pageSize);
		return of({ baiscTable, total });
	}
}
                                     
                                  

//interface

export interface Table {
  id: number;
  name: string;
  position: string;
  office: string;
  startDate: string;
  salary: string;
  age: string;
}
                                  
                                  

 // table-component.html

 <div class="table-responsive custom-scrollbar">
 <div class="dataTables_wrapper no-footer">
     <div class="mb-3 row">
         <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>
         @if (service.loading$ | async) {
         <span class="col col-form-label">Loading...</span>
         }
     </div>
     <table class="display dataTable" id="basic-1">
         <thead>
             <tr>
                 <th sortableDefault="name" (sort)="onSort($event)">Name</th>
                 <th sortableDefault="position" (sort)="onSort($event)">Position</th>
                 <th sortableDefault="office" (sort)="onSort($event)">Office</th>
                 <th sortableDefault="age" (sort)="onSort($event)">Age</th>
                 <th sortableDefault="startDate" (sort)="onSort($event)">Start date</th>
                 <th sortableDefault="salary" (sort)="onSort($event)">Salary</th>
                 <th>Action</th>
             </tr>
         </thead>
         <tbody>
             @for (item of basicDataTable$ | async; track item) {
             <tr>
                 <td>{{item.name}}</td>
                 <td>{{item.position}}</td>
                 <td>{{item.office}}</td>
                 <td>{{item.age}}</td>
                 <td>{{item.startDate}}</td>
                 <td>{{item.salary}}</td>
                 <td>
                     <ul class="action">
                         <li class="edit">
                             <a href="javascript:void(0)">
                                 <i class="icon-pencil-alt"></i>
                             </a>
                         </li>
                         <li class="delete">
                             <a href="javascript:void(0)">
                                 <i class="icon-trash"></i>
                             </a>
                         </li>
                     </ul>
                 </td>
             </tr>
             }
             @if (basicData.length === 0) {
             <tr>
                 <td>No matching records found</td>
             </tr>
             }
         </tbody>
     </table>
     <div class="d-flex justify-content-between p-2">
         <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 [collectionSize]="(total$ | async)!" [(page)]="service.page"
             [pageSize]="service.pageSize"> </ngb-pagination>
     </div>
 </div>
</div>



    // table-component.ts

import { DecimalPipe } from '@angular/common';
import { Component, QueryList, ViewChildren } from '@angular/core';
import { Observable } from 'rxjs';
import { Table } from '../../../shared/data/data/table/data-table';
import { BasicDataTableDirective, SortEvent } from '../../../shared/directives/basic-data-table.directive';
import { BasicDataTableService } from '../../../shared/services/basic-data-table.service';

@Component({
  selector: 'app-data-tables',
  templateUrl: './data-tables.component.html',
  styleUrls: ['./data-tables.component.scss'],
  providers: [BasicDataTableService, DecimalPipe],
})

export class DataTablesComponent {

  public isShow: boolean = false;
  public basicDataTable$: Observable;
  public total$: Observable;
  public basicData: Table[];
  @ViewChildren(BasicDataTableDirective)
  public headers: QueryList;

  constructor(public service: BasicDataTableService) {
    this.basicDataTable$ = service.basicDataTable$;
    this.total$ = service.total$;
  }

  ngOnInit() {
    this.service.basicDataTable$.subscribe((data) => {
      if (data) {
        this.basicData = data;
      }
    });
  }

  onSort({ column, direction }: SortEvent) {
    this.headers.forEach((header) => {
      if (header.sortableDefault !== column) {
        header.direction = "";
      }
    });
    this.service.sortColumn = column;
    this.service.sortDirection = direction;
  }
}
       
    
        
  
   // sortable.directive.ts

   import { Directive, EventEmitter, Input, Output } from '@angular/core';
   import { Table } from '../data/data/table/data-table';
   
   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[sortableDefault]',
     standalone: true,
     host: {
       '[class.asc]': 'direction === "asc"',
       '[class.desc]': 'direction === "desc"',
       '(click)': 'rotate()',
     },
   })
   
   export class BasicDataTableDirective {
   
     constructor() { }
   
     @Input() sortableDefault: SortColumn = '';
     @Input() direction: SortDirection = '';
     @Output() sort = new EventEmitter();
     rotate() {
       this.direction = rotate[this.direction];
       this.sort.emit({ column: this.sortableDefault, direction: this.direction });
     }
   }
   

Supplemental

Charts

Installing and usage

npm i ng-apexcharts
// basic-aria-chart.component.html //
  <apx-chart [chart]="basicAreaChart.chart" [dataLabels]="basicAreaChart.dataLabels"
  [stroke]="basicAreaChart.stroke" [series]="basicAreaChart.series" [title]="basicAreaChart.title"
  [subtitle]="basicAreaChart.subtitle" [labels]="basicAreaChart.labels" [xaxis]="basicAreaChart.xaxis"
  [yaxis]="basicAreaChart.yaxis" [legend]="basicAreaChart.legend" [colors]="basicAreaChart.colors">
                              

// basic-aria-chart.component.ts //

import { Component } from '@angular/core';
import { basicAreaChart } from '../../../../shared/data/chart/charts/apex-charts';

@Component({
  selector: 'app-basic-area-chart',
  templateUrl: './basic-area-chart.component.html',
  styleUrls: ['./basic-area-chart.component.scss']
})

export class BasicAreaChartComponent {

  public basicAreaChart = basicAreaChart ;

}

                              

// data files //

export type ChartOptions = {
  series?: ApexAxisChartSeries;
  chart?: ApexChart;
  xaxis?: ApexXAxis;
  stroke?: ApexStroke;
  tooltip?: any;
  dataLabels?: ApexDataLabels;
  hover?: number;
  yaxis?: ApexYAxis;
  legend?: ApexLegend;
  labels?: string[];
  plotOptions?: ApexPlotOptions;
  fill?: ApexFill;
  responsive?: ApexResponsive[];
  pieseries?: ApexNonAxisChartSeries;
  title?: ApexTitleSubtitle;
  theme?: ApexTheme;
  colors?: string[];
  markers?: ApexMarkers;
  annotations?: ApexAnnotations;
  grid?: ApexGrid;
};

export let basicAreaChart: ChartOptions | any = {
  chart: {
      height: 350,
      type: "area",
      zoom: {
          enabled: false,
      },
      toolbar: {
          show: false,
      },
  },
  dataLabels: {
      enabled: false,
  },
  stroke: {
      curve: "straight",
  },
  series: [
      {
          name: "STOCK ABC",
          data: series.monthDataSeries1.prices,
      },
  ],
  title: {
      text: "Fundamental Analysis of Stocks",
      align: "left",
  },
  subtitle: {
      text: "Price Movements",
      align: "left",
  },
  labels: series.monthDataSeries1.dates,
  xaxis: {
      type: "datetime",
  },
  yaxis: {
      opposite: true,
  },
  legend: {
      horizontalAlign: "left",
  },
  colors: [primary],
}

                              
Supplemental

Installing and usage

npm i ng2-google-charts

 // googl-chart.component.html //
 <google-chart [data]="areaChart1"></google-chart>
                              

//googl-chart.component.ts //
                                 
import { Component } from '@angular/core';
import { areaChart1 } from '../../../../shared/data/chart/charts/google-charts';

@Component({
  selector: 'app-area-chart-first',
  templateUrl: './area-chart-first.component.html',
  styleUrls: ['./area-chart-first.component.scss']
})

export class AreaChartFirstComponent {

  public areaChart1 = areaChart1;

}

                                 
                              

// data //

import { GoogleChartType } from "ng2-google-charts";

var primary = localStorage.getItem('primary_color') || '#009DB5';
var secondary = localStorage.getItem('secondary_color') || '#F94C8E';

export const 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, secondary],
    },
};


                                 
                              
Supplemental

Installing and usage

npm i ng2-charts
//bars-charts.component.html//
<canvas baseChart id="myBarGraph" class="chart" [datasets]="barChartChartData" [labels]="barChartChartLabels"
[options]="barChartChartOptions" [legend]="barChartChartLegend" [type]="barChartChartType"></canvas>              
                              
//bars-charts.component.ts//

import { Component } from '@angular/core';
import { barChartChartColors, barChartChartData, barChartChartLabels, barChartChartLegend, barChartChartOptions, barChartChartType } from '../../../../shared/data/chart/charts/chart-js';

@Component({
  selector: 'app-chart-js-bar-chart',
  templateUrl: './chart-js-bar-chart.component.html',
  styleUrls: ['./chart-js-bar-chart.component.scss']
})

export class ChartJsBarChartComponent {

  public barChartChartLabels = barChartChartLabels;
  public barChartChartData = barChartChartData;
  public barChartChartType = barChartChartType;
  public barChartChartColors = barChartChartColors;
  public barChartChartOptions = barChartChartOptions;
  public barChartChartLegend = barChartChartLegend;

}

 // chartjs-data.ts //
 export var barChartChartLabels: string[] = [
  "January", "February", "March", "April", "May", "June", "July"
];
export var barChartChartType: ChartType | any = "bar";
export var barChartChartLegend = false;
export var barChartChartOptions: any = {
  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,
};

export var barChartChartColors: any[] = [
  // { backgroundColor: [primary, secondary] },
];
export var barChartChartData: any[] = [
  {
    label: "My First dataset",
    fillColor: "rgba(0, 157 ,181, 0.4)",
    strokeColor: primary,
    highlightFill: "rgba(0, 157 ,181, 0.6)",
    highlightStroke: primary,
    data: [35, 59, 80, 81, 56, 55, 40],
  },
  {
    label: "My Second dataset",
    fillColor: "rgba(249, 76, 142, 0.4)",
    strokeColor: secondary,
    highlightFill: "rgba(249, 76, 142, 0.6)",
    highlightStroke: secondary,
    data: [28, 48, 40, 19, 86, 27, 90],
  },
];
                              
Supplemental

Installing and usage

npm i ng-chartist
// chart-list.html
<x-chartist [configuration]="chart1"></x-chartist>
                              
// chart-list.ts
import { Component } from '@angular/core';
import { chart1 } from '../../../../shared/data/chart/charts/chartist';

@Component({
  selector: 'app-advanced-smil-animations',
  templateUrl: './advanced-smil-animations.component.html',
  styleUrls: ['./advanced-smil-animations.component.scss']
})

export class AdvancedSMILAnimationsComponent {

  public chart1 = chart1;

}

// chartlist chart data

import * as Chartist from 'chartist';

var seq: number = 0;
var delays: number = 80;
var durations: number = 500;

var primary = localStorage.getItem('primary_color') || '#009DB5';
var secondary = localStorage.getItem('secondary_color') || '#F94C8E';

export const chart1: any = {
  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: 400,
    width: 700,
    colors: [primary, secondary],
  },
  events: {
    draw: (data: any) => {
      seq++;
      if (data.type === "line") {
        data.element.animate({
          opacity: {
            begin: seq * delays + 1000,
            dur: durations,
            from: 0,
            to: 1,
          },
        });
      } else if (data.type === "label" && data.axis === "x") {
        data.element.animate({
          y: {
            begin: seq * delays,
            dur: durations,
            from: data.y + 100,
            to: data.y,
            easing: "easeOutQuart",
          },
        });
      } else if (data.type === "label" && data.axis === "y") {
        data.element.animate({
          x: {
            begin: seq * delays,
            dur: durations,
            from: data.x - 100,
            to: data.x,
            easing: "easeOutQuart",
          },
        });
      } else if (data.type === "point") {
        data.element.animate({
          x1: {
            begin: seq * delays,
            dur: durations,
            from: data.x - 10,
            to: data.x,
            easing: "easeOutQuart",
          },
          x2: {
            begin: seq * delays,
            dur: durations,
            from: data.x - 10,
            to: data.x,
            easing: "easeOutQuart",
          },
          opacity: {
            begin: seq * delays,
            dur: durations,
            from: 0,
            to: 1,
            easing: "easeOutQuart",
          },
        });
      } else if (data.type === "grid") {
        var pos1Animation = {
          begin: seq * delays,
          dur: durations,
          from: data[data.axis.units.pos + "1"] - 30,
          to: data[data.axis.units.pos + "1"],
          easing: "easeOutQuart",
        };
        var pos2Animation = {
          begin: seq * delays,
          dur: durations,
          from: data[data.axis.units.pos + "2"] - 100,
          to: data[data.axis.units.pos + "2"],
          easing: "easeOutQuart",
        };
        var animations: any = {};
        animations[data.axis.units.pos + "1"] = pos1Animation;
        animations[data.axis.units.pos + "2"] = pos2Animation;
        animations["opacity"] = {
          begin: seq * delays,
          dur: durations,
          from: 0,
          to: 1,
          easing: "easeOutQuart",
        };
        data.element.animate(animations);
      }
    },
  },
};
                              
Supplemental

Maps

Installing and usage

npm i @angular/google-maps
// google-map.component.html
  <google-map width="100%" height="500px" [zoom]="zoom">
   @for (marker of markers; track marker) {
    <map-marker [position]="marker.position" [label]="marker.label">
    </map-marker>
   }
  </google-map>

                                
                               

// google-map.component.ts

import { Component, ViewChild } from '@angular/core';
import { GoogleMap } from '@angular/google-maps';

@Component({
  selector: 'app-googl-map',
  templateUrl: './googl-map.component.html',
  styleUrl: './googl-map.component.scss'
})

export class GooglMapComponent {

  public openInfo: any;
  public markers: any[];
  public markers1: any[];
  public zoom: number;

  public bangalore = { lat: 12.97, lng: 77.59 };
  constructor() {
    this.markers = [];
    this.zoom = 2;
  }

  ngOnInit() {
    this.markers1.push({
      position: {
        lat: 12.97,
        lng: 77.59
      },
      label: {
        color: "red",
        text: "Arial"
      },
      Option: {
        draggable: true,
        animation: google.maps.Animation.DROP,
        zoomControl: false,
        mapTypeControl: false,
        streetViewControl: false,
        fullscreenControl: false
      }
    });
    const map = new google.maps.Map(
      document.getElementById("map") as HTMLElement,
      {
        zoom: 12,
        center: this.bangalore,
      }
    );

    this.markers.push({
      position: {
        lat: 35.717,
        lng: 139.731
      },
      label: {
        color: "black",
        text: "Madrid"
      },
      Option: {
        draggable: true,
        animation: google.maps.Animation.DROP,
      }
    });

    this.markers.push({
      position: {
        lat: 48.8615515,
        lng: 2.3112233
      },
      label: {
        color: "black",
        text: "Paris"
      }
    });
  }

  //Street View
  @ViewChild(GoogleMap) map!: GoogleMap;

  ngAfterViewInit() {
    const streetView = this.map.getStreetView();

    streetView.setOptions({
      position: { lat: 38.9938386, lng: -77.2515373 },
      pov: { heading: 70, pitch: -10 },
    });

    streetView.setVisible(true);
    const bounds = this.getBounds(this.markers);
  }

  marker1 = { position: { lat: 38.9987208, lng: -77.2538699 } };
  marker2 = { position: { lat: 39.7, lng: -76.0 } };
  marker3 = { position: { lat: 37.9, lng: -76.8 } };

  markers5 = [this.marker1, this.marker2, this.marker3];

  getBounds(markers: any[]) {
    let north;
    let south;
    let east;
    let west;

    for (const marker of markers) {
      north = north !== undefined ? Math.max(north, marker.position.lat) : marker.position.lat;
      south = south !== undefined ? Math.min(south, marker.position.lat) : marker.position.lat;
      east = east !== undefined ? Math.max(east, marker.position.lng) : marker.position.lng;
      west = west !== undefined ? Math.min(west, marker.position.lng) : marker.position.lng;
    };

    const bounds = { north, south, east, west };

    return bounds;
  }

}

                              
                            
Supplemental

Installing and usage

npm i @asymmetrik/ngx-leaflet

// leaflet-map.component.html 

<div style="height: 500px; z-index: 0;" leaflet [leafletOptions]="options1"></div>

                              

import { Component } from '@angular/core';
import * as L from 'leaflet';

@Component({
  selector: 'app-leaflet-map',
  templateUrl: './leaflet-map.component.html',
  styleUrl: './leaflet-map.component.scss'
})

export class LeafletMapComponent {

  // First map options
  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),
  };
}
                              
Supplemental

Editors

Installing and usage

npm i ngx-editor
// ngx-editors.component.html
  <ngx-editor-menu [editor]="editor"> </ngx-editor-menu>
  <ngx-editor [editor]="editor" [ngModel]="html" [disabled]="false" [placeholder]="'Type here...'"></ngx-editor>
                              
// ngx-editors.component.ts

import { Component } from '@angular/core';
import { Editor } from 'ngx-editor';

@Component({
  selector: 'app-ngx-editor',
  templateUrl: './ngx-editor.component.html',
  styleUrl: './ngx-editor.component.scss'
})

export class NgxEditorComponent {

  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.component.html

<angular-editor [placeholder]="'Enter text here...'" [(ngModel)]="htmlContent"></angular-editor>
                                
                              
                                
                                
// mde-editors.component.ts

import { Component } from '@angular/core';

@Component({
selector: 'app-mde-editors',
templateUrl: './mde-editors.component.html',
styleUrls: ['./mde-editors.component.scss']
})

export class MdeEditorsComponent {
public htmlContent = '';

}


Supplemental