diff --git a/packages/common/src/directives/ng_optimized_image/ng_optimized_image.ts b/packages/common/src/directives/ng_optimized_image/ng_optimized_image.ts
index e7e57482d1b..2f71a4d48a5 100644
--- a/packages/common/src/directives/ng_optimized_image/ng_optimized_image.ts
+++ b/packages/common/src/directives/ng_optimized_image/ng_optimized_image.ts
@@ -439,8 +439,17 @@ export class NgOptimizedImage implements OnInit, OnChanges, OnDestroy {
/** @nodoc */
ngOnChanges(changes: SimpleChanges) {
if (ngDevMode) {
- assertNoPostInitInputChange(
- this, changes, ['ngSrc', 'ngSrcset', 'width', 'height', 'priority']);
+ assertNoPostInitInputChange(this, changes, [
+ 'ngSrc',
+ 'ngSrcset',
+ 'width',
+ 'height',
+ 'priority',
+ 'fill',
+ 'loading',
+ 'sizes',
+ 'disableOptimizedSrcset',
+ ]);
}
}
@@ -687,12 +696,20 @@ function assertUnderDensityCap(dir: NgOptimizedImage, value: string) {
* the directive has initialized.
*/
function postInitInputChangeError(dir: NgOptimizedImage, inputName: string): {} {
+ let reason!: string;
+ if (inputName === 'width' || inputName === 'height') {
+ reason = `Changing \`${inputName}\` may result in different attribute value ` +
+ `applied to the underlying image element and cause layout shifts on a page.`;
+ } else {
+ reason = `Changing the \`${inputName}\` would have no effect on the underlying ` +
+ `image element, because the resource loading has already occurred.`;
+ }
return new RuntimeError(
RuntimeErrorCode.UNEXPECTED_INPUT_CHANGE,
`${imgDirectiveDetails(dir.ngSrc)} \`${inputName}\` was updated after initialization. ` +
- `The NgOptimizedImage directive will not react to this input change. ` +
- `To fix this, switch \`${inputName}\` a static value or wrap the image element ` +
- `in an *ngIf that is gated on the necessary value.`);
+ `The NgOptimizedImage directive will not react to this input change. ${reason} ` +
+ `To fix this, either switch \`${inputName}\` to a static value ` +
+ `or wrap the image element in an *ngIf that is gated on the necessary value.`);
}
/**
diff --git a/packages/common/test/directives/ng_optimized_image_spec.ts b/packages/common/test/directives/ng_optimized_image_spec.ts
index 52185ef5c66..572d33057c4 100644
--- a/packages/common/test/directives/ng_optimized_image_spec.ts
+++ b/packages/common/test/directives/ng_optimized_image_spec.ts
@@ -641,34 +641,58 @@ describe('Image directive', () => {
});
const inputs = [
- ['ngSrc', 'new-img.png'], //
- ['width', 10], //
- ['height', 20], //
- ['priority', true]
+ ['ngSrc', 'new-img.png'],
+ ['width', 10],
+ ['height', 20],
+ ['priority', true],
+ ['fill', true],
+ ['loading', true],
+ ['sizes', '90vw'],
+ ['disableOptimizedSrcset', true],
];
inputs.forEach(([inputName, value]) => {
- it(`should throw if an input changed after directive initialized the input`, () => {
- setupTestingModule();
+ it(`should throw if the \`${inputName}\` input changed after directive initialized the input`,
+ () => {
+ @Component({
+ selector: 'test-cmp',
+ template: `
`
+ })
+ class TestComponent {
+ width = 100;
+ height = 50;
+ ngSrc = 'img.png';
+ priority = false;
+ fill = false;
+ loading = false;
+ sizes = '100vw';
+ disableOptimizedSrcset = false;
+ }
- const template =
- '
';
- // Initial render
- const fixture = createTestComponent(template);
- fixture.detectChanges();
+ setupTestingModule({component: TestComponent});
- expect(() => {
- // Update input (expect to throw)
- (fixture.componentInstance as unknown as {[key: string]: unknown})[inputName as string] =
- value;
- fixture.detectChanges();
- })
- .toThrowError(
- 'NG02953: The NgOptimizedImage directive (activated on an
element ' +
- `with the \`ngSrc="img.png"\`) has detected that \`${inputName}\` was updated ` +
- 'after initialization. The NgOptimizedImage directive will not react ' +
- `to this input change. To fix this, switch \`${inputName}\` a static value or ` +
- 'wrap the image element in an *ngIf that is gated on the necessary value.');
- });
+ // Initial render
+ const fixture = TestBed.createComponent(TestComponent);
+ fixture.detectChanges();
+
+ const expectedErrorMessage = //
+ `NG02953: The NgOptimizedImage directive (.*)? ` +
+ `has detected that \`${inputName}\` was updated after initialization`;
+ expect(() => {
+ // Update input (expect to throw)
+ (fixture.componentInstance as unknown as
+ {[key: string]: unknown})[inputName as string] = value;
+ fixture.detectChanges();
+ }).toThrowError(new RegExp(expectedErrorMessage));
+ });
});
});