Browse Source

Refactor to use new viewChild/viewChildren/contentChild APIs

Replaces deprecated ViewChild, ViewChildren, and ContentChild decorators with the new viewChild, viewChildren, and contentChild functions across multiple components. Updates related usages to use the new function call syntax, improving code consistency and aligning with Angular's latest best practices.
pull/24765/head
Fahri Gedik 8 months ago
parent
commit
bda3c32c65
  1. 8
      npm/ng-packs/apps/dev-app/src/app/dynamic-form-page/dynamic-form-page.component.ts
  2. 8
      npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field-host.component.ts
  3. 10
      npm/ng-packs/packages/components/extensible/src/lib/components/date-time-picker/extensible-date-time-picker.component.ts
  4. 8
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.ts
  5. 6
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.ts
  6. 18
      npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts
  7. 6
      npm/ng-packs/packages/components/page/src/page.component.html
  8. 15
      npm/ng-packs/packages/components/page/src/page.component.ts
  9. 5
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  10. 24
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  11. 7
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
  12. 7
      npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts
  13. 10
      npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts

8
npm/ng-packs/apps/dev-app/src/app/dynamic-form-page/dynamic-form-page.component.ts

@ -1,4 +1,4 @@
import { Component, inject, OnInit, ViewChild } from '@angular/core'; import { Component, inject, OnInit, viewChild } from '@angular/core';
import { DynamicFormComponent, FormFieldConfig } from '@abp/ng.components/dynamic-form'; import { DynamicFormComponent, FormFieldConfig } from '@abp/ng.components/dynamic-form';
import { FormConfigService } from './form-config.service'; import { FormConfigService } from './form-config.service';
@ -8,7 +8,7 @@ import { FormConfigService } from './form-config.service';
imports: [DynamicFormComponent], imports: [DynamicFormComponent],
}) })
export class DynamicFormPageComponent implements OnInit { export class DynamicFormPageComponent implements OnInit {
@ViewChild(DynamicFormComponent, { static: false }) dynamicFormComponent: DynamicFormComponent; readonly dynamicFormComponent = viewChild(DynamicFormComponent);
protected readonly formConfigService = inject(FormConfigService); protected readonly formConfigService = inject(FormConfigService);
formFields: FormFieldConfig[] = []; formFields: FormFieldConfig[] = [];
@ -27,12 +27,12 @@ export class DynamicFormPageComponent implements OnInit {
alert('✅ Form submitted successfully! Check the console for details.'); alert('✅ Form submitted successfully! Check the console for details.');
// Reset form after submission // Reset form after submission
this.dynamicFormComponent.resetForm(); this.dynamicFormComponent().resetForm();
} }
cancel() { cancel() {
console.log('❌ Form Cancelled'); console.log('❌ Form Cancelled');
alert('Form cancelled'); alert('Form cancelled');
this.dynamicFormComponent.resetForm(); this.dynamicFormComponent().resetForm();
} }
} }

8
npm/ng-packs/packages/components/dynamic-form/src/dynamic-form-field/dynamic-form-field-host.component.ts

@ -1,6 +1,5 @@
import { import {
Component, Component,
ViewChild,
ViewContainerRef, ViewContainerRef,
ChangeDetectionStrategy, ChangeDetectionStrategy,
forwardRef, forwardRef,
@ -9,6 +8,7 @@ import {
DestroyRef, DestroyRef,
inject, inject,
input, input,
viewChild
} from '@angular/core'; } from '@angular/core';
import { import {
ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, ReactiveFormsModule ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, ReactiveFormsModule
@ -34,7 +34,7 @@ export class DynamicFieldHostComponent implements ControlValueAccessor {
component = input<Type<ControlValueAccessor>>(); component = input<Type<ControlValueAccessor>>();
inputs = input<Record<string, any>>({}); inputs = input<Record<string, any>>({});
@ViewChild('vcRef', { read: ViewContainerRef, static: true }) viewContainerRef!: ViewContainerRef; readonly viewContainerRef = viewChild.required('vcRef', { read: ViewContainerRef });
private componentRef?: any; private componentRef?: any;
private value: any; private value: any;
@ -55,10 +55,10 @@ export class DynamicFieldHostComponent implements ControlValueAccessor {
} }
private createChild() { private createChild() {
this.viewContainerRef.clear(); this.viewContainerRef().clear();
if (!this.component()) return; if (!this.component()) return;
this.componentRef = this.viewContainerRef.createComponent(this.component()); this.componentRef = this.viewContainerRef().createComponent(this.component());
this.applyInputs(); this.applyInputs();
const instance: any = this.componentRef.instance as controlValueAccessorLike & acceptsFormControl; const instance: any = this.componentRef.instance as controlValueAccessorLike & acceptsFormControl;

10
npm/ng-packs/packages/components/extensible/src/lib/components/date-time-picker/extensible-date-time-picker.component.ts

@ -6,7 +6,7 @@ import {
input, input,
Optional, Optional,
SkipSelf, SkipSelf,
ViewChild, viewChild
} from '@angular/core'; } from '@angular/core';
import { ControlContainer, ReactiveFormsModule } from '@angular/forms'; import { ControlContainer, ReactiveFormsModule } from '@angular/forms';
import { import {
@ -76,14 +76,14 @@ export class ExtensibleDateTimePickerComponent {
meridian = input<boolean>(false); meridian = input<boolean>(false);
placement = input<Placement>('bottom-left'); placement = input<Placement>('bottom-left');
@ViewChild(NgbInputDatepicker) date!: NgbInputDatepicker; readonly date = viewChild.required(NgbInputDatepicker);
@ViewChild(NgbTimepicker) time!: NgbTimepicker; readonly time = viewChild.required(NgbTimepicker);
setDate(dateStr: string) { setDate(dateStr: string) {
this.date.writeValue(dateStr); this.date().writeValue(dateStr);
} }
setTime(dateStr: string) { setTime(dateStr: string) {
this.time.writeValue(dateStr); this.time().writeValue(dateStr);
} }
} }

8
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form-prop.component.ts

@ -19,9 +19,9 @@ import {
Optional, Optional,
SimpleChanges, SimpleChanges,
SkipSelf, SkipSelf,
ViewChild,
signal, signal,
effect, effect,
viewChild
} from '@angular/core'; } from '@angular/core';
import { import {
ControlContainer, ControlContainer,
@ -98,7 +98,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
@Input() prop!: FormProp; @Input() prop!: FormProp;
@Input() first?: boolean; @Input() first?: boolean;
@Input() isFirstGroup?: boolean; @Input() isFirstGroup?: boolean;
@ViewChild('field') private fieldRef!: ElementRef<HTMLElement>; private readonly fieldRef = viewChild.required<ElementRef<HTMLElement>>('field');
injectorForCustomComponent?: Injector; injectorForCustomComponent?: Injector;
asterisk = ''; asterisk = '';
@ -158,9 +158,9 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
} }
ngAfterViewInit() { ngAfterViewInit() {
if (this.isFirstGroup && this.first && this.fieldRef) { if (this.isFirstGroup && this.first && this.fieldRef()) {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.fieldRef.nativeElement.focus(); this.fieldRef().nativeElement.focus();
}); });
} }
} }

6
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-form/extensible-form.component.ts

@ -6,9 +6,8 @@ import {
inject, inject,
Input, Input,
Optional, Optional,
QueryList,
SkipSelf, SkipSelf,
ViewChildren, viewChildren
} from '@angular/core'; } from '@angular/core';
import { ControlContainer, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms'; import { ControlContainer, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { EXTRA_PROPERTIES_KEY } from '../../constants/extra-properties'; import { EXTRA_PROPERTIES_KEY } from '../../constants/extra-properties';
@ -41,8 +40,7 @@ export class ExtensibleFormComponent<R = any> {
private readonly extensions = inject(ExtensionsService); private readonly extensions = inject(ExtensionsService);
private readonly identifier = inject(EXTENSIONS_IDENTIFIER); private readonly identifier = inject(EXTENSIONS_IDENTIFIER);
@ViewChildren(ExtensibleFormPropComponent) readonly formProps = viewChildren(ExtensibleFormPropComponent);
formProps!: QueryList<ExtensibleFormPropComponent>;
@Input() @Input()
set selectedRecord(record: R) { set selectedRecord(record: R) {

18
npm/ng-packs/packages/components/extensible/src/lib/components/extensible-table/extensible-table.component.ts

@ -4,7 +4,6 @@ import {
ChangeDetectorRef, ChangeDetectorRef,
Component, Component,
computed, computed,
ContentChild,
EventEmitter, EventEmitter,
inject, inject,
Injector, Injector,
@ -18,7 +17,8 @@ import {
SimpleChanges, SimpleChanges,
TemplateRef, TemplateRef,
TrackByFunction, TrackByFunction,
ViewChild, contentChild,
viewChild
} from '@angular/core'; } from '@angular/core';
import { AsyncPipe, isPlatformBrowser, NgComponentOutlet, NgTemplateOutlet } from '@angular/common'; import { AsyncPipe, isPlatformBrowser, NgComponentOutlet, NgTemplateOutlet } from '@angular/common';
@ -141,17 +141,16 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
@Input() rowDetailHeight: string | number = '100%'; @Input() rowDetailHeight: string | number = '100%';
@Output() rowDetailToggle = new EventEmitter<R>(); @Output() rowDetailToggle = new EventEmitter<R>();
@ContentChild(ExtensibleTableRowDetailComponent) readonly rowDetailComponent = contentChild(ExtensibleTableRowDetailComponent);
rowDetailComponent?: ExtensibleTableRowDetailComponent<R>;
@ViewChild('table', { static: false }) table!: DatatableComponent; readonly table = viewChild.required<DatatableComponent>('table');
protected get effectiveRowDetailTemplate(): TemplateRef<RowDetailContext<R>> | undefined { protected get effectiveRowDetailTemplate(): TemplateRef<RowDetailContext<R>> | undefined {
return this.rowDetailComponent?.template() ?? this.rowDetailTemplate; return this.rowDetailComponent()?.template() ?? this.rowDetailTemplate;
} }
protected get effectiveRowDetailHeight(): string | number { protected get effectiveRowDetailHeight(): string | number {
return this.rowDetailComponent?.rowHeight() ?? this.rowDetailHeight; return this.rowDetailComponent()?.rowHeight() ?? this.rowDetailHeight;
} }
hasAtLeastOnePermittedAction: boolean; hasAtLeastOnePermittedAction: boolean;
@ -318,8 +317,9 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
} }
toggleExpandRow(row: R): void { toggleExpandRow(row: R): void {
if (this.table && this.table.rowDetail) { const table = this.table();
this.table.rowDetail.toggleExpandRow(row); if (table && table.rowDetail) {
table.rowDetail.toggleExpandRow(row);
} }
this.rowDetailToggle.emit(row); this.rowDetailToggle.emit(row);
} }

6
npm/ng-packs/packages/components/page/src/page.component.html

@ -1,6 +1,6 @@
@if (shouldRenderRow) { @if (shouldRenderRow) {
<div class="row entry-row"> <div class="row entry-row">
@if (customTitle) { @if (customTitle()) {
<ng-content select="abp-page-title-container"></ng-content> <ng-content select="abp-page-title-container"></ng-content>
} @else { } @else {
@if (title) { @if (title) {
@ -12,7 +12,7 @@
} }
} }
@if (customBreadcrumb) { @if (customBreadcrumb()) {
<ng-content select="abp-page-breadcrumb-container"></ng-content> <ng-content select="abp-page-breadcrumb-container"></ng-content>
} @else { } @else {
@if (breadcrumb) { @if (breadcrumb) {
@ -22,7 +22,7 @@
} }
} }
@if (customToolbar) { @if (customToolbar()) {
<ng-content select="abp-page-toolbar-container"></ng-content> <ng-content select="abp-page-toolbar-container"></ng-content>
} @else { } @else {
@if (toolbarVisible) { @if (toolbarVisible) {

15
npm/ng-packs/packages/components/page/src/page.component.ts

@ -1,4 +1,4 @@
import { Component, Input, ViewEncapsulation, ContentChild } from '@angular/core'; import { Component, Input, ViewEncapsulation, contentChild } from '@angular/core';
import { import {
PageTitleContainerComponent, PageTitleContainerComponent,
PageBreadcrumbContainerComponent, PageBreadcrumbContainerComponent,
@ -37,19 +37,18 @@ export class PageComponent {
toolbar: PageParts.toolbar, toolbar: PageParts.toolbar,
}; };
@ContentChild(PageTitleContainerComponent) customTitle?: PageTitleContainerComponent; readonly customTitle = contentChild(PageTitleContainerComponent);
@ContentChild(PageBreadcrumbContainerComponent) readonly customBreadcrumb = contentChild(PageBreadcrumbContainerComponent);
customBreadcrumb?: PageBreadcrumbContainerComponent; readonly customToolbar = contentChild(PageToolbarContainerComponent);
@ContentChild(PageToolbarContainerComponent) customToolbar?: PageToolbarContainerComponent;
get shouldRenderRow() { get shouldRenderRow() {
return !!( return !!(
this.title || this.title ||
this.toolbarVisible || this.toolbarVisible ||
this.breadcrumb || this.breadcrumb ||
this.customTitle || this.customTitle() ||
this.customBreadcrumb || this.customBreadcrumb() ||
this.customToolbar || this.customToolbar() ||
this.pageParts this.pageParts
); );
} }

5
npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts

@ -39,7 +39,7 @@ import {
OnInit, OnInit,
TemplateRef, TemplateRef,
TrackByFunction, TrackByFunction,
ViewChild, viewChild
} from '@angular/core'; } from '@angular/core';
import { import {
AbstractControl, AbstractControl,
@ -99,8 +99,7 @@ export class UsersComponent implements OnInit {
data: PagedResultDto<IdentityUserDto> = { items: [], totalCount: 0 }; data: PagedResultDto<IdentityUserDto> = { items: [], totalCount: 0 };
@ViewChild('modalContent', { static: false }) readonly modalContent = viewChild.required<TemplateRef<any>>('modalContent');
modalContent!: TemplateRef<any>;
form!: UntypedFormGroup; form!: UntypedFormGroup;

24
npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts

@ -15,21 +15,22 @@ import {
UpdatePermissionDto, UpdatePermissionDto,
} from '@abp/ng.permission-management/proxy'; } from '@abp/ng.permission-management/proxy';
import { import {
afterNextRender,
Component, Component,
computed, computed,
DOCUMENT, DOCUMENT,
ElementRef, ElementRef,
EventEmitter, EventEmitter,
inject, inject,
Injector,
Input, Input,
Output, Output,
QueryList,
signal, signal,
TrackByFunction, TrackByFunction,
ViewChildren, viewChildren
} from '@angular/core'; } from '@angular/core';
import { concat, of } from 'rxjs'; import { of } from 'rxjs';
import { finalize, switchMap, take, tap } from 'rxjs/operators'; import { finalize, switchMap, tap } from 'rxjs/operators';
import { PermissionManagement } from '../models'; import { PermissionManagement } from '../models';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
@ -116,6 +117,7 @@ export class PermissionManagementComponent
protected readonly service = inject(PermissionsService); protected readonly service = inject(PermissionsService);
protected readonly configState = inject(ConfigStateService); protected readonly configState = inject(ConfigStateService);
protected readonly toasterService = inject(ToasterService); protected readonly toasterService = inject(ToasterService);
private readonly injector = inject(Injector);
private document = inject(DOCUMENT); private document = inject(DOCUMENT);
@Input() @Input()
@ -146,11 +148,9 @@ export class PermissionManagementComponent
this.openModal().subscribe(() => { this.openModal().subscribe(() => {
this._visible = true; this._visible = true;
this.visibleChange.emit(true); this.visibleChange.emit(true);
concat(this.selectAllInAllTabsRef.changes, this.selectAllInThisTabsRef.changes) afterNextRender(() => {
.pipe(take(1)) this.initModal();
.subscribe(() => { }, { injector: this.injector });
this.initModal();
});
}); });
} else { } else {
this.setSelectedGroup(null); this.setSelectedGroup(null);
@ -162,10 +162,8 @@ export class PermissionManagementComponent
@Output() readonly visibleChange = new EventEmitter<boolean>(); @Output() readonly visibleChange = new EventEmitter<boolean>();
@ViewChildren('selectAllInThisTabsRef') selectAllInThisTabsRef = viewChildren<ElementRef<HTMLInputElement>>('selectAllInThisTabsRef');
selectAllInThisTabsRef!: QueryList<ElementRef<HTMLInputElement>>; selectAllInAllTabsRef = viewChildren<ElementRef<HTMLInputElement>>('selectAllInAllTabsRef');
@ViewChildren('selectAllInAllTabsRef')
selectAllInAllTabsRef!: QueryList<ElementRef<HTMLInputElement>>;
data: GetPermissionListResultDto = { groups: [], entityDisplayName: '' }; data: GetPermissionListResultDto = { groups: [], entityDisplayName: '' };

7
npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts

@ -11,10 +11,9 @@ import {
ElementRef, ElementRef,
inject, inject,
Input, Input,
QueryList,
Renderer2, Renderer2,
TrackByFunction, TrackByFunction,
ViewChildren, viewChildren
} from '@angular/core'; } from '@angular/core';
import { NgTemplateOutlet, AsyncPipe } from '@angular/common'; import { NgTemplateOutlet, AsyncPipe } from '@angular/common';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
@ -41,7 +40,7 @@ export class RoutesComponent {
@Input() smallScreen?: boolean; @Input() smallScreen?: boolean;
@ViewChildren('childrenContainer') childrenContainers!: QueryList<ElementRef<HTMLDivElement>>; readonly childrenContainers = viewChildren<ElementRef<HTMLDivElement>>('childrenContainer');
rootDropdownExpand = {} as { [key: string]: boolean }; rootDropdownExpand = {} as { [key: string]: boolean };
@ -52,7 +51,7 @@ export class RoutesComponent {
} }
closeDropdown() { closeDropdown() {
this.childrenContainers.forEach(({ nativeElement }) => { this.childrenContainers().forEach(({ nativeElement }) => {
this.renderer.addClass(nativeElement, 'd-none'); this.renderer.addClass(nativeElement, 'd-none');
setTimeout(() => this.renderer.removeClass(nativeElement, 'd-none'), 0); setTimeout(() => this.renderer.removeClass(nativeElement, 'd-none'), 0);
}); });

7
npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts

@ -7,8 +7,8 @@ import {
OnInit, OnInit,
Output, Output,
Renderer2, Renderer2,
ViewChild,
inject, inject,
viewChild
} from '@angular/core'; } from '@angular/core';
import { ABP, StopPropagationDirective } from '@abp/ng.core'; import { ABP, StopPropagationDirective } from '@abp/ng.core';
@ -70,8 +70,7 @@ export class ButtonComponent implements OnInit {
@Output() readonly abpBlur = new EventEmitter<FocusEvent>(); @Output() readonly abpBlur = new EventEmitter<FocusEvent>();
@ViewChild('button', { static: true }) readonly buttonRef = viewChild.required<ElementRef<HTMLButtonElement>>('button');
buttonRef!: ElementRef<HTMLButtonElement>;
get icon(): string { get icon(): string {
return `${this.loading ? 'fa fa-spinner fa-spin' : this.iconClass || 'd-none'}`; return `${this.loading ? 'fa fa-spinner fa-spin' : this.iconClass || 'd-none'}`;
@ -81,7 +80,7 @@ export class ButtonComponent implements OnInit {
if (this.attributes) { if (this.attributes) {
Object.keys(this.attributes).forEach(key => { Object.keys(this.attributes).forEach(key => {
if (this.attributes?.[key]) { if (this.attributes?.[key]) {
this.renderer.setAttribute(this.buttonRef.nativeElement, key, this.attributes[key]); this.renderer.setAttribute(this.buttonRef().nativeElement, key, this.attributes[key]);
} }
}); });
} }

10
npm/ng-packs/packages/theme-shared/src/lib/components/http-error-wrapper/http-error-wrapper.component.ts

@ -6,12 +6,12 @@ import {
ElementRef, ElementRef,
EmbeddedViewRef, EmbeddedViewRef,
Type, Type,
ViewChild,
AfterViewInit, AfterViewInit,
OnDestroy, OnDestroy,
createComponent, createComponent,
EnvironmentInjector, EnvironmentInjector,
DestroyRef, DestroyRef,
viewChild
} from '@angular/core'; } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
@ -53,8 +53,7 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr
isHomeShow = true; isHomeShow = true;
@ViewChild('container', { static: false }) readonly containerRef = viewChild<ElementRef<HTMLDivElement>>('container');
containerRef?: ElementRef<HTMLDivElement>;
get statusText(): string { get statusText(): string {
return this.status ? `[${this.status}]` : ''; return this.status ? `[${this.status}]` : '';
@ -86,8 +85,9 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr
this.appRef.attachView(customComponentRef.hostView); this.appRef.attachView(customComponentRef.hostView);
if (this.containerRef) { const containerRef = this.containerRef();
this.containerRef.nativeElement.appendChild( if (containerRef) {
containerRef.nativeElement.appendChild(
(customComponentRef.hostView as EmbeddedViewRef<any>).rootNodes[0], (customComponentRef.hostView as EmbeddedViewRef<any>).rootNodes[0],
); );
} }

Loading…
Cancel
Save