Skip to content

Instantly share code, notes, and snippets.

@killan
Created February 9, 2025 10:50
Show Gist options
  • Save killan/c1ca06fac2f637d4101e837af37fcffa to your computer and use it in GitHub Desktop.
Save killan/c1ca06fac2f637d4101e837af37fcffa to your computer and use it in GitHub Desktop.
Angular tabs system - signal version
import { Component } from '@angular/core';
import { NgClass } from '@angular/common';
import { TabCommonComponent } from './tab-common.component';
@Component({
selector: 'oma-tab-action',
imports: [
NgClass
],
templateUrl: "tab-common.component.html"
})
export class TabActionComponent extends TabCommonComponent {
}
@if ((lazy() && active()) || !lazy()) {
<div [ngClass]="{ hidden: !active() }">
<ng-content />
</div>
}
import {
Component, effect,
model, output,
} from '@angular/core';
import { NgClass } from '@angular/common';
@Component({
selector: 'oma-tab-common',
imports: [
NgClass
],
templateUrl: "tab-common.component.html"
})
export class TabCommonComponent {
id = model<number | string>(0, {
alias: 'tabId'
})
active = model(false)
lazy = model(false)
constructor() {
effect(() => {
const active = this.active()
active ? this.onActive.emit(active) : this.onInactive.emit(active)
if (active) {
this.lazy.set(false)
}
});
}
onActive = output<boolean>()
onInactive = output<boolean>()
}
import { Component, input } from '@angular/core';
import { NgClass } from '@angular/common';
import { TabCommonComponent } from './tab-common.component';
@Component({
selector: 'oma-tab',
imports: [
NgClass
],
templateUrl: "tab-common.component.html"
})
export class TabComponent extends TabCommonComponent {
title = input("")
}
<div class="tabs-actions">
<div class="flex justify-between">
<ul class="list-none">
@for (t of tabs; track t.id(); let idx = $index) {
<li class="inline-block" [ngClass]="{ selected: selectedTabId() === t.id() }">
<p-button [label]="t.title()" (onClick)="changeTab(t)" />
</li>
}
</ul>
<div class="text-right self-center">
<ng-content select="oma-tab-action" />
</div>
</div>
<div>
<ng-content select="oma-tab" />
</div>
</div>
import {
AfterContentInit,
Component,
ContentChildren, input,
QueryList, signal
} from '@angular/core';
import { NgClass } from '@angular/common';
import { Button } from 'primeng/button';
import { TabComponent } from './tab.component';
import { TabActionComponent } from './tab-action.component';
import { TabCommonComponent } from './tab-common.component';
@Component({
selector: 'oma-tabs',
imports: [
NgClass,
Button
],
templateUrl: './tabs.component.html'
})
export class TabsComponent implements AfterContentInit {
@ContentChildren(TabComponent) tabs!: QueryList<TabComponent>
@ContentChildren(TabActionComponent) tabsAction!: QueryList<TabActionComponent>
selected = input(0)
selectedTabId = signal<number | string>(0)
ngAfterContentInit() {
let indexing = 0;
const fnIndexing = (t: TabCommonComponent) => {
if (!t.id()) {
t.id.set(indexing++)
}
}
this.tabs.forEach(fnIndexing)
this.tabsAction.forEach(fnIndexing)
this.selectedTabId.set(this.selected() || this.tabs.first.id() || 0)
const tabActive = this.tabs.find(t => this.selectedTabId() === t.id())
if (tabActive) {
tabActive.active.set(true)
}
const tabActionActive = this.tabsAction.find(t => this.selectedTabId() === t.id())
if (tabActionActive) {
tabActionActive.active.set(true)
}
}
changeTab(tab: TabComponent) {
if (this.selectedTabId() != tab.id()) {
this.selectedTabId.set(tab.id())
// Change visibility
const fnChange = (t: TabCommonComponent) => {
t.active.set(t.id() === this.selectedTabId())
}
this.tabs.forEach(fnChange)
this.tabsAction.forEach(fnChange)
// TODO on change
}
}
}
@killan
Copy link
Author

killan commented Feb 9, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment