diff --git a/goldens/cdk/dialog/index.api.md b/goldens/cdk/dialog/index.api.md index 3a84074f0660..2a30553833d1 100644 --- a/goldens/cdk/dialog/index.api.md +++ b/goldens/cdk/dialog/index.api.md @@ -120,6 +120,7 @@ export class DialogConfig { ariaModal?: boolean; autoFocus?: AutoFocusTarget | string | boolean; backdropClass?: string; + bindings?: Binding[]; closeOnNavigation?: boolean; data?: D | null; direction?: Direction; diff --git a/goldens/material/dialog/index.api.md b/goldens/material/dialog/index.api.md index bff4cccabb64..95b45db02dc8 100644 --- a/goldens/material/dialog/index.api.md +++ b/goldens/material/dialog/index.api.md @@ -4,6 +4,7 @@ ```ts +import { Binding } from '@angular/core'; import { CdkDialogContainer } from '@angular/cdk/dialog'; import { ComponentPortal } from '@angular/cdk/portal'; import { ComponentRef } from '@angular/core'; @@ -125,6 +126,7 @@ export class MatDialogConfig { ariaModal?: boolean; autoFocus?: AutoFocusTarget | string | boolean; backdropClass?: string | string[]; + bindings?: Binding[]; closeOnNavigation?: boolean; closePredicate?: (result: Result | undefined, config: Config, componentInstance: Component | null) => boolean; data?: D | null; diff --git a/goldens/material/dialog/testing/index.api.md b/goldens/material/dialog/testing/index.api.md index 5ee65ad0b2aa..b9220f42762c 100644 --- a/goldens/material/dialog/testing/index.api.md +++ b/goldens/material/dialog/testing/index.api.md @@ -6,6 +6,7 @@ import * as _angular_cdk_testing from '@angular/cdk/testing'; import { BaseHarnessFilters } from '@angular/cdk/testing'; +import { Binding } from '@angular/core'; import { CdkDialogContainer } from '@angular/cdk/dialog'; import { ComponentHarnessConstructor } from '@angular/cdk/testing'; import { ComponentPortal } from '@angular/cdk/portal'; diff --git a/src/cdk/dialog/dialog-config.ts b/src/cdk/dialog/dialog-config.ts index 00833da2f21c..345238760497 100644 --- a/src/cdk/dialog/dialog-config.ts +++ b/src/cdk/dialog/dialog-config.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {ViewContainerRef, Injector, StaticProvider, Type} from '@angular/core'; +import {ViewContainerRef, Injector, StaticProvider, Type, Binding} from '@angular/core'; import {Direction} from '../bidi'; import {PositionStrategy, ScrollStrategy} from '../overlay'; import {Observable} from 'rxjs'; @@ -191,4 +191,10 @@ export class DialogConfig | (() => Record); + + /** + * Bindings to apply to the component rendered inside the dialog. + * Does nothing for template-based dialogs. + */ + bindings?: Binding[]; } diff --git a/src/cdk/dialog/dialog.spec.ts b/src/cdk/dialog/dialog.spec.ts index 1884b0e946f6..ddcf52f520da 100644 --- a/src/cdk/dialog/dialog.spec.ts +++ b/src/cdk/dialog/dialog.spec.ts @@ -17,11 +17,13 @@ import { Directive, InjectionToken, Injector, + Input, TemplateRef, ViewChild, ViewContainerRef, ViewEncapsulation, inject, + inputBinding, } from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; @@ -606,6 +608,15 @@ describe('Dialog', () => { expect(dialogRef.componentInstance!.data).toBeNull(); }).not.toThrow(); }); + + it('should be able to apply bindings', () => { + const dialogRef = dialog.open(PizzaMsg, { + bindings: [inputBinding('flavor', () => 'pepperoni')], + }); + viewContainerFixture.detectChanges(); + + expect(dialogRef.componentInstance!.flavor).toBe('pepperoni'); + }); }); it('should not keep a reference to the component after the dialog is closed', () => { @@ -1364,6 +1375,7 @@ class ComponentWithTemplateRef { changeDetection: ChangeDetectionStrategy.Eager, }) class PizzaMsg { + @Input() flavor = 'unknown'; dialogRef = inject>(DialogRef); dialogInjector = inject(Injector); directionality = inject(Directionality); diff --git a/src/cdk/dialog/dialog.ts b/src/cdk/dialog/dialog.ts index 41a3cfde4051..7c67e769399f 100644 --- a/src/cdk/dialog/dialog.ts +++ b/src/cdk/dialog/dialog.ts @@ -302,7 +302,13 @@ export class Dialog implements OnDestroy { } else { const injector = this._createInjector(config, dialogRef, dialogContainer, this._injector); const contentRef = dialogContainer.attachComponentPortal( - new ComponentPortal(componentOrTemplateRef, config.viewContainerRef, injector), + new ComponentPortal( + componentOrTemplateRef, + config.viewContainerRef, + injector, + null, + config.bindings, + ), ); (dialogRef as {componentRef: ComponentRef}).componentRef = contentRef; (dialogRef as {componentInstance: C}).componentInstance = contentRef.instance; diff --git a/src/material/bottom-sheet/bottom-sheet-config.ts b/src/material/bottom-sheet/bottom-sheet-config.ts index 123d166b4c03..dd7b6e5fc737 100644 --- a/src/material/bottom-sheet/bottom-sheet-config.ts +++ b/src/material/bottom-sheet/bottom-sheet-config.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {InjectionToken, Injector, ViewContainerRef} from '@angular/core'; +import {Binding, InjectionToken, Injector, ViewContainerRef} from '@angular/core'; import {Direction} from '@angular/cdk/bidi'; import {ScrollStrategy} from '@angular/cdk/overlay'; import {RestoreFocusValue} from '@angular/cdk/dialog'; @@ -86,4 +86,10 @@ export class MatBottomSheetConfig { /** Maximum height for the bottom sheet. If a number is provided, assumes pixel units. */ maxHeight?: number | string; + + /** + * Bindings to apply to the component rendered inside the dialog. + * Does nothing for template-based dialogs. + */ + bindings?: Binding[]; } diff --git a/src/material/bottom-sheet/bottom-sheet.spec.ts b/src/material/bottom-sheet/bottom-sheet.spec.ts index 8063fc4d5340..e9cf9d5cbe01 100644 --- a/src/material/bottom-sheet/bottom-sheet.spec.ts +++ b/src/material/bottom-sheet/bottom-sheet.spec.ts @@ -17,6 +17,7 @@ import { Directive, Injectable, Injector, + Input, NgModule, TemplateRef, ViewChild, @@ -24,6 +25,7 @@ import { ViewEncapsulation, forwardRef, inject, + inputBinding, ChangeDetectionStrategy, } from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; @@ -506,6 +508,15 @@ describe('MatBottomSheet', () => { expect(bottomSheetRef.instance.data).toBeNull(); }).not.toThrow(); }); + + it('should be able to apply bindings', () => { + const bottomSheetRef = bottomSheet.open(PizzaMsg, { + bindings: [inputBinding('flavor', () => 'pepperoni')], + }); + viewContainerFixture.detectChanges(); + + expect(bottomSheetRef.instance.flavor).toBe('pepperoni'); + }); }); describe('disableClose option', () => { @@ -1055,6 +1066,7 @@ class ComponentWithTemplateRef { changeDetection: ChangeDetectionStrategy.Eager, }) class PizzaMsg { + @Input() flavor = 'unknown'; bottomSheetRef = inject>(MatBottomSheetRef); injector = inject(Injector); directionality = inject(Directionality); diff --git a/src/material/dialog/dialog-config.ts b/src/material/dialog/dialog-config.ts index 899e0e1a58ce..0ebf4ee37b68 100644 --- a/src/material/dialog/dialog-config.ts +++ b/src/material/dialog/dialog-config.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.dev/license */ -import {ViewContainerRef, Injector} from '@angular/core'; +import {ViewContainerRef, Injector, Binding} from '@angular/core'; import {Direction} from '@angular/cdk/bidi'; import {ScrollStrategy} from '@angular/cdk/overlay'; import {DialogConfig, RestoreFocusValue} from '@angular/cdk/dialog'; @@ -159,5 +159,9 @@ export class MatDialogConfig { */ exitAnimationDuration?: string | number; - // TODO(jelbourn): add configuration for lifecycle hooks, ARIA labelling. + /** + * Bindings to apply to the component rendered inside the dialog. + * Does nothing for template-based dialogs. + */ + bindings?: Binding[]; } diff --git a/src/material/dialog/dialog.spec.ts b/src/material/dialog/dialog.spec.ts index 665f8fa43085..2279305fcf8e 100644 --- a/src/material/dialog/dialog.spec.ts +++ b/src/material/dialog/dialog.spec.ts @@ -20,6 +20,7 @@ import { Directive, Injectable, Injector, + Input, NgModule, TemplateRef, ViewChild, @@ -28,6 +29,7 @@ import { forwardRef, signal, inject, + inputBinding, } from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; @@ -736,6 +738,15 @@ describe('MatDialog', () => { expect(dialogRef.componentInstance.data).toBeNull(); }).not.toThrow(); }); + + it('should be able to apply bindings', () => { + const dialogRef = dialog.open(PizzaMsg, { + bindings: [inputBinding('flavor', () => 'pepperoni')], + }); + viewContainerFixture.detectChanges(); + + expect(dialogRef.componentInstance!.flavor).toBe('pepperoni'); + }); }); it('should not keep a reference to the component after the dialog is closed', async () => { @@ -2340,6 +2351,7 @@ class ComponentWithTemplateRef { changeDetection: ChangeDetectionStrategy.Eager, }) class PizzaMsg { + @Input() flavor = 'unknown'; dialogRef = inject>(MatDialogRef); dialogInjector = inject(Injector); directionality = inject(Directionality);