Skip to content

Commit

Permalink
fix(workbench/dialog): enable updating dialog properties in an Angula…
Browse files Browse the repository at this point in the history
…r effect

Dialog properties (title, closable, size, ...) can now be set in an Angular effect without having to enable `allowSignalWrites`.
  • Loading branch information
danielwiehl authored and Marcarrian committed Oct 11, 2024
1 parent a7d3594 commit 7da2418
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 14 deletions.
95 changes: 94 additions & 1 deletion projects/scion/workbench/src/lib/dialog/dialog.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {toShowCustomMatcher} from '../testing/jasmine/matcher/to-show.matcher';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {styleFixture, waitForInitialWorkbenchLayout, waitUntilStable} from '../testing/testing.util';
import {Component, DestroyRef, EnvironmentInjector, inject, InjectionToken, Injector, Type} from '@angular/core';
import {booleanAttribute, Component, DestroyRef, effect, EnvironmentInjector, inject, InjectionToken, Injector, input, Type} from '@angular/core';
import {expect} from '../testing/jasmine/matcher/custom-matchers.definition';
import {provideWorkbenchForTest} from '../testing/workbench.provider';
import {WorkbenchDialogService} from './workbench-dialog.service';
Expand Down Expand Up @@ -352,6 +352,99 @@ describe('Dialog', () => {
// Expect not to throw `ExpressionChangedAfterItHasBeenCheckedError`.
expect(errors).not.toContain(jasmine.stringMatching(`ExpressionChangedAfterItHasBeenCheckedError`));
});

it('should allow updating dialog properties in an effect (without enabling `allowSignalWrites`)', async () => {
TestBed.configureTestingModule({
providers: [provideWorkbenchForTest()],
});

@Component({
selector: 'spec-dialog',
template: 'dialog',
standalone: true,
})
class SpecDialogComponent {

public title = input<string>();
public padding = input(undefined, {transform: booleanAttribute});
public closable = input(undefined, {transform: booleanAttribute});
public resizable = input(undefined, {transform: booleanAttribute});
public cssClass = input<string>();
public minWidth = input<string>();
public width = input<string>();
public maxWidth = input<string>();
public minHeight = input<string>();
public height = input<string>();
public maxHeight = input<string>();

constructor(dialog: WorkbenchDialog) {
effect(() => {
dialog.title = this.title();
dialog.padding = this.padding() ?? true;
dialog.closable = this.closable() ?? true;
dialog.resizable = this.resizable() ?? true;
dialog.cssClass = this.cssClass() ?? [];
dialog.size.minWidth = this.minWidth();
dialog.size.width = this.width();
dialog.size.maxWidth = this.maxWidth();
dialog.size.minHeight = this.minHeight();
dialog.size.height = this.height();
dialog.size.maxHeight = this.maxHeight();
});
}
}

styleFixture(TestBed.createComponent(WorkbenchComponent));
await waitForInitialWorkbenchLayout();

const workbenchDialogService = TestBed.inject(WorkbenchDialogService);

// Set title.
workbenchDialogService.open(SpecDialogComponent, {cssClass: 'testee', inputs: {title: 'TITLE'}}).then();
await waitUntilStable();
expect(getDialog({cssClass: 'testee'}).title()).toEqual('TITLE');
getDialog({cssClass: 'testee'}).close();

// Set padding.
workbenchDialogService.open(SpecDialogComponent, {cssClass: 'testee', inputs: {padding: false}}).then();
await waitUntilStable();
expect(getDialog({cssClass: 'testee'}).padding()).toBeFalse();
getDialog({cssClass: 'testee'}).close();

// Set closable.
workbenchDialogService.open(SpecDialogComponent, {cssClass: 'testee', inputs: {closable: false}}).then();
await waitUntilStable();
expect(getDialog({cssClass: 'testee'}).closable()).toBeFalse();
getDialog({cssClass: 'testee'}).close();

// Set resizable.
workbenchDialogService.open(SpecDialogComponent, {cssClass: 'testee', inputs: {resizable: false}}).then();
await waitUntilStable();
expect(getDialog({cssClass: 'testee'}).resizable()).toBeFalse();
getDialog({cssClass: 'testee'}).close();

// Set CSS class.
workbenchDialogService.open(SpecDialogComponent, {cssClass: 'testee', inputs: {cssClass: 'cssclass'}}).then();
await waitUntilStable();
expect(getDialog({cssClass: 'testee'}).cssClass()).toContain('cssclass');
getDialog({cssClass: 'testee'}).close();

// Set size (width).
workbenchDialogService.open(SpecDialogComponent, {cssClass: 'testee', inputs: {minWidth: '100px', width: '200px', maxWidth: '300px'}}).then();
await waitUntilStable();
expect(getDialog({cssClass: 'testee'}).size.minWidth()).toEqual('100px');
expect(getDialog({cssClass: 'testee'}).size.width()).toEqual('200px');
expect(getDialog({cssClass: 'testee'}).size.maxWidth()).toEqual('300px');
getDialog({cssClass: 'testee'}).close();

// Set size (height).
workbenchDialogService.open(SpecDialogComponent, {cssClass: 'testee', inputs: {minHeight: '100px', height: '200px', maxHeight: '300px'}}).then();
await waitUntilStable();
expect(getDialog({cssClass: 'testee'}).size.minHeight()).toEqual('100px');
expect(getDialog({cssClass: 'testee'}).size.height()).toEqual('200px');
expect(getDialog({cssClass: 'testee'}).size.maxHeight()).toEqual('300px');
getDialog({cssClass: 'testee'}).close();
});
});

function getDialog(locator: {cssClass: string}): ɵWorkbenchDialog {
Expand Down
14 changes: 7 additions & 7 deletions projects/scion/workbench/src/lib/dialog/workbench-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* SPDX-License-Identifier: EPL-2.0
*/

import {signal, Signal} from '@angular/core';
import {signal, Signal, untracked} from '@angular/core';

/**
* Handle to interact with a dialog opened via {@link WorkbenchDialogService}.
Expand Down Expand Up @@ -131,7 +131,7 @@ export class ɵWorkbenchDialogSize implements WorkbenchDialogSize {

/** @inheritDoc */
public set minHeight(minHeight: string | undefined) {
this._minHeight.set(minHeight);
untracked(() => this._minHeight.set(minHeight));
}

/** @inheritDoc */
Expand All @@ -141,7 +141,7 @@ export class ɵWorkbenchDialogSize implements WorkbenchDialogSize {

/** @inheritDoc */
public set height(height: string | undefined) {
this._height.set(height);
untracked(() => this._height.set(height));
}

/** @inheritDoc */
Expand All @@ -151,7 +151,7 @@ export class ɵWorkbenchDialogSize implements WorkbenchDialogSize {

/** @inheritDoc */
public set maxHeight(maxHeight: string | undefined) {
this._maxHeight.set(maxHeight);
untracked(() => this._maxHeight.set(maxHeight));
}

/** @inheritDoc */
Expand All @@ -161,7 +161,7 @@ export class ɵWorkbenchDialogSize implements WorkbenchDialogSize {

/** @inheritDoc */
public set minWidth(minWidth: string | undefined) {
this._minWidth.set(minWidth);
untracked(() => this._minWidth.set(minWidth));
}

/** @inheritDoc */
Expand All @@ -171,7 +171,7 @@ export class ɵWorkbenchDialogSize implements WorkbenchDialogSize {

/** @inheritDoc */
public set width(width: string | undefined) {
this._width.set(width);
untracked(() => this._width.set(width));
}

/** @inheritDoc */
Expand All @@ -181,6 +181,6 @@ export class ɵWorkbenchDialogSize implements WorkbenchDialogSize {

/** @inheritDoc */
public set maxWidth(maxWidth: string | undefined) {
this._maxWidth.set(maxWidth);
untracked(() => this._maxWidth.set(maxWidth));
}
}
12 changes: 6 additions & 6 deletions projects/scion/workbench/src/lib/dialog/ɵworkbench-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
*/

import {BehaviorSubject, combineLatest, concatWith, delay, EMPTY, firstValueFrom, map, merge, Observable, of, Subject, switchMap} from 'rxjs';
import {ApplicationRef, ComponentRef, EnvironmentInjector, inject, Injector, NgZone, Signal, signal} from '@angular/core';
import {ApplicationRef, ComponentRef, EnvironmentInjector, inject, Injector, NgZone, Signal, signal, untracked} from '@angular/core';
import {WorkbenchDialog, WorkbenchDialogSize, ɵWorkbenchDialogSize} from './workbench-dialog';
import {WorkbenchDialogOptions} from './workbench-dialog.options';
import {ComponentPortal, ComponentType} from '@angular/cdk/portal';
Expand Down Expand Up @@ -182,7 +182,7 @@ export class ɵWorkbenchDialog<R = unknown> implements WorkbenchDialog<R>, Block

/** @inheritDoc */
public set title(title: string | undefined) {
this._title.set(title);
untracked(() => this._title.set(title));
}

/** @inheritDoc */
Expand All @@ -192,7 +192,7 @@ export class ɵWorkbenchDialog<R = unknown> implements WorkbenchDialog<R>, Block

/** @inheritDoc */
public set closable(closable: boolean) {
this._closable.set(closable);
untracked(() => this._closable.set(closable));
}

/** @inheritDoc */
Expand All @@ -202,7 +202,7 @@ export class ɵWorkbenchDialog<R = unknown> implements WorkbenchDialog<R>, Block

/** @inheritDoc */
public set resizable(resizable: boolean) {
this._resizable.set(resizable);
untracked(() => this._resizable.set(resizable));
}

/** @inheritDoc */
Expand All @@ -212,7 +212,7 @@ export class ɵWorkbenchDialog<R = unknown> implements WorkbenchDialog<R>, Block

/** @inheritDoc */
public set padding(padding: boolean) {
this._padding.set(padding);
untracked(() => this._padding.set(padding));
}

/** @inheritDoc */
Expand All @@ -222,7 +222,7 @@ export class ɵWorkbenchDialog<R = unknown> implements WorkbenchDialog<R>, Block

/** @inheritDoc */
public set cssClass(cssClass: string | string[]) {
this._cssClass.set(new Array<string>().concat(this._options.cssClass ?? []).concat(cssClass));
untracked(() => this._cssClass.set(new Array<string>().concat(this._options.cssClass ?? []).concat(cssClass)));
}

/**
Expand Down

0 comments on commit 7da2418

Please sign in to comment.