Skip to content

Commit 7096246

Browse files
mheverythePunderWoman
authored andcommitted
fix(core): Switch emitDistinctChangesOnlyDefaultValue to true (#41121)
BREAKING CHANGE: Switching default of `emitDistinctChangesOnlyDefaultValue` which changes the default behavior and may cause some applications which rely on the incorrect behavior to fail. `emitDistinctChangesOnly` flag has also been deprecated and will be removed in a future major release. The previous implementation would fire changes `QueryList.changes.subscribe` whenever the `QueryList` was recomputed. This resulted in an artificially high number of change notifications, as it is possible that recomputing `QueryList` results in the same list. When the `QueryList` gets recomputed is an implementation detail, and it should not be the thing that determines how often change event should fire. Unfortunately, fixing the behavior outright caused too many existing applications to fail. For this reason, Angular considers this fix a breaking fix and has introduced a flag in `@ContentChildren` and `@ViewChildren`, that controls the behavior. ``` export class QueryCompWithStrictChangeEmitParent { @ContentChildren('foo', { // This option is the new default with this change. emitDistinctChangesOnly: true, }) foos!: QueryList<any>; } ``` For backward compatibility before v12 `emitDistinctChangesOnlyDefaultValue` was set to `false. This change changes the default to `true`. PR Close #41121
1 parent 012a2b5 commit 7096246

File tree

20 files changed

+88
-90
lines changed

20 files changed

+88
-90
lines changed

aio/content/guide/deprecations.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i
9595
| [`ANALYZE_FOR_ENTRY_COMPONENTS`](api/core/ANALYZE_FOR_ENTRY_COMPONENTS) | none | v9 | See [`ANALYZE_FOR_ENTRY_COMPONENTS`](#entryComponents) |
9696
| [`WrappedValue`](api/core/WrappedValue) | none | v10 | See [removing `WrappedValue`](#wrapped-value) |
9797
| [`async`](api/core/testing/async) | [`waitForAsync`](api/core/testing/waitForAsync) | v11 | The `async` function from `@angular/core/testing` has been renamed to `waitForAsync` in order to avoid confusion with the native JavaScript `async` syntax. The existing function is deprecated and will be removed in a future version. |
98+
[ `ViewChildren.emitDistinctChangesOnly` / `ContentChildren.emitDistinctChangesOnly` | none (was part of [issue #40091](https://github.com/angular/angular/issues/40091)) ] | This is a temporary flag introduced as part of bugfix of [issue #40091](https://github.com/angular/angular/issues/40091) and will be removed. |
9899

99100
{@a testing}
100101
### @angular/core/testing

packages/compiler-cli/ngcc/test/rendering/renderer_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ A.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: A, selectors: [["",
570570
UndecoratedBase.ɵfac = function UndecoratedBase_Factory(t) { return new (t || UndecoratedBase)(); };
571571
// TRANSPILED
572572
UndecoratedBase.ɵdir = /*@__PURE__*/ ɵngcc0.ɵɵdefineDirective({ type: UndecoratedBase, viewQuery: function UndecoratedBase_Query(rf, ctx) { if (rf & 1) {
573-
ɵngcc0.ɵɵviewQuery(_c0, 3);
573+
ɵngcc0.ɵɵviewQuery(_c0, 7);
574574
} if (rf & 2) {
575575
let _t;
576576
ɵngcc0.ɵɵqueryRefresh(_t = ɵngcc0.ɵɵloadQuery()) && (ctx.test = _t.first);

packages/compiler-cli/src/ngtsc/annotations/src/directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ export function extractQueryMetadata(
605605
if (typeof emitDistinctChangesOnlyValue !== 'boolean') {
606606
throw createValueHasWrongTypeError(
607607
emitDistinctChangesOnlyExpr, emitDistinctChangesOnlyValue,
608-
`@${name} options.emitDistinctChangesOnlys must be a boolean`);
608+
`@${name} options.emitDistinctChangesOnly must be a boolean`);
609609
}
610610
emitDistinctChangesOnly = emitDistinctChangesOnlyValue;
611611
}

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/queries/GOLDEN_PARTIAL.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import * as i0 from "@angular/core";
3232
export class ViewQueryComponent {
3333
}
3434
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
35-
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true }, { propertyName: "someDirs", predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
35+
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true }, { propertyName: "someDirs", predicate: SomeDirective, descendants: true }], ngImport: i0, template: `
3636
<div someDir></div>
3737
`, isInline: true, directives: [{ type: i0.forwardRef(function () { return SomeDirective; }), selector: "[someDir]" }] });
3838
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewQueryComponent, [{
@@ -88,7 +88,7 @@ import * as i0 from "@angular/core";
8888
export class ViewQueryComponent {
8989
}
9090
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
91-
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
91+
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], descendants: true }], ngImport: i0, template: `
9292
<div #myRef></div>
9393
<div #myRef1></div>
9494
`, isInline: true });
@@ -170,7 +170,7 @@ import * as i0 from "@angular/core";
170170
export class ViewQueryComponent {
171171
}
172172
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
173-
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
173+
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], descendants: true }], ngImport: i0, template: `
174174
<div someDir></div>
175175
`, isInline: true, directives: [{ type: i0.forwardRef(function () { return SomeDirective; }), selector: "[someDir]" }] });
176176
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewQueryComponent, [{
@@ -252,7 +252,7 @@ import * as i0 from "@angular/core";
252252
export class ViewQueryComponent {
253253
}
254254
ViewQueryComponent.ɵfac = function ViewQueryComponent_Factory(t) { return new (t || ViewQueryComponent)(); };
255-
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false, descendants: true, read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, read: TemplateRef }], ngImport: i0, template: `
255+
ViewQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ViewQueryComponent, selector: "view-query-component", viewQueries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], descendants: true, read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, descendants: true, read: TemplateRef }], ngImport: i0, template: `
256256
<div someDir></div>
257257
<div #myRef></div>
258258
<div #myRef1></div>
@@ -344,7 +344,7 @@ import * as i0 from "@angular/core";
344344
export class ContentQueryComponent {
345345
}
346346
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
347-
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true }, { propertyName: "someDirList", predicate: SomeDirective, emitDistinctChangesOnly: false }], ngImport: i0, template: `
347+
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true }, { propertyName: "someDirList", predicate: SomeDirective }], ngImport: i0, template: `
348348
<div><ng-content></ng-content></div>
349349
`, isInline: true });
350350
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContentQueryComponent, [{
@@ -423,7 +423,7 @@ import * as i0 from "@angular/core";
423423
export class ContentQueryComponent {
424424
}
425425
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
426-
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false }], ngImport: i0, template: `
426+
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"] }], ngImport: i0, template: `
427427
<div #myRef></div>
428428
<div #myRef1></div>
429429
`, isInline: true });
@@ -505,7 +505,7 @@ import * as i0 from "@angular/core";
505505
export class ContentQueryComponent {
506506
}
507507
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
508-
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], emitDistinctChangesOnly: false, descendants: true }], ngImport: i0, template: `
508+
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, static: true }, { propertyName: "foo", first: true, predicate: ["foo"], descendants: true }], ngImport: i0, template: `
509509
<div><ng-content></ng-content></div>
510510
`, isInline: true });
511511
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ContentQueryComponent, [{
@@ -610,7 +610,7 @@ import * as i0 from "@angular/core";
610610
export class ContentQueryComponent {
611611
}
612612
ContentQueryComponent.ɵfac = function ContentQueryComponent_Factory(t) { return new (t || ContentQueryComponent)(); };
613-
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], emitDistinctChangesOnly: false, descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, emitDistinctChangesOnly: false, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], emitDistinctChangesOnly: false, read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, emitDistinctChangesOnly: false, read: TemplateRef }], ngImport: i0, template: `
613+
ContentQueryComponent.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER", type: ContentQueryComponent, selector: "content-query-component", queries: [{ propertyName: "myRef", first: true, predicate: ["myRef"], descendants: true, read: TemplateRef }, { propertyName: "someDir", first: true, predicate: SomeDirective, descendants: true, read: ElementRef }, { propertyName: "myRefs", predicate: ["myRef1, myRef2, myRef3"], read: ElementRef }, { propertyName: "someDirs", predicate: SomeDirective, read: TemplateRef }], ngImport: i0, template: `
614614
<div someDir></div>
615615
<div #myRef></div>
616616
<div #myRef1></div>

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/queries/content_query_for_directive.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ ContentQueryComponent.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
33
selectors: [["content-query-component"]],
44
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
55
if (rf & 1) {
6-
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 1);
7-
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 0);
6+
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 5);
7+
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 4);
88
}
99
if (rf & 2) {
1010
let $tmp$;

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/queries/content_query_for_local_ref.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ ContentQueryComponent.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
55
// ...
66
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
77
if (rf & 1) {
8-
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 1);
9-
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 0);
8+
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 5);
9+
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 4);
1010
}
1111
if (rf & 2) {
1212
let $tmp$;

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/queries/content_query_read_token.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ ContentQueryComponent.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
55
// ...
66
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
77
if (rf & 1) {
8-
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 1, TemplateRef);
9-
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 1, ElementRef);
10-
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 0, ElementRef);
11-
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 0, TemplateRef);
8+
$r3$.ɵɵcontentQuery(dirIndex, $e0_attrs$, 5, TemplateRef);
9+
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 5, ElementRef);
10+
$r3$.ɵɵcontentQuery(dirIndex, $e1_attrs$, 4, ElementRef);
11+
$r3$.ɵɵcontentQuery(dirIndex, SomeDirective, 4, TemplateRef);
1212
}
1313
if (rf & 2) {
1414
let $tmp$;

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/queries/static_content_query.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ ContentQueryComponent.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
44
contentQueries: function ContentQueryComponent_ContentQueries(rf, ctx, dirIndex) {
55
if (rf & 1) {
66
$r3$.ɵɵcontentQuery(
7-
dirIndex, SomeDirective, __QueryFlags.isStatic__|__QueryFlags.descendants__);
8-
$r3$.ɵɵcontentQuery(dirIndex, $ref0$, 1);
7+
dirIndex, SomeDirective, __QueryFlags.isStatic__|__QueryFlags.descendants__|__QueryFlags.emitDistinctChangesOnly__);
8+
$r3$.ɵɵcontentQuery(dirIndex, $ref0$, 5);
99
}
1010
if (rf & 2) {
1111
let $tmp$;

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/queries/static_view_query.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ ViewQueryComponent.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
55
selectors: [["view-query-component"]],
66
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
77
if (rf & 1) {
8-
$r3$.ɵɵviewQuery(SomeDirective, __QueryFlags.isStatic__|__QueryFlags.descendants__);
9-
$r3$.ɵɵviewQuery($refs$, 1);
8+
$r3$.ɵɵviewQuery(SomeDirective, __QueryFlags.isStatic__|__QueryFlags.descendants__|__QueryFlags.emitDistinctChangesOnly__);
9+
$r3$.ɵɵviewQuery($refs$, 5);
1010
}
1111
if (rf & 2) {
1212
let $tmp$;

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/queries/view_query_for_directive.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ ViewQueryComponent.ɵcmp = /*@__PURE__*/ $r3$.ɵɵdefineComponent({
33
selectors: [["view-query-component"]],
44
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
55
if (rf & 1) {
6-
$r3$.ɵɵviewQuery(SomeDirective, 1);
7-
$r3$.ɵɵviewQuery(SomeDirective, 1);
6+
$r3$.ɵɵviewQuery(SomeDirective, 5);
7+
$r3$.ɵɵviewQuery(SomeDirective, 5);
88
}
99
if (rf & 2) {
1010
let $tmp$;

0 commit comments

Comments
 (0)