Browse Source

Merge pull request #24765 from abpframework/issue-24672-v2

feat(angular): Migrate to signal queries
MaxTypeFullNameLength
sumeyye 2 days ago
committed by GitHub
parent
commit
7ea4465ef9
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  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. 14
      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. 8
      npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html
  10. 8
      npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts
  11. 5
      npm/ng-packs/packages/identity/src/lib/components/users/users.component.ts
  12. 24
      npm/ng-packs/packages/permission-management/src/lib/components/permission-management.component.ts
  13. 7
      npm/ng-packs/packages/theme-basic/src/lib/components/routes/routes.component.ts
  14. 7
      npm/ng-packs/packages/theme-shared/src/lib/components/button/button.component.ts
  15. 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);
}
}

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

@ -19,9 +19,7 @@ import {
Optional,
SimpleChanges,
SkipSelf,
ViewChild,
signal,
effect,
viewChild,
} from '@angular/core';
import {
ControlContainer,
@ -72,8 +70,8 @@ import { ExtensibleFormMultiselectComponent } from '../multi-select/extensible-f
AsyncPipe,
NgComponentOutlet,
NgTemplateOutlet,
FormsModule
],
FormsModule,
],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [ExtensibleFormPropService],
viewProviders: [
@ -98,7 +96,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 +156,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
);
}

8
npm/ng-packs/packages/components/tree/src/lib/components/tree.component.html

@ -7,7 +7,7 @@
[nzData]="nodes"
[nzTreeTemplate]="treeTemplate"
[nzExpandedKeys]="expandedKeys"
[nzExpandedIcon]="expandedIconTemplate?.template || defaultIconTemplate"
[nzExpandedIcon]="expandedIconTemplate()?.template || defaultIconTemplate"
(nzExpandChange)="onExpandedKeysChange($event)"
(nzCheckboxChange)="onCheckboxChange($event)"
(nzOnDrop)="onDrop($event)"
@ -26,13 +26,13 @@
<div class="d-inline-flex align-items-center abp-ellipsis-inline">
<ng-container
*ngTemplateOutlet="
customNodeTemplate ? customNodeTemplate?.template : defaultNodeTemplate;
customNodeTemplate() ? customNodeTemplate()?.template : defaultNodeTemplate;
context: { $implicit: node }
"
/>
</div>
@if (menu) {
@if (menu()) {
<div
#dropdown="ngbDropdown"
class="d-inline-block ms-1"
@ -48,7 +48,7 @@
aria-hidden="true"
></i>
<div ngbDropdownMenu>
<ng-template *ngTemplateOutlet="menu; context: { $implicit: node }" />
<ng-template *ngTemplateOutlet="menu(); context: { $implicit: node }" />
</div>
</div>
}

8
npm/ng-packs/packages/components/tree/src/lib/components/tree.component.ts

@ -2,7 +2,7 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild,
contentChild,
EventEmitter,
inject,
Input,
@ -60,9 +60,9 @@ export class TreeComponent implements OnInit {
dropdowns = {} as { [key: string]: NgbDropdown };
@ContentChild('menu') menu: TemplateRef<any>;
@ContentChild(TreeNodeTemplateDirective) customNodeTemplate: TreeNodeTemplateDirective;
@ContentChild(ExpandedIconTemplateDirective) expandedIconTemplate: ExpandedIconTemplateDirective;
readonly menu = contentChild<TemplateRef<any>>('menu');
readonly customNodeTemplate = contentChild(TreeNodeTemplateDirective);
readonly expandedIconTemplate = contentChild(ExpandedIconTemplateDirective);
@Output() readonly checkedKeysChange = new EventEmitter();
@Output() readonly expandedKeysChange = new EventEmitter<string[]>();
@Output() readonly selectedNodeChange = new EventEmitter();

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