diff --git a/packages/primeng/src/accordion/accordion.ts b/packages/primeng/src/accordion/accordion.ts index dd1ec973e70..195c1ed8859 100755 --- a/packages/primeng/src/accordion/accordion.ts +++ b/packages/primeng/src/accordion/accordion.ts @@ -27,7 +27,7 @@ import { ViewEncapsulation } from '@angular/core'; import { findSingle, focus, getAttribute, uuid } from '@primeuix/utils'; -import { BlockableUI, Header, SharedModule } from 'primeng/api'; +import { BlockableUI, Header, PrimeTemplate, SharedModule } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { ChevronDownIcon, ChevronUpIcon } from 'primeng/icons'; import { Ripple } from 'primeng/ripple'; @@ -120,7 +120,7 @@ export class AccordionPanel extends BaseComponent { */ @Component({ selector: 'p-accordion-header, p-accordionheader', - imports: [CommonModule, ChevronDownIcon, ChevronUpIcon, Ripple], + imports: [CommonModule, ChevronDownIcon, ChevronUpIcon], standalone: true, template: ` @@ -358,18 +358,18 @@ export class AccordionContent extends BaseComponent { [attr.id]="getTabHeaderActionId(id)" [attr.aria-controls]="getTabContentId(id)" > - @if (!headerTemplate) { + @if (!headerTemplate && !_headerTemplate) { {{ header }} } @else { - @if (headerTemplate) { - + @if (headerTemplate || _headerTemplate) { + } @if (headerFacet) { } } - @if (iconTemplate) { - + @if (iconTemplate || _iconTemplate) { + } @else { @@ -392,8 +392,8 @@ export class AccordionContent extends BaseComponent { >
- - + +
@@ -539,22 +539,25 @@ export class AccordionTab extends BaseComponent implements AfterContentInit, OnD * Content template for the content of the drawer. * @group Templates */ - @ContentChild('header') headerTemplate: TemplateRef | undefined; - /** - * Header template for the header of the drawer. - * @group Templates - */ - @ContentChild('footer') footerTemplate: TemplateRef | undefined; + @ContentChild('header', { descendants: false }) headerTemplate: TemplateRef | undefined; /** * Template for the header icon. * @group Templates */ - @ContentChild('icon') iconTemplate: TemplateRef | undefined; + @ContentChild('icon', { descendants: false }) iconTemplate: TemplateRef | undefined; /** * Content template for the footer of the drawer. * @group Templates */ - @ContentChild('content') contentTemplate: TemplateRef | undefined; + @ContentChild('content', { descendants: false }) contentTemplate: TemplateRef | undefined; + + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + _headerTemplate: TemplateRef; + + _iconTemplate: TemplateRef; + + _contentTemplate: TemplateRef; loaded: boolean = false; @@ -567,6 +570,28 @@ export class AccordionTab extends BaseComponent implements AfterContentInit, OnD console.log('AccordionTab is deprecated as of v18, please use the new structure instead.'); } + ngAfterContentInit() { + this.templates.forEach((item) => { + switch (item.getType()) { + case 'content': + this._contentTemplate = item.template; + break; + + case 'header': + this._headerTemplate = item.template; + break; + + case 'icon': + this._iconTemplate = item.template; + break; + + default: + this._contentTemplate = item.template; + break; + } + }); + } + toggle(event?: MouseEvent | KeyboardEvent) { if (this.disabled) { return false; @@ -645,7 +670,7 @@ export class AccordionTab extends BaseComponent implements AfterContentInit, OnD @Component({ selector: 'p-accordion', standalone: true, - imports: [CommonModule, AccordionTab, SharedModule], + imports: [CommonModule, SharedModule], template: ` `, host: { '[class.p-accordion]': 'true', @@ -889,7 +914,6 @@ export class Accordion extends BaseComponent implements BlockableUI, AfterConten } ngAfterContentInit() { - super.ngAfterContentInit(); this.initTabs(); this.tabListSubscription = (this.tabList as QueryList).changes.subscribe((_) => { diff --git a/packages/primeng/src/autocomplete/autocomplete.ts b/packages/primeng/src/autocomplete/autocomplete.ts index f4752f27e3a..537302115d2 100755 --- a/packages/primeng/src/autocomplete/autocomplete.ts +++ b/packages/primeng/src/autocomplete/autocomplete.ts @@ -8,6 +8,7 @@ import { Component, computed, ContentChild, + ContentChildren, effect, ElementRef, EventEmitter, @@ -19,6 +20,7 @@ import { numberAttribute, OnDestroy, Output, + QueryList, signal, TemplateRef, ViewChild, @@ -26,7 +28,7 @@ import { } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { equals, findLastIndex, findSingle, focus, isEmpty, isNotEmpty, resolveFieldData, uuid } from '@primeuix/utils'; -import { OverlayOptions, OverlayService, ScrollerOptions, SharedModule, TranslationKeys } from 'primeng/api'; +import { OverlayOptions, OverlayService, PrimeTemplate, ScrollerOptions, SharedModule, TranslationKeys } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { BaseComponent } from 'primeng/basecomponent'; import { Chip } from 'primeng/chip'; @@ -95,9 +97,9 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = { [fluid]="hasFluid()" /> - - - + + + @@ -124,9 +126,9 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = { [attr.aria-posinset]="i + 1" [attr.aria-selected]="true" > - - - + + + @@ -134,8 +136,8 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = { - - + +
  • @@ -174,16 +176,16 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = {
  • - - - + + +
    - +
    - + - + @@ -251,10 +253,10 @@ export const AUTOCOMPLETE_VALUE_ACCESSOR: any = { (click)="onOptionSelect($event, option)" (mouseenter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))" > - {{ getOptionLabel(option) }} + {{ getOptionLabel(option) }} - + {{ searchResultMessageText }} - + - +
    {{ selectedMessageText }} @@ -749,7 +751,7 @@ export class AutoComplete extends BaseComponent implements AfterViewChecked, Aft * Custom selected item template. * @group Templates */ - @ContentChild('selecteditem') selecteditemTemplate: Nullable>; + @ContentChild('selecteditem') selectedItemTemplate: Nullable>; /** * Custom group item template. @@ -767,25 +769,25 @@ export class AutoComplete extends BaseComponent implements AfterViewChecked, Aft * Custom remove icon template. * @group Templates */ - @ContentChild('removeicon') removeiconTemplate: Nullable>; + @ContentChild('removeicon') removeIconTemplate: Nullable>; /** * Custom loading icon template. * @group Templates */ - @ContentChild('loadingicon') loadingiconTemplate: Nullable>; + @ContentChild('loadingicon') loadingIconTemplate: Nullable>; /** * Custom clear icon template. * @group Templates */ - @ContentChild('clearicon') cleariconTemplate: Nullable>; + @ContentChild('clearicon') clearIconTemplate: Nullable>; /** * Custom dropdown icon template. * @group Templates */ - @ContentChild('dropdownicon') dropdowniconTemplate: Nullable>; + @ContentChild('dropdownicon') dropdownIconTemplate: Nullable>; private primeng = inject(PrimeNG); @@ -828,6 +830,28 @@ export class AutoComplete extends BaseComponent implements AfterViewChecked, Aft dirty: boolean = false; + _itemTemplate: TemplateRef; + + _groupTemplate: TemplateRef; + + _selectedItemTemplate: TemplateRef; + + _headerTemplate: TemplateRef; + + _emptyTemplate: TemplateRef; + + _footerTemplate: TemplateRef; + + _loaderTemplate: TemplateRef; + + _removeIconTemplate: TemplateRef; + + _loadingIconTemplate: TemplateRef; + + _clearIconTemplate: TemplateRef; + + _dropdownIconTemplate: TemplateRef; + modelValue = signal(null); focusedMultipleOptionIndex = signal(-1); @@ -957,6 +981,66 @@ export class AutoComplete extends BaseComponent implements AfterViewChecked, Aft this.cd.detectChanges(); } + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + ngAfterContentInit() { + (this.templates as QueryList).forEach((item) => { + switch (item.getType()) { + case 'item': + this._itemTemplate = item.template; + break; + + case 'group': + this._groupTemplate = item.template; + break; + + case 'selecteditem': + this._selectedItemTemplate = item.template; + break; + + case 'selectedItem': + this._selectedItemTemplate = item.template; + break; + + case 'header': + this._headerTemplate = item.template; + break; + + case 'empty': + this._emptyTemplate = item.template; + break; + + case 'footer': + this._footerTemplate = item.template; + break; + + case 'loader': + this._loaderTemplate = item.template; + break; + + case 'removetokenicon': + this._removeIconTemplate = item.template; + break; + + case 'loadingicon': + this._loadingIconTemplate = item.template; + break; + + case 'clearicon': + this._clearIconTemplate = item.template; + break; + + case 'dropdownicon': + this._dropdownIconTemplate = item.template; + break; + + default: + this._itemTemplate = item.template; + break; + } + }); + } + ngAfterViewChecked() { //Use timeouts as since Angular 4.2, AfterViewChecked is broken and not called after panel is updated if (this.suggestionsUpdated && this.overlayViewChild) { diff --git a/packages/primeng/src/basecomponent/basecomponent.ts b/packages/primeng/src/basecomponent/basecomponent.ts index 8e210710c1d..145b0a9ee2b 100644 --- a/packages/primeng/src/basecomponent/basecomponent.ts +++ b/packages/primeng/src/basecomponent/basecomponent.ts @@ -70,25 +70,6 @@ export class BaseComponent { } } - @ContentChildren(PrimeTemplate) templates: QueryList | undefined; - - ngAfterContentInit() { - this.templates?.forEach((item) => { - const type = item.getType(); - const template = `${type}Template`; - - if (this.hasOwnProperty(template)) { - this[template] = item.template; - } - - if (this.hasOwnProperty(`_${template}`)) { - this[`_${template}`] = item.template; - } - - this[type] = item.template; - }); - } - ngOnChanges(changes: SimpleChanges) { if (this.document && !isPlatformServer(this.platformId)) { const { dt } = changes; diff --git a/packages/primeng/src/blockui/blockui.ts b/packages/primeng/src/blockui/blockui.ts index 67289a1aa70..049ec1bf755 100755 --- a/packages/primeng/src/blockui/blockui.ts +++ b/packages/primeng/src/blockui/blockui.ts @@ -1,7 +1,25 @@ import { CommonModule, isPlatformBrowser } from '@angular/common'; -import { AfterViewInit, booleanAttribute, ChangeDetectionStrategy, Component, ContentChild, ElementRef, inject, Input, NgModule, numberAttribute, OnDestroy, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + AfterContentInit, + AfterViewInit, + booleanAttribute, + ChangeDetectionStrategy, + Component, + ContentChild, + ContentChildren, + ElementRef, + inject, + Input, + NgModule, + numberAttribute, + OnDestroy, + QueryList, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; import { addClass, blockBodyScroll, removeClass, unblockBodyScroll } from '@primeuix/utils'; -import { SharedModule } from 'primeng/api'; +import { PrimeTemplate, SharedModule } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { ZIndexUtils } from 'primeng/utils'; import { BlockUiStyle } from './style/blockuistyle'; @@ -25,14 +43,14 @@ import { BlockUiStyle } from './style/blockuistyle'; [attr.data-pc-section]="'root'" > - +
    `, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [BlockUiStyle] }) -export class BlockUI extends BaseComponent implements AfterViewInit, OnDestroy { +export class BlockUI extends BaseComponent implements AfterViewInit, AfterContentInit, OnDestroy { /** * Name of the local ng-template variable referring to another component. * @group Props @@ -72,7 +90,7 @@ export class BlockUI extends BaseComponent implements AfterViewInit, OnDestroy { * template of the content * @group Templates */ - @ContentChild('content') content: TemplateRef | undefined; + @ContentChild('content', { descendants: false }) contentTemplate: TemplateRef | undefined; @ViewChild('mask') mask: ElementRef | undefined; @@ -95,6 +113,24 @@ export class BlockUI extends BaseComponent implements AfterViewInit, OnDestroy { } } + _contentTemplate: TemplateRef | undefined; + + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + ngAfterContentInit() { + (this.templates as QueryList).forEach((item) => { + switch (item.getType()) { + case 'content': + this.contentTemplate = item.template; + break; + + default: + this.contentTemplate = item.template; + break; + } + }); + } + block() { if (isPlatformBrowser(this.platformId)) { this._blocked = true; @@ -150,7 +186,7 @@ export class BlockUI extends BaseComponent implements AfterViewInit, OnDestroy { } @NgModule({ - imports: [BlockUI], + imports: [BlockUI, SharedModule], exports: [BlockUI, SharedModule] }) export class BlockUIModule {} diff --git a/packages/primeng/src/breadcrumb/breadcrumb.ts b/packages/primeng/src/breadcrumb/breadcrumb.ts index 1018d30f196..efec2c9a0cb 100755 --- a/packages/primeng/src/breadcrumb/breadcrumb.ts +++ b/packages/primeng/src/breadcrumb/breadcrumb.ts @@ -1,7 +1,7 @@ import { CommonModule } from '@angular/common'; -import { AfterContentInit, ChangeDetectionStrategy, Component, ContentChild, EventEmitter, inject, Input, NgModule, Output, TemplateRef, ViewEncapsulation } from '@angular/core'; +import { AfterContentInit, ChangeDetectionStrategy, Component, ContentChild, ContentChildren, EventEmitter, inject, Input, NgModule, Output, QueryList, TemplateRef, ViewEncapsulation } from '@angular/core'; import { Router, RouterModule } from '@angular/router'; -import { MenuItem, SharedModule } from 'primeng/api'; +import { MenuItem, PrimeTemplate, SharedModule } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { ChevronRightIcon, HomeIcon } from 'primeng/icons'; import { TooltipModule } from 'primeng/tooltip'; @@ -73,8 +73,8 @@ import { BreadCrumbStyle } from './style/breadcrumbstyle';
  • - - + +
  • - @if (item) { - + @if (itemTemplate || _itemTemplate) { + } @else { - + {{ menuitem?.label }} @@ -112,7 +112,7 @@ import { BreadCrumbStyle } from './style/breadcrumbstyle'; [queryParams]="menuitem?.queryParams" [routerLinkActiveOptions]="menuitem?.routerLinkActiveOptions || { exact: false }" class="p-breadcrumb-item-link" - (click)="onClick($event, item)" + (click)="onClick($event, menuitem)" [target]="menuitem?.target" [attr.title]="menuitem?.title" [attr.tabindex]="menuitem?.disabled ? null : '0'" @@ -132,8 +132,8 @@ import { BreadCrumbStyle } from './style/breadcrumbstyle'; }
  • - - + +
  • @@ -205,23 +205,41 @@ export class Breadcrumb extends BaseComponent implements AfterContentInit { }); } - onHomeClick(event: MouseEvent | any) { - if (this.home) { - this.onClick(event, this.home); - } - } - /** * Defines template option for item. * @group Templates */ - @ContentChild('item') item: TemplateRef | undefined; + @ContentChild('item') itemTemplate: TemplateRef | undefined; /** * Defines template option for separator. * @group Templates */ - @ContentChild('separator') separator: TemplateRef | undefined; + @ContentChild('separator') separatorTemplate: TemplateRef | undefined; + + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + _separatorTemplate: TemplateRef | undefined; + + _itemTemplate: TemplateRef | undefined; + + ngAfterContentInit() { + this.templates?.forEach((item) => { + switch (item.getType()) { + case 'separator': + this._separatorTemplate = item.template; + break; + + case 'item': + this._itemTemplate = item.template; + break; + + default: + this._itemTemplate = item.template; + break; + } + }); + } } @NgModule({ diff --git a/packages/primeng/src/button/button.ts b/packages/primeng/src/button/button.ts index 249e6d4e682..9d6378d7187 100755 --- a/packages/primeng/src/button/button.ts +++ b/packages/primeng/src/button/button.ts @@ -8,6 +8,7 @@ import { computed, contentChild, ContentChild, + ContentChildren, Directive, EventEmitter, inject, @@ -16,12 +17,13 @@ import { numberAttribute, OnDestroy, Output, + QueryList, SimpleChanges, TemplateRef, ViewEncapsulation } from '@angular/core'; import { addClass, findSingle, isEmpty } from '@primeuix/utils'; -import { SharedModule } from 'primeng/api'; +import { PrimeTemplate, SharedModule } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { BadgeModule } from 'primeng/badge'; import { BaseComponent } from 'primeng/basecomponent'; @@ -446,20 +448,20 @@ export class ButtonDirective extends BaseComponent implements AfterViewInit, OnD [pAutoFocus]="autofocus" > - + - + - + - - + + - {{ label }} - + {{ label }} + `, changeDetection: ChangeDetectionStrategy.OnPush, @@ -620,12 +622,12 @@ export class Button extends BaseComponent implements AfterContentInit { * Template of the content. * @group Templates **/ - @ContentChild('content') content: TemplateRef | undefined; + @ContentChild('content') contentTemplate: TemplateRef | undefined; /** * Template of the loading. * @group Templates **/ - @ContentChild('loading') loadingicon: TemplateRef | undefined; + @ContentChild('loading') loadingIconTemplate: TemplateRef | undefined; /** * Template of the icon. * @group Templates @@ -658,6 +660,36 @@ export class Button extends BaseComponent implements AfterContentInit { _componentStyle = inject(ButtonStyle); + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + _contentTemplate: TemplateRef | undefined; + + _iconTemplate: TemplateRef | undefined; + + _loadingIconTemplate: TemplateRef | undefined; + + ngAfterContentInit() { + this.templates?.forEach((item) => { + switch (item.getType()) { + case 'content': + this.contentTemplate = item.template; + break; + + case 'icon': + this.iconTemplate = item.template; + break; + + case 'loadingicon': + this.loadingIconTemplate = item.template; + break; + + default: + this.contentTemplate = item.template; + break; + } + }); + } + ngOnChanges(simpleChanges: SimpleChanges) { super.ngOnChanges(simpleChanges); const { buttonProps } = simpleChanges; @@ -691,7 +723,7 @@ export class Button extends BaseComponent implements AfterContentInit { get buttonClass() { return { 'p-button p-component': true, - 'p-button-icon-only': (this.icon || this.iconTemplate || this.loadingIcon || this.loadingicon) && !this.label, + 'p-button-icon-only': (this.icon || this.iconTemplate || this.loadingIcon || this.loadingIconTemplate || this._loadingIconTemplate) && !this.label, 'p-button-vertical': (this.iconPos === 'top' || this.iconPos === 'bottom') && this.label, 'p-button-loading': this.loading, 'p-button-loading-label-only': this.loading && !this.icon && this.label && !this.loadingIcon && this.iconPos === 'left', diff --git a/packages/primeng/src/calendar/calendar.ts b/packages/primeng/src/calendar/calendar.ts index 4f96a8bc66c..7966d208f7f 100644 --- a/packages/primeng/src/calendar/calendar.ts +++ b/packages/primeng/src/calendar/calendar.ts @@ -1,10 +1,12 @@ import { animate, AnimationEvent, state, style, transition, trigger } from '@angular/animations'; import { CommonModule } from '@angular/common'; import { + AfterContentInit, booleanAttribute, ChangeDetectionStrategy, Component, ContentChild, + ContentChildren, ElementRef, EventEmitter, forwardRef, @@ -16,6 +18,7 @@ import { OnDestroy, OnInit, Output, + QueryList, TemplateRef, ViewChild, ViewEncapsulation @@ -40,7 +43,7 @@ import { unblockBodyScroll, uuid } from '@primeuix/utils'; -import { OverlayService, SharedModule, TranslationKeys } from 'primeng/api'; +import { OverlayService, PrimeTemplate, SharedModule, TranslationKeys } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { BaseComponent } from 'primeng/basecomponent'; import { Button } from 'primeng/button'; @@ -105,9 +108,9 @@ export const CALENDAR_VALUE_ACCESSOR: any = { [fluid]="hasFluid" /> - - - + + + - +
    @@ -162,7 +165,7 @@ export const CALENDAR_VALUE_ACCESSOR: any = { *ngIf="inline || overlayVisible" > - +
    @@ -178,9 +181,9 @@ export const CALENDAR_VALUE_ACCESSOR: any = { type="button" [attr.aria-label]="prevIconAriaLabel" > - - - + + +
    @@ -209,8 +212,8 @@ export const CALENDAR_VALUE_ACCESSOR: any = { {{ getYear(month) }} - {{ yearPickerValues()[0] }} - {{ yearPickerValues()[yearPickerValues().length - 1] }} - + {{ yearPickerValues()[0] }} - {{ yearPickerValues()[yearPickerValues().length - 1] }} +
    - + - - + +
    @@ -266,12 +269,12 @@ export const CALENDAR_VALUE_ACCESSOR: any = { (keydown)="onDateCellKeydown($event, date, i)" pRipple > - {{ date.day }} - - + {{ date.day }} + + - +
    @@ -338,9 +341,9 @@ export const CALENDAR_VALUE_ACCESSOR: any = { (mouseleave)="onTimePickerElementMouseLeave()" [attr.aria-label]="getTranslation('nextHour')" > - + - + 0{{ currentHour }} - + - +
    @@ -382,9 +385,9 @@ export const CALENDAR_VALUE_ACCESSOR: any = { (mouseleave)="onTimePickerElementMouseLeave()" [attr.aria-label]="getTranslation('nextMinute')" > - + - + 0{{ currentMinute }} - - - + + +
    @@ -427,9 +430,9 @@ export const CALENDAR_VALUE_ACCESSOR: any = { (mouseleave)="onTimePickerElementMouseLeave()" [attr.aria-label]="getTranslation('nextSecond')" > - + - + 0{{ currentSecond }} - + - +
    @@ -466,8 +469,8 @@ export const CALENDAR_VALUE_ACCESSOR: any = { (keydown.enter)="toggleAMPM($event)" [attr.aria-label]="getTranslation('am')" > - - + + {{ pm ? 'PM' : 'AM' }} - - + +
    @@ -490,7 +493,7 @@ export const CALENDAR_VALUE_ACCESSOR: any = { - +
    `, @@ -521,7 +524,7 @@ export const CALENDAR_VALUE_ACCESSOR: any = { changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None }) -export class Calendar extends BaseComponent implements OnInit, OnDestroy, ControlValueAccessor { +export class Calendar extends BaseComponent implements OnInit, AfterContentInit, OnDestroy, ControlValueAccessor { @Input() iconDisplay: 'input' | 'button' = 'button'; /** * Inline style of the component. @@ -1045,73 +1048,73 @@ export class Calendar extends BaseComponent implements OnInit, OnDestroy, Contro * Custom template for date cells. * @group Templates */ - @ContentChild('date') dateTemplate: Nullable>; + @ContentChild('date', { descendants: false }) dateTemplate: Nullable>; /** * Custom template for header section. * @group Templates */ - @ContentChild('header') header: Nullable>; + @ContentChild('header', { descendants: false }) headerTemplate: Nullable>; /** * Custom template for footer section. * @group Templates */ - @ContentChild('footer') footer: Nullable>; + @ContentChild('footer', { descendants: false }) footerTemplate: Nullable>; /** * Custom template for disabled date cells. * @group Templates */ - @ContentChild('disabledDate') disabledDate: Nullable>; + @ContentChild('disabledDate', { descendants: false }) disabledDateTemplate: Nullable>; /** * Custom template for decade view. * @group Templates */ - @ContentChild('decade') decade: Nullable>; + @ContentChild('decade', { descendants: false }) decadeTemplate: Nullable>; /** * Custom template for previous month icon. * @group Templates */ - @ContentChild('previousicon') previousicon: Nullable>; + @ContentChild('previousicon', { descendants: false }) previousIconTemplate: Nullable>; /** * Custom template for next month icon. * @group Templates */ - @ContentChild('nexticon') nexticon: Nullable>; + @ContentChild('nexticon', { descendants: false }) nextIconTemplate: Nullable>; /** * Custom template for trigger icon. * @group Templates */ - @ContentChild('triggericon') triggericon: Nullable>; + @ContentChild('triggericon', { descendants: false }) triggerIconTemplate: Nullable>; /** * Custom template for clear icon. * @group Templates */ - @ContentChild('clearicon') clearicon: Nullable>; + @ContentChild('clearicon', { descendants: false }) clearIconTemplate: Nullable>; /** * Custom template for decrement icon. * @group Templates */ - @ContentChild('decrementicon') decrementicon: Nullable>; + @ContentChild('decrementicon', { descendants: false }) decrementIconTemplate: Nullable>; /** * Custom template for increment icon. * @group Templates */ - @ContentChild('incrementicon') incrementicon: Nullable>; + @ContentChild('incrementicon', { descendants: false }) incrementIconTemplate: Nullable>; /** * Custom template for input icon. * @group Templates */ - @ContentChild('inputicon') inputicon: Nullable>; + @ContentChild('inputicon', { descendants: false }) inputIconTemplate: Nullable>; @ViewChild('container', { static: false }) containerViewChild: Nullable; @@ -1132,6 +1135,30 @@ export class Calendar extends BaseComponent implements OnInit, OnDestroy, Contro } } + _dateTemplate: TemplateRef | undefined; + + _headerTemplate: TemplateRef | undefined; + + _footerTemplate: TemplateRef | undefined; + + _disabledDateTemplate: TemplateRef | undefined; + + _decadeTemplate: TemplateRef | undefined; + + _previousIconTemplate: TemplateRef | undefined; + + _nextIconTemplate: TemplateRef | undefined; + + _triggerIconTemplate: TemplateRef | undefined; + + _clearIconTemplate: TemplateRef | undefined; + + _decrementIconTemplate: TemplateRef | undefined; + + _incrementIconTemplate: TemplateRef | undefined; + + _inputIconTemplate: TemplateRef | undefined; + _componentStyle = inject(CalendarStyle); contentViewChild!: ElementRef; @@ -1330,6 +1357,66 @@ export class Calendar extends BaseComponent implements OnInit, OnDestroy, Contro } } + @ContentChildren(PrimeTemplate) templates!: QueryList; + + ngAfterContentInit() { + this.templates.forEach((item) => { + switch (item.getType()) { + case 'date': + this._dateTemplate = item.template; + break; + + case 'decade': + this._decadeTemplate = item.template; + break; + + case 'disabledDate': + this._disabledDateTemplate = item.template; + break; + + case 'header': + this._headerTemplate = item.template; + break; + + case 'inputicon': + this._inputIconTemplate = item.template; + break; + + case 'previousicon': + this._previousIconTemplate = item.template; + break; + + case 'nexticon': + this._nextIconTemplate = item.template; + break; + + case 'triggericon': + this._triggerIconTemplate = item.template; + break; + + case 'clearicon': + this._clearIconTemplate = item.template; + break; + + case 'decrementicon': + this._decrementIconTemplate = item.template; + break; + + case 'incrementicon': + this._incrementIconTemplate = item.template; + break; + + case 'footer': + this._footerTemplate = item.template; + break; + + default: + this._dateTemplate = item.template; + break; + } + }); + } + getTranslation(option: string) { return this.config.getTranslation(option); } diff --git a/packages/primeng/src/card/card.ts b/packages/primeng/src/card/card.ts index c2ef94e6c41..a89e97efe1e 100755 --- a/packages/primeng/src/card/card.ts +++ b/packages/primeng/src/card/card.ts @@ -1,7 +1,7 @@ import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, Component, ContentChild, inject, Input, NgModule, signal, TemplateRef, ViewEncapsulation } from '@angular/core'; +import { AfterContentInit, ChangeDetectionStrategy, Component, ContentChild, ContentChildren, inject, Input, NgModule, QueryList, signal, TemplateRef, ViewEncapsulation } from '@angular/core'; import { equals } from '@primeuix/utils'; -import { BlockableUI, Footer, Header, SharedModule } from 'primeng/api'; +import { BlockableUI, Footer, Header, PrimeTemplate, SharedModule } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { CardStyle } from './style/cardstyle'; @@ -15,26 +15,26 @@ import { CardStyle } from './style/cardstyle'; imports: [CommonModule, SharedModule], template: `
    -
    +
    - +
    -
    - {{ _header }} - +
    + {{ header }} +
    -
    - {{ subheader }} - +
    + {{ subheader }} +
    - +
    -
    @@ -43,12 +43,12 @@ import { CardStyle } from './style/cardstyle'; encapsulation: ViewEncapsulation.None, providers: [CardStyle] }) -export class Card extends BaseComponent implements BlockableUI { +export class Card extends BaseComponent implements AfterContentInit, BlockableUI { /** * Header of the card. * @group Props */ - @Input('header') _header: string | undefined; + @Input() header: string | undefined; /** * Subheader of the card. * @group Props @@ -73,15 +73,25 @@ export class Card extends BaseComponent implements BlockableUI { @ContentChild(Footer) footerFacet: TemplateRef | undefined; - @ContentChild('header') headerTemplate: TemplateRef | undefined; + @ContentChild('header', { descendants: false }) headerTemplate: TemplateRef | undefined; - @ContentChild('title') titleTemplate: TemplateRef | undefined; + @ContentChild('title', { descendants: false }) titleTemplate: TemplateRef | undefined; - @ContentChild('subtitle') subtitleTemplate: TemplateRef | undefined; + @ContentChild('subtitle', { descendants: false }) subtitleTemplate: TemplateRef | undefined; - @ContentChild('content') contentTemplate: TemplateRef | undefined; + @ContentChild('content', { descendants: false }) contentTemplate: TemplateRef | undefined; - @ContentChild('footer') footerTemplate: TemplateRef | undefined; + @ContentChild('footer', { descendants: false }) footerTemplate: TemplateRef | undefined; + + _headerTemplate: TemplateRef | undefined; + + _titleTemplate: TemplateRef | undefined; + + _subtitleTemplate: TemplateRef | undefined; + + _contentTemplate: TemplateRef | undefined; + + _footerTemplate: TemplateRef | undefined; _style = signal<{ [klass: string]: any } | null | undefined>(null); @@ -90,6 +100,38 @@ export class Card extends BaseComponent implements BlockableUI { getBlockableElement(): HTMLElement { return this.el.nativeElement.children[0]; } + + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + ngAfterContentInit() { + (this.templates as QueryList).forEach((item) => { + switch (item.getType()) { + case 'header': + this._headerTemplate = item.template; + break; + + case 'title': + this._titleTemplate = item.template; + break; + + case 'subtitle': + this._subtitleTemplate = item.template; + break; + + case 'content': + this._contentTemplate = item.template; + break; + + case 'footer': + this._footerTemplate = item.template; + break; + + default: + this._contentTemplate = item.template; + break; + } + }); + } } @NgModule({ diff --git a/packages/primeng/src/carousel/carousel.ts b/packages/primeng/src/carousel/carousel.ts index 7dfb23fffdd..ef4973195ff 100755 --- a/packages/primeng/src/carousel/carousel.ts +++ b/packages/primeng/src/carousel/carousel.ts @@ -5,6 +5,7 @@ import { ChangeDetectionStrategy, Component, ContentChild, + ContentChildren, ElementRef, EventEmitter, inject, @@ -20,7 +21,7 @@ import { ViewEncapsulation } from '@angular/core'; import { find, findSingle, getAttribute, setAttribute, uuid } from '@primeuix/utils'; -import { Footer, Header, SharedModule } from 'primeng/api'; +import { Footer, Header, PrimeTemplate, SharedModule } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { Button, ButtonProps } from 'primeng/button'; import { ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon } from 'primeng/icons'; @@ -54,12 +55,12 @@ import { CarouselStyle } from './style/carouselstyle'; [buttonProps]="prevButtonProps" > - + - - + + @@ -77,7 +78,7 @@ import { CarouselStyle } from './style/carouselstyle'; [attr.aria-label]="ariaSlideNumber(index)" [attr.aria-roledescription]="ariaSlideLabel()" > - +
    - +
    - +
    @@ -117,12 +118,12 @@ import { CarouselStyle } from './style/carouselstyle'; [buttonProps]="nextButtonProps" [text]="true" > - + - - + +
    @@ -141,9 +142,9 @@ import { CarouselStyle } from './style/carouselstyle'; - `, @@ -369,31 +370,41 @@ export class Carousel extends BaseComponent implements AfterContentInit { * Template for carousel items. * @group Templates */ - @ContentChild('item') itemTemplate: TemplateRef | undefined; + @ContentChild('item', { descendants: false }) itemTemplate: TemplateRef | undefined; /** * Template for the carousel header. * @group Templates */ - @ContentChild('header') headerTemplate: TemplateRef | undefined; + @ContentChild('header', { descendants: false }) headerTemplate: TemplateRef | undefined; /** * Template for the carousel footer. * @group Templates */ - @ContentChild('footer') footerTemplate: TemplateRef | undefined; + @ContentChild('footer', { descendants: false }) footerTemplate: TemplateRef | undefined; /** * Template for the previous button icon. * @group Templates */ - @ContentChild('previousicon') previousicon: TemplateRef | undefined; + @ContentChild('previousicon', { descendants: false }) previousIconTemplate: TemplateRef | undefined; /** * Template for the next button icon. * @group Templates */ - @ContentChild('nexticon') nexticon: TemplateRef | undefined; + @ContentChild('nexticon', { descendants: false }) nextIconTemplate: TemplateRef | undefined; + + _itemTemplate: TemplateRef | undefined; + + _headerTemplate: TemplateRef | undefined; + + _footerTemplate: TemplateRef | undefined; + + _previousIconTemplate: TemplateRef | undefined; + + _nextIconTemplate: TemplateRef | undefined; window: Window; @@ -440,8 +451,9 @@ export class Carousel extends BaseComponent implements AfterContentInit { this.cd.markForCheck(); } + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + ngAfterContentInit() { - super.ngAfterContentInit(); this.id = uuid('pn_id_'); if (isPlatformBrowser(this.platformId)) { this.allowAutoplay = !!this.autoplayInterval; @@ -463,6 +475,34 @@ export class Carousel extends BaseComponent implements AfterContentInit { } } + this.templates?.forEach((item) => { + switch (item.getType()) { + case 'item': + this._itemTemplate = item.template; + break; + + case 'header': + this._headerTemplate = item.template; + break; + + case 'footer': + this._footerTemplate = item.template; + break; + + case 'previousicon': + this._previousIconTemplate = item.template; + break; + + case 'nexticon': + this._nextIconTemplate = item.template; + break; + + default: + this._itemTemplate = item.template; + break; + } + }); + this.cd.detectChanges(); } diff --git a/packages/primeng/src/cascadeselect/cascadeselect.ts b/packages/primeng/src/cascadeselect/cascadeselect.ts index f3a4021e38c..bd431e99d6e 100755 --- a/packages/primeng/src/cascadeselect/cascadeselect.ts +++ b/packages/primeng/src/cascadeselect/cascadeselect.ts @@ -1,10 +1,12 @@ import { CommonModule } from '@angular/common'; import { + AfterContentInit, booleanAttribute, ChangeDetectionStrategy, Component, computed, ContentChild, + ContentChildren, effect, ElementRef, EventEmitter, @@ -15,6 +17,7 @@ import { numberAttribute, OnInit, Output, + QueryList, signal, SimpleChanges, TemplateRef, @@ -23,7 +26,7 @@ import { } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { calculateScrollbarWidth, equals, findLastIndex, findSingle, focus, getHiddenElementOuterWidth, getOffset, getOuterWidth, getViewport, isEmpty, isNotEmpty, isPrintableCharacter, resolveFieldData, uuid } from '@primeuix/utils'; -import { OverlayOptions, OverlayService, SharedModule, TranslationKeys } from 'primeng/api'; +import { OverlayOptions, OverlayService, PrimeTemplate, SharedModule, TranslationKeys } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { BaseComponent } from 'primeng/basecomponent'; import { AngleRightIcon, ChevronDownIcon, TimesIcon } from 'primeng/icons'; @@ -42,7 +45,7 @@ export const CASCADESELECT_VALUE_ACCESSOR: any = { @Component({ selector: 'p-cascadeSelectSub, p-cascadeselect-sub', standalone: true, - imports: [CommonModule, Overlay, Ripple, AutoFocus, AngleRightIcon, SharedModule], + imports: [CommonModule, Ripple, AngleRightIcon, SharedModule], template: `
    - @@ -133,7 +134,7 @@ import { TabMenuStyle } from './style/tabmenustyle'; encapsulation: ViewEncapsulation.None, providers: [TabMenuStyle] }) -export class TabMenu extends BaseComponent implements AfterViewInit, AfterViewChecked, OnDestroy { +export class TabMenu extends BaseComponent implements AfterViewInit, AfterContentInit, AfterViewChecked, OnDestroy { /** * An array of menuitems. * @group Props @@ -216,17 +217,25 @@ export class TabMenu extends BaseComponent implements AfterViewInit, AfterViewCh * Template of the menu item. * @group Templates */ - @ContentChild('item') itemTemplate: Nullable>; + @ContentChild('item', { descendants: false }) itemTemplate: Nullable>; /** * Template of the previous icon. * @group Templates */ - @ContentChild('previousicon') previousiconTemplate: Nullable>; + @ContentChild('previousicon', { descendants: false }) previousIconTemplate: Nullable>; /** * Template of the next icon. * @group Templates */ - @ContentChild('nexticon') nexticonTemplate: Nullable>; + @ContentChild('nexticon', { descendants: false }) nextIconTemplate: Nullable>; + + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + _itemTemplate: TemplateRef | undefined; + + _nextIconTemplate: TemplateRef | undefined; + + _previousIconTemplate: TemplateRef | undefined; tabChanged: boolean | undefined; @@ -281,6 +290,28 @@ export class TabMenu extends BaseComponent implements AfterViewInit, AfterViewCh } } + ngAfterContentInit() { + this.templates?.forEach((item) => { + switch (item.getType()) { + case 'item': + this._itemTemplate = item.template; + break; + + case 'nexticon': + this._nextIconTemplate = item.template; + break; + + case 'previousicon': + this._previousIconTemplate = item.template; + break; + + default: + this._itemTemplate = item.template; + break; + } + }); + } + ngOnDestroy(): void { this.clearAutoScrollHandler(); super.ngOnDestroy(); @@ -296,7 +327,7 @@ export class TabMenu extends BaseComponent implements AfterViewInit, AfterViewCh return item === this.activeItem; } - getItemProp(item: any, name: string) { + getItemProp(item: any, name: string): string { return item ? resolve(item[name]) : undefined; } diff --git a/packages/primeng/src/tabs/tablist.ts b/packages/primeng/src/tabs/tablist.ts index d32a174ab2a..2ff795883ed 100644 --- a/packages/primeng/src/tabs/tablist.ts +++ b/packages/primeng/src/tabs/tablist.ts @@ -1,7 +1,7 @@ import { CommonModule, isPlatformBrowser } from '@angular/common'; -import { AfterContentInit, AfterViewInit, ChangeDetectionStrategy, Component, computed, ContentChild, effect, ElementRef, forwardRef, inject, signal, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { AfterContentInit, AfterViewInit, ChangeDetectionStrategy, Component, computed, ContentChild, ContentChildren, effect, ElementRef, forwardRef, inject, QueryList, signal, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; import { findSingle, getHeight, getOffset, getOuterWidth, getWidth, isRTL } from '@primeuix/utils'; -import { SharedModule } from 'primeng/api'; +import { PrimeTemplate, SharedModule } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { ChevronLeftIcon, ChevronRightIcon } from 'primeng/icons'; import { RippleModule } from 'primeng/ripple'; @@ -18,8 +18,8 @@ import { Tabs } from './tabs'; template: ` @if (showNavigators() && isPrevButtonEnabled()) {
    @@ -273,23 +315,23 @@ export class TabPanel extends BaseComponent implements AfterContentInit, OnDestr (keydown)="onTabKeyDown($event, tab)" pRipple > - @if (tab.headerTemplate) { - + @if (tab.headerTemplate || tab._headerTemplate) { + } @else { - @if (tab.lefticonTemplate) { - - } @else if (tab.leftIcon && !tab.lefticonTemplate) { + @if (tab.leftIconTemplate || tab._leftIconTemplate) { + + } @else if (tab.leftIcon && !tab.leftIconTemplate && !tab._leftIconTemplate) { } {{ tab.header }} - @if (tab.rightIconTemplate) { - - } @else if (tab.rightIcon && !tab.rightIconTemplate) { + @if (tab.rightIconTemplate || tab._rightIconTemplate) { + + } @else if (tab.rightIcon && !tab.rightIconTemplate && !tab._rightIconTemplate) { } @if (tab.closable) { - @if (tab.closeIconTemplate) { - + @if (tab.closeIconTemplate || tab._closeIconTemplate) { + } @else { } @@ -302,8 +344,8 @@ export class TabPanel extends BaseComponent implements AfterContentInit, OnDestr
    @@ -62,7 +61,7 @@ export const TOGGLEBUTTON_VALUE_ACCESSOR: any = { providers: [TOGGLEBUTTON_VALUE_ACCESSOR, ToggleButtonStyle], changeDetection: ChangeDetectionStrategy.OnPush }) -export class ToggleButton extends BaseComponent implements ControlValueAccessor { +export class ToggleButton extends BaseComponent implements AfterContentInit, ControlValueAccessor { /** * Label for the on state. * @group Props @@ -108,6 +107,7 @@ export class ToggleButton extends BaseComponent implements ControlValueAccessor * @group Props */ @Input() styleClass: string | undefined; + @HostBinding('class') get hostClass() { return this.styleClass || ''; } @@ -151,12 +151,14 @@ export class ToggleButton extends BaseComponent implements ControlValueAccessor * Custom icon template. * @group Templates */ - @ContentChild('icon') iconTemplate: Nullable>; + @ContentChild('icon', { descendants: false }) iconTemplate: Nullable>; /** * Custom content template. * @group Templates */ - @ContentChild('content') contentTemplate: Nullable>; + @ContentChild('content', { descendants: false }) contentTemplate: Nullable>; + + @ContentChildren(PrimeTemplate) templates!: QueryList; checked: boolean = false; @@ -226,6 +228,26 @@ export class ToggleButton extends BaseComponent implements ControlValueAccessor get active() { return this.checked === true; } + + _iconTemplate: TemplateRef | undefined; + + _contentTemplate: TemplateRef | undefined; + + ngAfterContentInit() { + this.templates.forEach((item) => { + switch (item.getType()) { + case 'icon': + this._iconTemplate = item.template; + break; + case 'content': + this._contentTemplate = item.template; + break; + default: + this._contentTemplate = item.template; + break; + } + }); + } } @NgModule({ diff --git a/packages/primeng/src/toggleswitch/toggleswitch.ts b/packages/primeng/src/toggleswitch/toggleswitch.ts index a4616c3f590..aea79a74795 100755 --- a/packages/primeng/src/toggleswitch/toggleswitch.ts +++ b/packages/primeng/src/toggleswitch/toggleswitch.ts @@ -1,7 +1,26 @@ import { CommonModule } from '@angular/common'; -import { AfterContentInit, booleanAttribute, ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmitter, forwardRef, inject, Input, NgModule, numberAttribute, Output, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + AfterContentInit, + booleanAttribute, + ChangeDetectionStrategy, + Component, + ContentChild, + ContentChildren, + ElementRef, + EventEmitter, + forwardRef, + inject, + Input, + NgModule, + numberAttribute, + Output, + QueryList, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { SharedModule } from 'primeng/api'; +import { PrimeTemplate, SharedModule } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { BaseComponent } from 'primeng/basecomponent'; import { ToggleSwitchStyle } from './style/toggleswitchstyle'; @@ -51,8 +70,8 @@ export const TOGGLESWITCH_VALUE_ACCESSOR: any = { />
    - @if (handleTemplate) { - + @if (handleTemplate || _handleTemplate) { + }
    @@ -141,7 +160,9 @@ export class ToggleSwitch extends BaseComponent implements AfterContentInit { * @see {@link ToggleSwitchHandleTemplateContext} * @group Templates */ - @ContentChild('handle') handleTemplate: TemplateRef | undefined; + @ContentChild('handle', { descendants: false }) handleTemplate: TemplateRef | undefined; + + _handleTemplate: TemplateRef | undefined; modelValue: any = false; @@ -153,6 +174,21 @@ export class ToggleSwitch extends BaseComponent implements AfterContentInit { _componentStyle = inject(ToggleSwitchStyle); + @ContentChildren(PrimeTemplate) templates!: QueryList; + + ngAfterContentInit() { + this.templates.forEach((item) => { + switch (item.getType()) { + case 'handle': + this._handleTemplate = item.template; + break; + default: + this._handleTemplate = item.template; + break; + } + }); + } + onClick(event: Event) { if (!this.disabled && !this.readonly) { this.modelValue = this.checked() ? this.falseValue : this.trueValue; diff --git a/packages/primeng/src/toolbar/toolbar.ts b/packages/primeng/src/toolbar/toolbar.ts index 2b5527dcd6a..7980ca0c167 100755 --- a/packages/primeng/src/toolbar/toolbar.ts +++ b/packages/primeng/src/toolbar/toolbar.ts @@ -1,6 +1,6 @@ import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, Component, ContentChild, inject, Input, NgModule, TemplateRef, ViewEncapsulation } from '@angular/core'; -import { BlockableUI, SharedModule } from 'primeng/api'; +import { AfterContentInit, ChangeDetectionStrategy, Component, ContentChild, ContentChildren, inject, Input, NgModule, QueryList, TemplateRef, ViewEncapsulation } from '@angular/core'; +import { BlockableUI, PrimeTemplate, SharedModule } from 'primeng/api'; import { BaseComponent } from 'primeng/basecomponent'; import { ToolbarStyle } from './style/toolbarstyle'; @@ -15,14 +15,14 @@ import { ToolbarStyle } from './style/toolbarstyle'; template: `
    -
    - +
    +
    -
    - +
    +
    -
    - +
    +
    `, @@ -30,7 +30,7 @@ import { ToolbarStyle } from './style/toolbarstyle'; encapsulation: ViewEncapsulation.None, providers: [ToolbarStyle] }) -export class Toolbar extends BaseComponent implements BlockableUI { +export class Toolbar extends BaseComponent implements AfterContentInit, BlockableUI { /** * Inline style of the component. * @group Props @@ -56,19 +56,47 @@ export class Toolbar extends BaseComponent implements BlockableUI { * Defines template option for start. * @group Templates */ - @ContentChild('start') startTemplate: TemplateRef | undefined; + @ContentChild('start', { descendants: false }) startTemplate: TemplateRef | undefined; /** * Defines template option for end. * @group Templates */ - @ContentChild('end') endTemplate: TemplateRef | undefined; + @ContentChild('end', { descendants: false }) endTemplate: TemplateRef | undefined; /** * Defines template option for center. * @group Templates */ - @ContentChild('center') centerTemplate: TemplateRef | undefined; + @ContentChild('center', { descendants: false }) centerTemplate: TemplateRef | undefined; + + @ContentChildren(PrimeTemplate) templates: QueryList | undefined; + + _startTemplate: TemplateRef | undefined; + + _endTemplate: TemplateRef | undefined; + + _centerTemplate: TemplateRef | undefined; + + ngAfterContentInit() { + (this.templates as QueryList).forEach((item) => { + switch (item.getType()) { + case 'start': + case 'left': + this._startTemplate = item.template; + break; + + case 'end': + case 'right': + this._endTemplate = item.template; + break; + + case 'center': + this._centerTemplate = item.template; + break; + } + }); + } } @NgModule({ diff --git a/packages/primeng/src/tree/tree.ts b/packages/primeng/src/tree/tree.ts index 2dabb094164..eaf4efacb3c 100755 --- a/packages/primeng/src/tree/tree.ts +++ b/packages/primeng/src/tree/tree.ts @@ -1,5 +1,6 @@ import { CommonModule } from '@angular/common'; import { + AfterContentInit, booleanAttribute, ChangeDetectionStrategy, Component, @@ -97,7 +98,7 @@ import { (dragend)="onDragStop($event)" > @@ -122,11 +123,11 @@ import { [attr.data-p-partialchecked]="node.partialSelected" [tabindex]="-1" > - +
    - - - + + +
    - - @if (filterTemplate) { - + + @if (filterTemplate || _filterTemplate) { + } @else { - - - + + + @@ -761,9 +762,9 @@ export class UITreeNode extends BaseComponent implements OnInit { >
    - + - + @@ -785,20 +786,19 @@ export class UITreeNode extends BaseComponent implements OnInit {
    - + {{ emptyMessageLabel }} - +
    - +
    `, changeDetection: ChangeDetectionStrategy.Default, encapsulation: ViewEncapsulation.None, providers: [TreeStyle] }) -export class Tree extends BaseComponent implements OnInit, OnChanges, OnDestroy, BlockableUI { - @ContentChild('filter') filterTemplate: TemplateRef; +export class Tree extends BaseComponent implements OnInit, AfterContentInit, OnChanges, OnDestroy, BlockableUI { /** * An array of treenodes. * @group Props @@ -1063,51 +1063,56 @@ export class Tree extends BaseComponent implements OnInit, OnChanges, OnDestroy, * @group Emits */ @Output() onFilter: EventEmitter = new EventEmitter(); + /** + * Filter template. + * @group Templates + */ + @ContentChild('filter', { descendants: false }) filterTemplate: TemplateRef; /** * Node template. * @group Templates */ - @ContentChild('node') nodeTemplate: TemplateRef | undefined; + @ContentChild('node', { descendants: false }) nodeTemplate: TemplateRef | undefined; /** * Header template. * @group Templates */ - @ContentChild('header') headerTemplate: TemplateRef | undefined; + @ContentChild('header', { descendants: false }) headerTemplate: TemplateRef | undefined; /** * Footer template. * @group Templates */ - @ContentChild('footer') footerTemplate: TemplateRef | undefined; + @ContentChild('footer', { descendants: false }) footerTemplate: TemplateRef | undefined; /** * Loader template. * @group Templates */ - @ContentChild('loader') loaderTemplate: TemplateRef | undefined; + @ContentChild('loader', { descendants: false }) loaderTemplate: TemplateRef | undefined; /** * Empty message template. * @group Templates */ - @ContentChild('empty') emptymessageTemplate: TemplateRef | undefined; + @ContentChild('empty', { descendants: false }) emptyMessageTemplate: TemplateRef | undefined; /** * Toggler icon template. * @group Templates */ - @ContentChild('togglericon') togglericonTemplate: TemplateRef | undefined; + @ContentChild('togglericon', { descendants: false }) togglerIconTemplate: TemplateRef | undefined; /** * Checkbox icon template. * @group Templates */ - @ContentChild('checkboxicon') checkboxiconTemplate: TemplateRef | undefined; + @ContentChild('checkboxicon', { descendants: false }) checkboxIconTemplate: TemplateRef | undefined; /** * Loading icon template. * @group Templates */ - @ContentChild('loadingicon') loadingiconTemplate: TemplateRef | undefined; + @ContentChild('loadingicon', { descendants: false }) loadingIconTemplate: TemplateRef | undefined; /** * Filter icon template. * @group Templates */ - @ContentChild('filtericon') filtericonTemplate: TemplateRef | undefined; + @ContentChild('filtericon', { descendants: false }) filterIconTemplate: TemplateRef | undefined; @ViewChild('filter') filterViewChild: Nullable; @@ -1115,45 +1120,67 @@ export class Tree extends BaseComponent implements OnInit, OnChanges, OnDestroy, @ViewChild('wrapper') wrapperViewChild: Nullable; - @ContentChildren(PrimeTemplate) private _templates: QueryList | undefined; + @ContentChildren(PrimeTemplate) private templates: QueryList | undefined; + + _headerTemplate: TemplateRef | undefined; + + _emptyMessageTemplate: TemplateRef | undefined; + + _footerTemplate: TemplateRef | undefined; + + _loaderTemplate: TemplateRef | undefined; + + _togglerIconTemplate: TemplateRef | undefined; + + _checkboxIconTemplate: TemplateRef | undefined; + + _loadingIconTemplate: TemplateRef | undefined; + + _filterIconTemplate: TemplateRef | undefined; + + _filterTemplate: TemplateRef | undefined; ngAfterContentInit() { - if ((this._templates as QueryList).length) { + if ((this.templates as QueryList).length) { this._templateMap = {}; } - (this._templates as QueryList).forEach((item) => { + (this.templates as QueryList).forEach((item) => { switch (item.getType()) { case 'header': - this.headerTemplate = item.template; + this._headerTemplate = item.template; break; case 'empty': - this.emptymessageTemplate = item.template; + this._emptyMessageTemplate = item.template; break; case 'footer': - this.footerTemplate = item.template; + this._footerTemplate = item.template; break; case 'loader': - this.loaderTemplate = item.template; + this._loaderTemplate = item.template; break; case 'togglericon': - this.togglericonTemplate = item.template; + this._togglerIconTemplate = item.template; break; case 'checkboxicon': - this.checkboxiconTemplate = item.template; + this._checkboxIconTemplate = item.template; break; case 'loadingicon': - this.loadingiconTemplate = item.template; + this._loadingIconTemplate = item.template; break; case 'filtericon': - this.filtericonTemplate = item.template; + this._filterIconTemplate = item.template; + break; + + case 'filter': + this._filterTemplate = item.template; break; default: diff --git a/packages/primeng/src/treeselect/treeselect.ts b/packages/primeng/src/treeselect/treeselect.ts index a6c92d49c0a..107483433fb 100755 --- a/packages/primeng/src/treeselect/treeselect.ts +++ b/packages/primeng/src/treeselect/treeselect.ts @@ -1,16 +1,32 @@ import { AnimationEvent } from '@angular/animations'; import { CommonModule } from '@angular/common'; -import { booleanAttribute, ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmitter, forwardRef, inject, Input, NgModule, Output, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; +import { + AfterContentInit, + booleanAttribute, + ChangeDetectionStrategy, + Component, + ContentChild, + ContentChildren, + ElementRef, + EventEmitter, + forwardRef, + inject, + Input, + NgModule, + Output, + QueryList, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { focus, getFirstFocusableElement, getFocusableElements, getLastFocusableElement, hasClass, isNotEmpty, uuid } from '@primeuix/utils'; -import { OverlayOptions, ScrollerOptions, SharedModule, TreeNode } from 'primeng/api'; +import { OverlayOptions, PrimeTemplate, ScrollerOptions, SharedModule, TreeNode } from 'primeng/api'; import { AutoFocus } from 'primeng/autofocus'; import { BaseComponent } from 'primeng/basecomponent'; import { Chip } from 'primeng/chip'; -import { ChevronDownIcon, SearchIcon, TimesIcon } from 'primeng/icons'; -import { InputText } from 'primeng/inputtext'; +import { ChevronDownIcon, TimesIcon } from 'primeng/icons'; import { Overlay } from 'primeng/overlay'; -import { Ripple } from 'primeng/ripple'; import { Tree, TreeFilterEvent, TreeNodeSelectEvent, TreeNodeUnSelectEvent } from 'primeng/tree'; import { Nullable } from 'primeng/ts-helpers'; import { TreeSelectStyle } from './style/treeselectstyle'; @@ -28,7 +44,7 @@ export const TREESELECT_VALUE_ACCESSOR: any = { @Component({ selector: 'p-treeSelect, p-treeselect, p-tree-select', standalone: true, - imports: [CommonModule, Overlay, SharedModule, Ripple, InputText, Tree, AutoFocus, SearchIcon, TimesIcon, ChevronDownIcon, Chip], + imports: [CommonModule, Overlay, SharedModule, Tree, AutoFocus, TimesIcon, ChevronDownIcon, Chip], template: `
    @@ -53,8 +69,8 @@ export const TREESELECT_VALUE_ACCESSOR: any = {
    - - + + @@ -70,15 +86,15 @@ export const TREESELECT_VALUE_ACCESSOR: any = {
    - - - + + +
    - - - + + +
    - +
    - + - + - - + + - - + + - - + +
    @@ -169,7 +185,7 @@ export const TREESELECT_VALUE_ACCESSOR: any = { providers: [TREESELECT_VALUE_ACCESSOR, TreeSelectStyle], encapsulation: ViewEncapsulation.None }) -export class TreeSelect extends BaseComponent { +export class TreeSelect extends BaseComponent implements AfterContentInit { /** * Identifier of the underlying input element. * @group Props @@ -492,73 +508,99 @@ export class TreeSelect extends BaseComponent { * Custom value template. * @group Templates */ - @ContentChild('value') valueTemplate: Nullable>; + @ContentChild('value', { descendants: false }) valueTemplate: Nullable>; /** * Custom header template. * @group Templates */ - @ContentChild('header') headerTemplate: Nullable>; + @ContentChild('header', { descendants: false }) headerTemplate: Nullable>; /** * Custom empty message template. * @group Templates */ - @ContentChild('empty') emptyTemplate: Nullable>; + @ContentChild('empty', { descendants: false }) emptyTemplate: Nullable>; /** * Custom footer template. * @group Templates */ - @ContentChild('footer') footerTemplate: Nullable>; + @ContentChild('footer', { descendants: false }) footerTemplate: Nullable>; /** * Custom clear icon template. * @group Templates */ - @ContentChild('clearicon') cleariconTemplate: Nullable>; + @ContentChild('clearicon', { descendants: false }) clearIconTemplate: Nullable>; /** * Custom trigger icon template. * @group Templates */ - @ContentChild('triggericon') triggericonTemplate: Nullable>; + @ContentChild('triggericon', { descendants: false }) triggerIconTemplate: Nullable>; /** * Custom dropdown icon template. * @group Templates */ - @ContentChild('dropdownicon') dropdowniconTemplate: Nullable>; + @ContentChild('dropdownicon', { descendants: false }) dropdownIconTemplate: Nullable>; /** * Custom filter icon template. * @group Templates */ - @ContentChild('filtericon') filtericonTemplate: Nullable>; + @ContentChild('filtericon', { descendants: false }) filterIconTemplate: Nullable>; /** * Custom close icon template. * @group Templates */ - @ContentChild('closeicon') closeiconTemplate: Nullable>; + @ContentChild('closeicon', { descendants: false }) closeIconTemplate: Nullable>; /** * Custom item toggler icon template. * @group Templates */ - @ContentChild('itemtogglericon') itemtogglericonTemplate: Nullable>; + @ContentChild('itemtogglericon', { descendants: false }) itemTogglerIconTemplate: Nullable>; /** * Custom item checkbox icon template. * @group Templates */ - @ContentChild('itemcheckboxicon') itemcheckboxiconTemplate: Nullable>; + @ContentChild('itemcheckboxicon', { descendants: false }) itemCheckboxIconTemplate: Nullable>; /** * Custom item loading icon template. * @group Templates */ - @ContentChild('itemloadingicon') itemloadingiconTemplate: Nullable>; + @ContentChild('itemloadingicon', { descendants: false }) itemLoadingIconTemplate: Nullable>; + + @ContentChildren(PrimeTemplate) templates: Nullable>; + + _valueTemplate: TemplateRef | undefined; + + _headerTemplate: TemplateRef | undefined; + + _emptyTemplate: TemplateRef | undefined; + + _footerTemplate: TemplateRef | undefined; + + _clearIconTemplate: TemplateRef | undefined; + + _triggerIconTemplate: TemplateRef | undefined; + + _filterIconTemplate: TemplateRef | undefined; + + _closeIconTemplate: TemplateRef | undefined; + + _itemTogglerIconTemplate: TemplateRef | undefined; + + _itemCheckboxIconTemplate: TemplateRef | undefined; + + _itemLoadingIconTemplate: TemplateRef | undefined; + + _dropdownIconTemplate: TemplateRef | undefined; focused: Nullable; @@ -588,6 +630,69 @@ export class TreeSelect extends BaseComponent { this.updateTreeState(); } + ngAfterContentInit() { + if ((this.templates as QueryList).length) { + this.templateMap = {}; + } + + (this.templates as QueryList).forEach((item) => { + switch (item.getType()) { + case 'value': + this._valueTemplate = item.template; + break; + + case 'header': + this._headerTemplate = item.template; + break; + + case 'empty': + this._emptyTemplate = item.template; + break; + + case 'footer': + this._footerTemplate = item.template; + break; + + case 'clearicon': + this._clearIconTemplate = item.template; + break; + + case 'triggericon': + this._triggerIconTemplate = item.template; + break; + + case 'filtericon': + this._filterIconTemplate = item.template; + break; + + case 'closeicon': + this._closeIconTemplate = item.template; + break; + + case 'itemtogglericon': + this._itemTogglerIconTemplate = item.template; + break; + + case 'itemcheckboxicon': + this._itemCheckboxIconTemplate = item.template; + break; + + case 'dropdownicon': + this._dropdownIconTemplate = item.template; + break; + + case 'itemloadingicon': + this._itemLoadingIconTemplate = item.template; + break; + + default: //TODO: @deprecated Used "value" template instead + if (item.name) this.templateMap[item.name] = item.template; + else this.valueTemplate = item.template; + break; + } + }); + } + onOverlayAnimationStart(event: AnimationEvent) { switch (event.toState) { case 'visible': diff --git a/packages/primeng/src/treetable/treetable.ts b/packages/primeng/src/treetable/treetable.ts index 1ad9367c638..75a663e11ba 100755 --- a/packages/primeng/src/treetable/treetable.ts +++ b/packages/primeng/src/treetable/treetable.ts @@ -6,6 +6,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + ContentChildren, Directive, ElementRef, EventEmitter, @@ -883,6 +884,8 @@ export class TreeTable extends BaseComponent implements AfterContentInit, OnInit this.initialized = true; } + @ContentChildren(PrimeTemplate) templates: Nullable>; + ngAfterContentInit() { (this.templates as QueryList).forEach((item) => { switch (item.getType()) { @@ -3533,6 +3536,8 @@ export class TTEditableColumn implements AfterViewInit { encapsulation: ViewEncapsulation.None }) export class TreeTableCellEditor extends BaseComponent implements AfterContentInit { + @ContentChildren(PrimeTemplate) templates: Nullable>; + inputTemplate: Nullable>; outputTemplate: Nullable>; @@ -3545,7 +3550,6 @@ export class TreeTableCellEditor extends BaseComponent implements AfterContentIn } ngAfterContentInit() { - super.ngAfterContentInit(); (this.templates as QueryList).forEach((item) => { switch (item.getType()) { case 'input':