Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { sendDebugMessage } from './send-debug-message';
import { getImportSpecifier, loadTypescript } from './ts-utils';
import type { MigrationResponse } from './types';

const supportedStrategies: ReadonlySet<string> = new Set(['OnPush', 'Default', 'Eager']);

export async function migrateSingleFile(
sourceFile: SourceFile,
extras: RequestHandlerExtra<ServerRequest, ServerNotification>,
Expand All @@ -31,7 +33,7 @@ export async function migrateSingleFile(
return unsupportedZoneUseResponse;
}

let detectedStrategy: 'OnPush' | 'Default' | undefined;
let detectedStrategy: string | undefined;
let hasComponentDecorator = false;

const componentSpecifier = await getImportSpecifier(sourceFile, '@angular/core', 'Component');
Expand Down Expand Up @@ -63,7 +65,7 @@ export async function migrateSingleFile(
prop.initializer.expression.getText(sourceFile) === 'ChangeDetectionStrategy'
) {
const strategy = prop.initializer.name.text;
if (strategy === 'OnPush' || strategy === 'Default') {
if (supportedStrategies.has(strategy)) {
detectedStrategy = strategy;

return;
Expand All @@ -77,13 +79,7 @@ export async function migrateSingleFile(
ts.forEachChild(node, visit);
});

if (
!hasComponentDecorator ||
// component uses OnPush. We don't have anything more to do here.
detectedStrategy === 'OnPush' ||
// Explicit default strategy, assume there's a reason for it (already migrated, or is a library that hosts Default components) and skip.
detectedStrategy === 'Default'
) {
if (!hasComponentDecorator || (detectedStrategy && supportedStrategies.has(detectedStrategy))) {
sendDebugMessage(
`Component decorator found with strategy: ${detectedStrategy} in file: ${sourceFile.fileName}. Skipping migration for file.`,
extras,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ describe('migrateSingleFile', () => {
expect(result).toBeNull();
});

it('should return null if component has ChangeDetectionStrategy.Default', async () => {
it('should return null if component has ChangeDetectionStrategy.Eager', async () => {
const fileName = 'app.component.ts';
const content = `
import { Component, ChangeDetectionStrategy } from '@angular/core';

@Component({
selector: 'app-root',
template: 'Hello',
changeDetection: ChangeDetectionStrategy.Default,
changeDetection: ChangeDetectionStrategy.Eager,
})
export class AppComponent {}
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,11 @@ export function generateZonelessMigrationInstructionsForComponent(
* **(Preferred) Convert to Signal**: The best approach is to convert the property to an Angular Signal. This is the most idiomatic and future-proof way to handle state in zoneless applications.
* **(Alternative) Use \`markForCheck()\`**: If converting to a signal is too complex or would require extensive refactoring, you can instead inject \`ChangeDetectorRef\` and call \`this.cdr.markForCheck()\` immediately after the property is updated.

#### Step 2: Add \`ChangeDetectionStrategy.Default\`
#### Step 2: Add \`ChangeDetectionStrategy.Eager\`
After you have refactored all necessary properties, you must update the component's decorator to explicitly set the change detection strategy.

1. Add \`ChangeDetectionStrategy\` to the import from \`@angular/core\`.
2. In the \`@Component\` decorator, add the property \`changeDetection: ChangeDetectionStrategy.Default\`.
2. In the \`@Component\` decorator, add the property \`changeDetection: ChangeDetectionStrategy.Eager\`.
3. Add a \`// TODO\` comment above this line explaining that the component should be fully migrated to \`OnPush\` after the application has been tested with these changes.

Example:
Expand All @@ -143,14 +143,14 @@ export function generateZonelessMigrationInstructionsForComponent(
...
// TODO: This component has been partially migrated to be zoneless-compatible.
// After testing, this should be updated to ChangeDetectionStrategy.OnPush.
changeDetection: ChangeDetectionStrategy.Default,
changeDetection: ChangeDetectionStrategy.Eager,
})
\`\`\`

### IMPORTANT: Rules and Constraints
You must follow these rules without exception:
1. **DO** apply one of the two refactoring strategies (signals or \`markForCheck()\`) for all relevant component properties.
2. **DO** add \`changeDetection: ChangeDetectionStrategy.Default\` with the specified TODO comment as the final code change.
2. **DO** add \`changeDetection: ChangeDetectionStrategy.Eager\` with the specified TODO comment as the final code change.
3. **DO NOT** use \`ChangeDetectionStrategy.OnPush\`. This will be the next step in the migration, but it is not part of this task.
4. **DO NOT** modify properties that are already signals or are used with the \`async\` pipe in the template, as they are already zoneless-compatible.
5. **DO NOT** make any changes to files other than the component file at \`${filePath}\` and its direct template/style files if necessary.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,7 @@ async function categorizeFile(
componentTestFiles.add(sourceFile);
} else if (componentSpecifier) {
if (
!content.includes('changeDetectionStrategy: ChangeDetectionStrategy.OnPush') &&
!content.includes('changeDetectionStrategy: ChangeDetectionStrategy.Default')
!/changeDetectionStrategy:\s*ChangeDetectionStrategy\.(?:OnPush|Default|Eager)/.test(content)
) {
filesWithComponents.add(sourceFile);
} else {
Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/component/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('Component Schematic', () => {
inlineStyle: false,
inlineTemplate: false,
displayBlock: false,
changeDetection: ChangeDetection.Default,
changeDetection: ChangeDetection.Eager,
style: Style.Css,
type: 'Component',
skipTests: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/schematics/angular/component/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@
},
"changeDetection": {
"description": "Configures the change detection strategy for the component.",
"enum": ["Default", "OnPush"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we leave Default here until its removed on the framework side?

Copy link
Collaborator Author

@alan-agius4 alan-agius4 Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed it, cause the FW already did a migration to move all apps from using Default to Eager.

"enum": ["Eager", "OnPush"],
"type": "string",
"default": "Default",
"default": "Eager",
"alias": "c"
},
"prefix": {
Expand Down