My scenario is, I have a dialog, which is opened through a signal, but I want to trigger this dialog to open, across my application. The obvious way is to create a DialogService
(providedIn: 'root'
) and store the signal there, but is there a more lightweight way to achieve the same.
@if(showDialog()) {
<kendo-dialog
title="sometitle"
>
some text
</kendo-dialog>
}
@Component({ ... })
export class DialogComponent {
showDialog = signal(false); // <-- I want to share this signal, across multiple components.
}
Version is Angular 19 but am ok with something that is backwards compatible also.
For this solution you can look at the source code of angular.dev
, they have a search popup (for searching documentation), this dialog component is opened/closed, from a signal, that is actually provided using an InjectionToken
(providedIn: 'root'
-> provided throughout the application), this token, thanks to Dependency injection can be shared across components easily and the dialog can be opened from anywhere.
app.component.ts - Adev folder angular Github Source Code Reference
Below is how we define a injection token signal:
export const DIALOG_OPEN = new InjectionToken('DIALOG_OPEN', {
providedIn: 'root',
factory: () => signal(false),
});
Then we define the DialogCustomComponent
to open based on this DI token.
@Component({
selector: 'app-dialog',
imports: [DialogComponent, DialogActionsComponent],
template: `
@if(opened()) {
<kendo-dialog title="Oh no!" (close)="close()">
<p style="margin: 30px; text-align: center;">Dialog was opened.</p>
<kendo-dialog-actions>
<button kendoButton (click)="close()" themeColor="primary">
Close
</button>
</kendo-dialog-actions>
</kendo-dialog>
}
`,
})
export class DialogCustomComponent {
opened: WritableSignal<boolean> = inject(DIALOG_OPEN);
close() {
this.opened.update((prev: boolean) => !prev);
}
}
For example, if we want to open the dialog, from the root component, just inject the token and toggle it for the dialog to open.
@Component({
selector: 'my-app',
template: `
<button kendoButton (click)="open()">Show Dialog</button>
<button kendoButton (click)="close()">Close Dialog</button>
<app-dialog/>
`,
standalone: false,
})
export class AppComponent {
opened: WritableSignal<boolean> = inject(DIALOG_OPEN);
public close(): void {
this.opened.set(false);
}
public open(): void {
this.opened.set(true);
}
}
import {
Component,
inject,
InjectionToken,
signal,
WritableSignal,
} from '@angular/core';
import {
DialogComponent,
DialogActionsComponent,
} from '@progress/kendo-angular-dialog';
export const DIALOG_OPEN = new InjectionToken('DIALOG_OPEN', {
providedIn: 'root',
factory: () => signal(false),
});
@Component({
selector: 'app-dialog',
imports: [DialogComponent, DialogActionsComponent],
template: `
@if(opened()) {
<kendo-dialog title="Oh no!" (close)="close()">
<p style="margin: 30px; text-align: center;">Dialog was opened.</p>
<kendo-dialog-actions>
<button kendoButton (click)="close()" themeColor="primary">
Close
</button>
</kendo-dialog-actions>
</kendo-dialog>
}
`,
})
export class DialogCustomComponent {
opened: WritableSignal<boolean> = inject(DIALOG_OPEN);
close() {
this.opened.update((prev: boolean) => !prev);
}
}
@Component({
selector: 'my-app',
template: `
<button kendoButton (click)="open()">Show Dialog</button>
<button kendoButton (click)="close()">Close Dialog</button>
<app-dialog/>
`,
standalone: false,
})
export class AppComponent {
opened: WritableSignal<boolean> = inject(DIALOG_OPEN);
public close(): void {
this.opened.set(false);
}
public open(): void {
this.opened.set(true);
}
}