npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@libs-ui/components-pages-template-full-screen

v0.2.357-4

Published

> Khung layout toàn màn hình (Full Screen) cho Angular — tích hợp header đa vùng với action linh hoạt, giao tiếp micro-frontend, và hỗ trợ lazy load body component (V2).

Readme

@libs-ui/components-pages-template-full-screen

Khung layout toàn màn hình (Full Screen) cho Angular — tích hợp header đa vùng với action linh hoạt, giao tiếp micro-frontend, và hỗ trợ lazy load body component (V2).

Giới thiệu

Package này cung cấp hai component layout toàn màn hình cho Angular:

  • LibsUiComponentsPagesTemplateFullScreenComponent (V1 — @deprecated): Component gốc, sử dụng ng-content cho phần body. Phù hợp với codebase cũ nhưng không còn được khuyến khích dùng cho code mới.
  • LibsUiComponentsPagesTemplateFullScreenV2Component (V2 — khuyến dùng): Phiên bản nâng cấp, hỗ trợ lazy load body component động qua bodyConfig, skeleton tự động trong lúc chờ load, và FunctionsControl API để điều khiển từ component con.

Cả hai đều tích hợp sẵn cơ chế PostMessage để đồng bộ trạng thái "đang mở" với ứng dụng cha (micro-frontend host).

Tính năng

  • Header 3 vùng (Trái / Giữa / Phải) với phân chia class tùy chỉnh
  • Hỗ trợ các loại action trên header: button, button-status, switch, label, line-space, button-dropdown
  • TemplateRef tùy chỉnh cho từng vùng header (leftTemplate, centerTemplate, templateRight)
  • Menu dropdown "ba chấm" tích hợp sẵn (menuDropDownConfigs)
  • Tự động escape HTML cho tiêu đề (XSS protection)
  • Giao tiếp micro-frontend: gửi PostMessage open/close khi mount/unmount, ping định kỳ mỗi 2 giây
  • (V2) Lazy load body component qua Observable<Type<any>>
  • (V2) Skeleton tự động hiển thị trong lúc chờ Observable resolve
  • (V2) FunctionsControl — API để component con chủ động đóng page
  • (V2) ChangeDetectionStrategy.OnPush + Angular Signals

Khi nào sử dụng

  • Xây dựng màn hình cấu hình workflow, editor chuyên sâu chiếm trọn viewport
  • Các trang báo cáo dữ liệu lớn cần tối đa không gian hiển thị
  • Tạo mới thực thể phức tạp với quy trình nhiều bước (wizard-style)
  • Khi cần đồng bộ trạng thái "đang mở" với ứng dụng cha qua PostMessage
  • Khi muốn mở trang full screen từ TypeScript (không cần selector HTML) thông qua LibsUiDynamicComponentService
  • Khi body cần được lazy load theo bundle split với skeleton trong lúc chờ (dùng V2)

Cài đặt

npm install @libs-ui/components-pages-template-full-screen

Import

// V2 (khuyến dùng)
import { LibsUiComponentsPagesTemplateFullScreenV2Component } from '@libs-ui/components-pages-template-full-screen';

// V1 (deprecated — chỉ dùng khi maintain code cũ)
import { LibsUiComponentsPagesTemplateFullScreenComponent } from '@libs-ui/components-pages-template-full-screen';

// Types & Interfaces
import {
  IPagesTemplateFullScreenButton,
  IPagesTemplateFullScreenButtonKey,
  IFullScreenV2BodyConfig,
  IFullScreenV2SectionData,
  IFunctionControlPageFullScreen,
} from '@libs-ui/components-pages-template-full-screen';

Ví dụ sử dụng — V1 (cơ bản, dùng ng-content)

Ví dụ 1: Trang full screen đơn giản

import { ChangeDetectionStrategy, Component } from '@angular/core';
import {
  IPagesTemplateFullScreenButton,
  LibsUiComponentsPagesTemplateFullScreenComponent,
} from '@libs-ui/components-pages-template-full-screen';

@Component({
  selector: 'app-campaign-create',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [LibsUiComponentsPagesTemplateFullScreenComponent],
  template: `
    <libs_ui-components-pages_template_full_screen
      [title]="'Tạo chiến dịch Marketing'"
      [labelLeft]="'Hủy bỏ'"
      [buttonRight]="buttonRight"
      (outClose)="handlerClose()"
      (outClickButton)="handlerClickButton($event)">
      <div class="p-[24px]">
        <h2 class="libs-ui-font-h3s">Bước 1: Thông tin cơ bản</h2>
        <!-- Nội dung trang -->
      </div>
    </libs_ui-components-pages_template_full_screen>
  `,
})
export class AppCampaignCreateComponent {
  readonly buttonRight: IPagesTemplateFullScreenButton[] = [
    { key: 'button', label: 'Lưu nháp', type: 'button-secondary' },
    { key: 'button', label: 'Tiếp tục', type: 'button-primary' },
  ];

  handlerClose(): void {
    // event.stopPropagation() không cần thiết ở đây vì outClose không bubble DOM
    console.log('Đóng trang full screen');
  }

  handlerClickButton(button: IPagesTemplateFullScreenButton): void {
    if (button.label === 'Tiếp tục') {
      // Xử lý chuyển bước
    }
  }
}

Ví dụ 2: Header với switch, dropdown menu và edit icon

import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import {
  IPagesTemplateFullScreenButton,
  LibsUiComponentsPagesTemplateFullScreenComponent,
} from '@libs-ui/components-pages-template-full-screen';
import { IDropdown, IEmitSelectKey } from '@libs-ui/components-dropdown';

@Component({
  selector: 'app-report-editor',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [LibsUiComponentsPagesTemplateFullScreenComponent],
  template: `
    <libs_ui-components-pages_template_full_screen
      [title]="'Báo cáo doanh thu Q2/2026'"
      [hasEdit]="true"
      [buttonRight]="buttonRight"
      [menuDropDownConfigs]="menuConfig"
      [ignoreClosePageFullEvent]="true"
      (outClose)="handlerClose()"
      (outEdit)="handlerEdit()"
      (outClickButton)="handlerClickButton($event)"
      (outSelectedMenuDropdown)="handlerMenuSelect($event)">
      <div class="p-[24px]">
        <!-- Nội dung báo cáo -->
      </div>
    </libs_ui-components-pages_template_full_screen>
  `,
})
export class AppReportEditorComponent {
  readonly isPublished = signal(false);

  readonly buttonRight: IPagesTemplateFullScreenButton[] = [
    {
      key: 'switch',
      active: false,
      classInclude: 'mr-[8px]',
      action: async (event) => {
        this.isPublished.set(event?.state ?? false);
      },
    },
    { key: 'line-space' },
    { key: 'button', label: 'Xuất PDF', type: 'button-secondary' },
    { key: 'button', label: 'Lưu', type: 'button-primary' },
  ];

  readonly menuConfig: IDropdown = {
    listConfig: {
      type: 'text',
      httpRequestData: signal({
        objectInstance: {
          list: [
            { key: 'duplicate', label: 'Nhân bản' },
            { key: 'archive', label: 'Lưu trữ' },
            { key: 'delete', label: 'Xóa vĩnh viễn' },
          ],
        },
        functionName: 'list',
        argumentsValue: [],
      }),
      configTemplateText: signal({
        fieldKey: 'key',
        notUseVirtualScroll: true,
        getConfigButtonLeft: (item: { key: string; label: string }) => ({
          label: item.label,
          type: 'button-link-third',
          classLabel: 'libs-ui-font-h5r',
        }),
      }),
    },
  };

  handlerClose(): void {
    console.log('Đóng trang');
  }

  handlerEdit(): void {
    console.log('Mở chỉnh sửa tiêu đề');
  }

  handlerClickButton(button: IPagesTemplateFullScreenButton): void {
    console.log('Click button:', button.label);
  }

  handlerMenuSelect(event: IEmitSelectKey | undefined): void {
    console.log('Menu chọn:', event?.key);
  }
}

Ví dụ sử dụng — V2 (khuyến dùng, mở động qua DynamicComponentService)

Ví dụ 3: Mở full screen V2 từ TypeScript với lazy load body

import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';
import { from, of } from 'rxjs';
import {
  IFullScreenV2BodyConfig,
  IPagesTemplateFullScreenButton,
  LibsUiComponentsPagesTemplateFullScreenV2Component,
} from '@libs-ui/components-pages-template-full-screen';
import { ISkeletonConfig } from '@libs-ui/components-skeleton';
import { LibsUiDynamicComponentService, setInputs } from '@libs-ui/services-dynamic-component';

@Component({
  selector: 'app-order-list',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <button (click)="handlerOpenDetail()">Xem chi tiết đơn hàng</button>
  `,
})
export class AppOrderListComponent {
  private readonly dynamicService = inject(LibsUiDynamicComponentService);

  readonly skeletonConfig = signal<ISkeletonConfig>({
    repeat: 1,
    rows: [
      { item: { classInclude: 'w-full h-[56px] rounded-lg mb-[8px]' } },
      {
        cols: [
          { item: { classInclude: 'w-1/3 h-[80px] rounded-lg' } },
          { item: { classInclude: 'w-1/3 h-[80px] rounded-lg' } },
          { item: { classInclude: 'w-1/3 h-[80px] rounded-lg' } },
        ],
      },
      { item: { classInclude: 'w-full h-[64px] rounded-xl mt-[16px]' } },
    ],
  });

  readonly bodyConfig: IFullScreenV2BodyConfig = {
    getComponentOutlet: () =>
      from(import('./order-detail/order-detail.component').then((c) => c.OrderDetailComponent)),
    getDataComponentOutlet: (sectionData) =>
      of({ disable: sectionData.item.disable, orderId: 'OD-4521' }),
    skeletonConfig: this.skeletonConfig,
    classInclude: 'overflow-y-auto',
  };

  readonly buttonRight: IPagesTemplateFullScreenButton[] = [
    { key: 'button', label: 'In hóa đơn', type: 'button-secondary' },
    { key: 'button', label: 'Xác nhận giao', type: 'button-primary' },
  ];

  handlerOpenDetail(): void {
    const fullScreenRef = this.dynamicService.resolveComponentFactory(
      LibsUiComponentsPagesTemplateFullScreenV2Component,
    );

    setInputs(fullScreenRef, {
      title: 'Chi tiết đơn hàng #OD-4521',
      labelLeft: 'Quay lại',
      buttonRight: this.buttonRight,
      bodyConfig: this.bodyConfig,
      zIndex: 9999,
    });

    fullScreenRef.instance.outClose.subscribe(() => {
      this.dynamicService.delete(fullScreenRef);
    });

    document.getElementsByTagName('main')?.[0]?.classList.add('relative');
    this.dynamicService.addToElement(fullScreenRef, document.getElementsByTagName('main')?.[0]);
  }
}

Ví dụ 4: Sử dụng FunctionsControl để đóng page từ component con

// Trong parent component — lưu ref để gọi FunctionsControl
import { ComponentRef } from '@angular/core';
import { LibsUiComponentsPagesTemplateFullScreenV2Component } from '@libs-ui/components-pages-template-full-screen';

// Khai báo ở cấp class (không phải const trong hàm)
private fullScreenRef: ComponentRef<LibsUiComponentsPagesTemplateFullScreenV2Component> | undefined;

handlerOpen(): void {
  this.fullScreenRef = this.dynamicService.resolveComponentFactory(
    LibsUiComponentsPagesTemplateFullScreenV2Component,
  );

  // Lấy FunctionsControl sau khi có ref
  const fc = this.fullScreenRef.instance.FunctionsControl;

  setInputs(this.fullScreenRef, {
    title: 'Quy trình phê duyệt',
    bodyConfig: {
      getComponentOutlet: () =>
        from(import('./approval-form.component').then((c) => c.ApprovalFormComponent)),
      getDataComponentOutlet: () =>
        of({ onClose: () => fc.emitClosePageFullEvent() }),
    },
  });

  this.fullScreenRef.instance.outClose.subscribe(() => {
    this.dynamicService.delete(this.fullScreenRef!);
    this.fullScreenRef = undefined;
  });

  this.dynamicService.addToElement(this.fullScreenRef, document.body);
}

ngOnDestroy(): void {
  if (this.fullScreenRef) {
    this.dynamicService.delete(this.fullScreenRef);
  }
}

Ví dụ 5: Tùy chỉnh phân vùng header với TemplateRef

import { ChangeDetectionStrategy, Component, TemplateRef, viewChild } from '@angular/core';
import { LibsUiComponentsPagesTemplateFullScreenComponent } from '@libs-ui/components-pages-template-full-screen';

@Component({
  selector: 'app-editor',
  standalone: true,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [LibsUiComponentsPagesTemplateFullScreenComponent],
  template: `
    <ng-template #customCenter>
      <div class="flex items-center gap-[8px]">
        <span class="libs-ui-font-h3s libs-ui-color-primary">Soạn thảo nội dung</span>
        <span class="libs-ui-badge-status-success">Đang lưu...</span>
      </div>
    </ng-template>

    <libs_ui-components-pages_template_full_screen
      [centerTemplate]="customCenter"
      [buttonRight]="[{ key: 'button', label: 'Xuất bản', type: 'button-primary' }]"
      (outClose)="handlerClose()"
      (outClickButton)="handlerClickButton($event)">
      <div class="p-[24px]">Nội dung editor...</div>
    </libs_ui-components-pages_template_full_screen>
  `,
})
export class AppEditorComponent {
  handlerClose(): void {
    console.log('Đóng editor');
  }

  handlerClickButton(): void {
    console.log('Xuất bản');
  }
}

@Input() — V1 (libs_ui-components-pages_template_full_screen)

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | [title] | string | undefined | Tiêu đề hiển thị ở giữa header, tự động escape HTML | [title]="'Cấu hình chiến dịch'" | | [labelLeft] | string | 'i18n_back_to_list' | Nhãn nút quay lại bên trái header | [labelLeft]="'Hủy bỏ'" | | [buttonCenter] | IPagesTemplateFullScreenButton[] | undefined | Danh sách button/switch/label hiển thị ở giữa header (cạnh title) | [buttonCenter]="centerButtons" | | [buttonRight] | IPagesTemplateFullScreenButton[] | undefined | Danh sách button/switch/label/line-space ở bên phải header | [buttonRight]="rightButtons" | | [hasEdit] | boolean | false | Hiển thị icon chỉnh sửa cạnh tiêu đề, phát outEdit khi click | [hasEdit]="true" | | [menuDropDownConfigs] | IDropdown | undefined | Cấu hình menu dropdown "ba chấm dọc" ở góc phải header | [menuDropDownConfigs]="menuConfig" | | [zIndex] | number | 1000 | CSS z-index của toàn bộ overlay | [zIndex]="9999" | | [ignoreClosePageFullEvent] | boolean | false | Nếu true, không gửi PostMessage open/close tới app cha | [ignoreClosePageFullEvent]="true" | | [ignoreBackgroundColor] | boolean | undefined | Nếu true, nền trong suốt thay vì màu mặc định #f2f5f7 | [ignoreBackgroundColor]="true" | | [disable] | boolean | false | Vô hiệu hóa toàn bộ action trên header (button, switch) | [disable]="isLoading()" | | [classHeaderInclude] | string | undefined | Class bổ sung cho phần tử header | [classHeaderInclude]="'border-b'" | | [classBodyInclude] | string | undefined | Class bổ sung cho phần body | [classBodyInclude]="'p-[24px]'" | | [leftTemplate] | TemplateRef<any> | undefined | Template tùy chỉnh thay thế toàn bộ vùng trái header (bao gồm nút Back) | [leftTemplate]="leftTpl" | | [centerTemplate] | TemplateRef<any> | undefined | Template tùy chỉnh thay thế vùng giữa header (bao gồm title + buttonCenter) | [centerTemplate]="centerTpl" | | [templateRight] | TemplateRef<any> | undefined | Template bổ sung vào sau danh sách buttonRight ở vùng phải header | [templateRight]="rightTpl" | | [divideClassHeader] | { classButtonCancel: string; classButtonCenter: string; classButtonRight: string } | undefined | Override class width cho 3 vùng header (mặc định: 25% / 40% / 35%) | [divideClassHeader]="{ classButtonCancel: 'w-[20%]', classButtonCenter: 'w-[50%]', classButtonRight: 'w-[30%]' }" |


@Input() — V2 (libs_ui-components-pages_template_full_screen_v2)

V2 kế thừa toàn bộ inputs của V1, bổ sung thêm:

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | [bodyConfig] | IFullScreenV2BodyConfig | {} | Cấu hình lazy load component vào body. Nếu không truyền getComponentOutlet thì body render bằng ng-content như V1 | [bodyConfig]="bodyConfig" |


@Output()

Cả V1 và V2 đều có chung các outputs sau:

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outClose) | void | Phát ra khi click nút quay lại / đóng ở vùng trái header | handlerClose(): void { /* xử lý đóng */ } | (outClose)="handlerClose()" | | (outEdit) | void | Phát ra khi click icon edit cạnh tiêu đề (chỉ khi [hasEdit]="true") | handlerEdit(): void { /* mở form chỉnh sửa tiêu đề */ } | (outEdit)="handlerEdit()" | | (outClickButton) | IPagesTemplateFullScreenButton | Phát ra khi click bất kỳ button nào trong buttonCenter hoặc buttonRightkey: 'button' | handlerClickButton(button: IPagesTemplateFullScreenButton): void { event.stopPropagation(); /* xử lý theo button.label */ } | (outClickButton)="handlerClickButton($event)" | | (outSelectedMenuDropdown) | IEmitSelectKey \| undefined | Phát ra khi chọn item trong menu dropdown (ba chấm dọc) | handlerMenuSelect(event: IEmitSelectKey \| undefined): void { event.stopPropagation ? event.stopPropagation() : null; /* xử lý theo event.key */ } | (outSelectedMenuDropdown)="handlerMenuSelect($event)" |


FunctionsControl (V2 only)

LibsUiComponentsPagesTemplateFullScreenV2Component expose getter FunctionsControl để component con hoặc service bên ngoài có thể điều khiển trang:

import { ComponentRef } from '@angular/core';
import {
  IFunctionControlPageFullScreen,
  LibsUiComponentsPagesTemplateFullScreenV2Component,
} from '@libs-ui/components-pages-template-full-screen';

// Lấy FunctionsControl từ ComponentRef
const fc: IFunctionControlPageFullScreen = fullScreenRef.instance.FunctionsControl;

// Gửi sự kiện đóng trang (PostMessage 'close') tới app cha
fc.emitClosePageFullEvent();

| Method | Signature | Mô tả | |---|---|---| | emitClosePageFullEvent | () => void | Gửi PostMessage với message: 'close' tới ứng dụng cha qua UtilsCommunicateMicro. Thường dùng khi component con muốn chủ động đóng page mà không thông qua (outClose). |


Types & Interfaces

import {
  IPagesTemplateFullScreenButton,
  IPagesTemplateFullScreenButtonKey,
  IFullScreenV2BodyConfig,
  IFullScreenV2SectionData,
  IFunctionControlPageFullScreen,
} from '@libs-ui/components-pages-template-full-screen';

// Loại button có thể dùng trong buttonCenter và buttonRight
export type IPagesTemplateFullScreenButtonKey =
  | 'button'          // Nút bấm thông thường
  | 'button-status'   // Nút hiển thị trạng thái (không click)
  | 'switch'          // Toggle switch
  | 'label'           // Label text
  | 'line-space'      // Đường kẻ phân cách dọc
  | 'button-dropdown';// Nút dropdown

// Cấu hình mỗi button trong header
export interface IPagesTemplateFullScreenButton extends IButton {
  key: IPagesTemplateFullScreenButtonKey;
  classInclude?: string;
  disable?: boolean;
  // Async callback khi click — dùng cho switch (nhận ISwitchEvent) hoặc button
  action?: (event?: ISwitchEvent) => Promise<void>;
  configButtonStatus?: IButtonStatus; // Chỉ dùng khi key = 'button-status'
  active?: boolean;                   // Trạng thái ban đầu của switch
  labelConfig?: ILabel;               // Chỉ dùng khi key = 'label'
}

// Cấu hình body cho V2
export interface IFullScreenV2BodyConfig {
  // Hàm trả về Observable<Type<any>> — lazy load component vào body
  getComponentOutlet?: TYPE_FUNCTION<any>;
  // Hàm trả về Observable<Record> — truyền inputs vào component được load
  // Nhận sectionData (chứa { disable: boolean }) làm tham số
  getDataComponentOutlet?: TYPE_FUNCTION<Record<string, unknown>>;
  // Custom skeleton (bắt buộc là WritableSignal để reactive)
  skeletonConfig?: WritableSignal<ISkeletonConfig>;
  // Class bổ sung vào wrapper của vùng body
  classInclude?: string;
}

// Data được truyền tự động vào component outlet (qua sectionData)
export interface IFullScreenV2SectionData {
  disable: boolean;
}

// API điều khiển nội bộ
export interface IFunctionControlPageFullScreen {
  emitClosePageFullEvent: () => void;
}

Lưu ý quan trọng

⚠️ V1 đã deprecated: LibsUiComponentsPagesTemplateFullScreenComponent có annotation @deprecated. Chỉ dùng để maintain code cũ. Code mới bắt buộc dùng V2.

⚠️ PostMessage lifecycle: Mặc định cả V1 và V2 đều gửi PostMessage với message: 'open' khi ngOnInitmessage: 'close' khi ngOnDestroy tới ứng dụng cha. Nếu không cần hành vi này (ví dụ: dùng trong iframe độc lập hoặc demo), hãy set [ignoreClosePageFullEvent]="true".

⚠️ Ping định kỳ 2 giây: Nếu IGNORE_INTERVAL_UPDATE_TIME_LIVE_EVENT_MODALfalse, component gửi ping PostMessage mỗi 2 giây để báo cho app cha rằng user đang hoạt động. V2 dùng takeUntilDestroyed nên tự cleanup; V1 dùng Subject + takeUntil.

⚠️ ComponentRef phải là class property: Khi dùng dynamicService.resolveComponentFactory(), BẮT BUỘC lưu kết quả vào biến class (không phải const trong hàm) để có thể delete khi component cha bị destroy. Quên xóa sẽ gây memory leak.

⚠️ skeletonConfig phải là WritableSignal: Trường bodyConfig.skeletonConfig bắt buộc là signal<ISkeletonConfig>(...) (không phải plain object) để skeleton cập nhật reactive.

⚠️ getDataComponentOutlet nhận sectionData: Hàm getDataComponentOutlet nhận tham số { item: IFullScreenV2SectionData } (wrapper) — truy cập sectionData.item.disable để lấy trạng thái disable. Xem ví dụ 3 ở trên.

⚠️ Body layout: Khi không truyền bodyConfig.getComponentOutlet, V2 không render gì ở body (không có ng-content như V1). Nếu cần ng-content, dùng V1 hoặc luôn truyền getComponentOutlet.


Demo

npx nx serve core-ui

Truy cập:

  • V1: http://localhost:4500/page-template/full-screen
  • V2: http://localhost:4500/page-template/full-screen-v2