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 { FormConfigService } from './form-config.service';
@ -8,7 +8,7 @@ import { FormConfigService } from './form-config.service';
imports: [DynamicFormComponent],
})
export class DynamicFormPageComponent implements OnInit {
@ViewChild(DynamicFormComponent, { static: false }) dynamicFormComponent: DynamicFormComponent;
readonly dynamicFormComponent = viewChild(DynamicFormComponent);
protected readonly formConfigService = inject(FormConfigService);
formFields: FormFieldConfig[] = [];
@ -27,12 +27,12 @@ export class DynamicFormPageComponent implements OnInit {
alert('✅ Form submitted successfully! Check the console for details.');
// Reset form after submission
this.dynamicFormComponent.resetForm();
this.dynamicFormComponent().resetForm();
}
cancel() {
console.log('❌ 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 {
Component,
ViewChild,
ViewContainerRef,
ChangeDetectionStrategy,
forwardRef,
@ -9,6 +8,7 @@ import {
DestroyRef,
inject,
input,
viewChild
} from '@angular/core';
import {
ControlValueAccessor, NG_VALUE_ACCESSOR, FormControl, ReactiveFormsModule
@ -34,7 +34,7 @@ export class DynamicFieldHostComponent implements ControlValueAccessor {
component = input<Type<ControlValueAccessor>>();
inputs = input<Record<string, any>>({});
@ViewChild('vcRef', { read: ViewContainerRef, static: true }) viewContainerRef!: ViewContainerRef;
readonly viewContainerRef = viewChild.required('vcRef', { read: ViewContainerRef });
private componentRef?: any;
private value: any;
@ -55,10 +55,10 @@ export class DynamicFieldHostComponent implements ControlValueAccessor {
}
private createChild() {
this.viewContainerRef.clear();
this.viewContainerRef().clear();
if (!this.component()) return;
this.componentRef = this.viewContainerRef.createComponent(this.component());
this.componentRef = this.viewContainerRef().createComponent(this.component());
this.applyInputs();
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,
Optional,
SkipSelf,
ViewChild,
viewChild
} from '@angular/core';
import { ControlContainer, ReactiveFormsModule } from '@angular/forms';
import {
@ -76,14 +76,14 @@ export class ExtensibleDateTimePickerComponent {
meridian = input<boolean>(false);
placement = input<Placement>('bottom-left');
@ViewChild(NgbInputDatepicker) date!: NgbInputDatepicker;
@ViewChild(NgbTimepicker) time!: NgbTimepicker;
readonly date = viewChild.required(NgbInputDatepicker);
readonly time = viewChild.required(NgbTimepicker);
setDate(dateStr: string) {
this.date.writeValue(dateStr);
this.date().writeValue(dateStr);
}
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,
SimpleChanges,
SkipSelf,
ViewChild,
signal,
effect,
viewChild
} from '@angular/core';
import {
ControlContainer,
@ -98,7 +98,7 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
@Input() prop!: FormProp;
@Input() first?: boolean;
@Input() isFirstGroup?: boolean;
@ViewChild('field') private fieldRef!: ElementRef<HTMLElement>;
private readonly fieldRef = viewChild.required<ElementRef<HTMLElement>>('field');
injectorForCustomComponent?: Injector;
asterisk = '';
@ -158,9 +158,9 @@ export class ExtensibleFormPropComponent implements OnChanges, AfterViewInit {
}
ngAfterViewInit() {
if (this.isFirstGroup && this.first && this.fieldRef) {
if (this.isFirstGroup && this.first && this.fieldRef()) {
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,
Input,
Optional,
QueryList,
SkipSelf,
ViewChildren,
viewChildren
} from '@angular/core';
import { ControlContainer, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms';
import { EXTRA_PROPERTIES_KEY } from '../../constants/extra-properties';
@ -41,8 +40,7 @@ export class ExtensibleFormComponent<R = any> {
private readonly extensions = inject(ExtensionsService);
private readonly identifier = inject(EXTENSIONS_IDENTIFIER);
@ViewChildren(ExtensibleFormPropComponent)
formProps!: QueryList<ExtensibleFormPropComponent>;
readonly formProps = viewChildren(ExtensibleFormPropComponent);
@Input()
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,
Component,
computed,
ContentChild,
EventEmitter,
inject,
Injector,
@ -18,7 +17,8 @@ import {
SimpleChanges,
TemplateRef,
TrackByFunction,
ViewChild,
contentChild,
viewChild
} from '@angular/core';
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%';
@Output() rowDetailToggle = new EventEmitter<R>();
@ContentChild(ExtensibleTableRowDetailComponent)
rowDetailComponent?: ExtensibleTableRowDetailComponent<R>;
readonly rowDetailComponent = contentChild(ExtensibleTableRowDetailComponent);
@ViewChild('table', { static: false }) table!: DatatableComponent;
readonly table = viewChild.required<DatatableComponent>('table');
protected get effectiveRowDetailTemplate(): TemplateRef<RowDetailContext<R>> | undefined {
return this.rowDetailComponent?.template() ?? this.rowDetailTemplate;
return this.rowDetailComponent()?.template() ?? this.rowDetailTemplate;
}
protected get effectiveRowDetailHeight(): string | number {
return this.rowDetailComponent?.rowHeight() ?? this.rowDetailHeight;
return this.rowDetailComponent()?.rowHeight() ?? this.rowDetailHeight;
}
hasAtLeastOnePermittedAction: boolean;
@ -318,8 +317,9 @@ export class ExtensibleTableComponent<R = any> implements OnChanges, AfterViewIn
}
toggleExpandRow(row: R): void {
if (this.table && this.table.rowDetail) {
this.table.rowDetail.toggleExpandRow(row);
const table = this.table();
if (table && table.rowDetail) {
table.rowDetail.toggleExpandRow(row);
}
this.rowDetailToggle.emit(row);
}

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

@ -1,6 +1,6 @@
@if (shouldRenderRow) {
<div class="row entry-row">
@if (customTitle) {
@if (customTitle()) {
<ng-content select="abp-page-title-container"></ng-content>
} @else {
@if (title) {
@ -12,7 +12,7 @@
}
}
@if (customBreadcrumb) {
@if (customBreadcrumb()) {
<ng-content select="abp-page-breadcrumb-container"></ng-content>
} @else {
@if (breadcrumb) {
@ -22,7 +22,7 @@
}
}
@if (customToolbar) {
@if (customToolbar()) {
<ng-content select="abp-page-toolbar-container"></ng-content>
} @else {
@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 {
PageTitleContainerComponent,
PageBreadcrumbContainerComponent,
@ -37,19 +37,18 @@ export class PageComponent {
toolbar: PageParts.toolbar,
};
@ContentChild(PageTitleContainerComponent) customTitle?: PageTitleContainerComponent;
@ContentChild(PageBreadcrumbContainerComponent)
customBreadcrumb?: PageBreadcrumbContainerComponent;
@ContentChild(PageToolbarContainerComponent) customToolbar?: PageToolbarContainerComponent;
readonly customTitle = contentChild(PageTitleContainerComponent);
readonly customBreadcrumb = contentChild(PageBreadcrumbContainerComponent);
readonly customToolbar = contentChild(PageToolbarContainerComponent);
get shouldRenderRow() {
return !!(
this.title ||
this.toolbarVisible ||
this.breadcrumb ||
this.customTitle ||
this.customBreadcrumb ||
this.customToolbar ||
this.customTitle() ||
this.customBreadcrumb() ||
this.customToolbar() ||
this.pageParts
);
}

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

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

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

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

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

@ -11,10 +11,9 @@ import {
ElementRef,
inject,
Input,
QueryList,
Renderer2,
TrackByFunction,
ViewChildren,
viewChildren
} from '@angular/core';
import { NgTemplateOutlet, AsyncPipe } from '@angular/common';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
@ -41,7 +40,7 @@ export class RoutesComponent {
@Input() smallScreen?: boolean;
@ViewChildren('childrenContainer') childrenContainers!: QueryList<ElementRef<HTMLDivElement>>;
readonly childrenContainers = viewChildren<ElementRef<HTMLDivElement>>('childrenContainer');
rootDropdownExpand = {} as { [key: string]: boolean };
@ -52,7 +51,7 @@ export class RoutesComponent {
}
closeDropdown() {
this.childrenContainers.forEach(({ nativeElement }) => {
this.childrenContainers().forEach(({ nativeElement }) => {
this.renderer.addClass(nativeElement, 'd-none');
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,
Output,
Renderer2,
ViewChild,
inject,
viewChild
} from '@angular/core';
import { ABP, StopPropagationDirective } from '@abp/ng.core';
@ -70,8 +70,7 @@ export class ButtonComponent implements OnInit {
@Output() readonly abpBlur = new EventEmitter<FocusEvent>();
@ViewChild('button', { static: true })
buttonRef!: ElementRef<HTMLButtonElement>;
readonly buttonRef = viewChild.required<ElementRef<HTMLButtonElement>>('button');
get icon(): string {
return `${this.loading ? 'fa fa-spinner fa-spin' : this.iconClass || 'd-none'}`;
@ -81,7 +80,7 @@ export class ButtonComponent implements OnInit {
if (this.attributes) {
Object.keys(this.attributes).forEach(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,
EmbeddedViewRef,
Type,
ViewChild,
AfterViewInit,
OnDestroy,
createComponent,
EnvironmentInjector,
DestroyRef,
viewChild
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DOCUMENT } from '@angular/common';
@ -53,8 +53,7 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr
isHomeShow = true;
@ViewChild('container', { static: false })
containerRef?: ElementRef<HTMLDivElement>;
readonly containerRef = viewChild<ElementRef<HTMLDivElement>>('container');
get statusText(): string {
return this.status ? `[${this.status}]` : '';
@ -86,8 +85,9 @@ export class HttpErrorWrapperComponent implements OnInit, AfterViewInit, OnDestr
this.appRef.attachView(customComponentRef.hostView);
if (this.containerRef) {
this.containerRef.nativeElement.appendChild(
const containerRef = this.containerRef();
if (containerRef) {
containerRef.nativeElement.appendChild(
(customComponentRef.hostView as EmbeddedViewRef<any>).rootNodes[0],
);
}

Loading…
Cancel
Save