Skip to content

Commit 6ed2061

Browse files
committed
feat(migrations): add migration to convert ngClass to use class
feat angular#61661 - add migration to convert ngClass to use class
1 parent 90b0227 commit 6ed2061

27 files changed

Lines changed: 1627 additions & 142 deletions

File tree

adev/src/app/sub-navigation-data.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,12 @@ const REFERENCE_SUB_NAVIGATION_DATA: NavigationItem[] = [
13711371
path: 'reference/migrations/self-closing-tags',
13721372
contentPath: 'reference/migrations/self-closing-tags',
13731373
},
1374+
{
1375+
label: 'NgClass to Class',
1376+
path: 'reference/migrations/ngclass-to-class',
1377+
contentPath: 'reference/migrations/ngclass-to-class',
1378+
status: 'new',
1379+
},
13741380
],
13751381
},
13761382
];
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Migration from NgClass to class bindings
2+
3+
This schematic migrates NgClass directive usages to class bindings in your application.
4+
It will only migrate usages that are considered safe to migrate.
5+
6+
Run the schematic using the following command:
7+
8+
```bash
9+
ng generate @angular/core:ngclass-to-class
10+
```
11+
12+
13+
#### Before
14+
15+
```html
16+
<div [ngClass]="{admin: isAdmin, dense: density === 'high'}">
17+
```
18+
19+
20+
#### After
21+
22+
```html
23+
<div [class]="{admin: isAdmin, dense: density === 'high'}">
24+
```
25+
26+
## Configuration options
27+
28+
The migration supports a few options for fine tuning the migration to your specific needs.
29+
30+
### `--migrate-space-separated-key`
31+
32+
By default, migration avoids migrating keys separated by spaces.
33+
To migrate these keys as well, enable the `--migrate-space-separated-key` flag.
34+
35+
```html
36+
<div [ngClass]="{'class1 class2': condition}"></div>
37+
```
38+
39+
to
40+
41+
```html
42+
<div [class.class1]="condition" [class.class2]="condition"></div>
43+
```

adev/src/content/reference/migrations/overview.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,7 @@ Learn about how you can migrate your existing angular project to the latest feat
3030
<docs-card title="Self-closing tags" link="Migrate now" href="reference/migrations/self-closing-tags">
3131
Convert component templates to use self-closing tags where possible.
3232
</docs-card>
33+
<docs-card title="NgClass to Class Bindings" link="Migrate now" href="reference/migrations/ngclass-to-class">
34+
Convert component templates to prefer class bindings over the `NgClass`directives when possible.
35+
</docs-card>
3336
</docs-card-container>

packages/core/schematics/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ npm_package(
4343
"migrations.json",
4444
":bundles",
4545
"//packages/core/schematics/migrations/control-flow-migration:static_files",
46+
"//packages/core/schematics/migrations/ngclass-to-class-migration:static_files",
4647
"//packages/core/schematics/ng-generate/cleanup-unused-imports:static_files",
4748
"//packages/core/schematics/ng-generate/inject-migration:static_files",
4849
"//packages/core/schematics/ng-generate/output-migration:static_files",
@@ -109,6 +110,10 @@ bundle_entrypoints = [
109110
"control-flow-migration",
110111
"packages/core/schematics/migrations/control-flow-migration/index.js",
111112
],
113+
[
114+
"ngclass-to-class-migration",
115+
"packages/core/schematics/migrations/ngclass-to-class-migration/index.js",
116+
],
112117
[
113118
"router-current-navigation",
114119
"packages/core/schematics/migrations/router-current-navigation/index.js",
@@ -127,6 +132,7 @@ rollup.rollup(
127132
"//packages/core/schematics/migrations/control-flow-migration",
128133
"//packages/core/schematics/migrations/document-core",
129134
"//packages/core/schematics/migrations/inject-flags",
135+
"//packages/core/schematics/migrations/ngclass-to-class-migration",
130136
"//packages/core/schematics/migrations/router-current-navigation",
131137
"//packages/core/schematics/migrations/test-bed-get",
132138
"//packages/core/schematics/ng-generate/cleanup-unused-imports",

packages/core/schematics/collection.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@
5757
"factory": "./bundles/control-flow-migration.cjs#migrate",
5858
"schema": "./migrations/control-flow-migration/schema.json",
5959
"aliases": ["control-flow"]
60+
},
61+
"ngclass-to-class-migration": {
62+
"description": "Updates usages of `ngClass` directives to the `class` bindings where possible",
63+
"factory": "./bundles/ngclass-to-class-migration.cjs#migrate",
64+
"schema": "./migrations/ngclass-to-class-migration/schema.json",
65+
"aliases": ["ngclass-to-class"]
6066
}
6167
}
6268
}

packages/core/schematics/migrations/control-flow-migration/cases.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,15 @@
88

99
import {visitAll} from '@angular/compiler';
1010

11-
import {
12-
ElementCollector,
13-
ElementToMigrate,
14-
endMarker,
15-
MigrateError,
16-
Result,
17-
startMarker,
18-
} from './types';
11+
import {ElementCollector, ElementToMigrate, endMarker, Result, startMarker} from './types';
1912
import {
2013
calculateNesting,
2114
getMainBlock,
2215
getOriginals,
2316
hasLineBreaks,
24-
parseTemplate,
2517
reduceNestingOffset,
2618
} from './util';
19+
import {MigrateError, parseTemplate} from '../../utils/parse_html';
2720

2821
export const boundcase = '[ngSwitchCase]';
2922
export const switchcase = '*ngSwitchCase';

packages/core/schematics/migrations/control-flow-migration/fors.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,17 @@
88

99
import {visitAll} from '@angular/compiler';
1010

11-
import {
12-
ElementCollector,
13-
ElementToMigrate,
14-
endMarker,
15-
MigrateError,
16-
Result,
17-
startMarker,
18-
} from './types';
11+
import {ElementCollector, ElementToMigrate, endMarker, Result, startMarker} from './types';
1912
import {
2013
calculateNesting,
2114
getMainBlock,
2215
getOriginals,
2316
getPlaceholder,
2417
hasLineBreaks,
25-
parseTemplate,
2618
PlaceholderKind,
2719
reduceNestingOffset,
2820
} from './util';
21+
import {MigrateError, parseTemplate} from '../../utils/parse_html';
2922

3023
export const ngfor = '*ngFor';
3124
export const nakedngfor = 'ngFor';

packages/core/schematics/migrations/control-flow-migration/ifs.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,16 @@
88

99
import {visitAll} from '@angular/compiler';
1010

11-
import {
12-
ElementCollector,
13-
ElementToMigrate,
14-
endMarker,
15-
MigrateError,
16-
Result,
17-
startMarker,
18-
} from './types';
11+
import {ElementCollector, ElementToMigrate, endMarker, Result, startMarker} from './types';
1912
import {
2013
calculateNesting,
2114
getMainBlock,
2215
getOriginals,
2316
getPlaceholder,
2417
hasLineBreaks,
25-
parseTemplate,
2618
reduceNestingOffset,
2719
} from './util';
20+
import {MigrateError, parseTemplate} from '../../utils/parse_html';
2821

2922
export const ngif = '*ngIf';
3023
export const boundngif = '[ngIf]';

packages/core/schematics/migrations/control-flow-migration/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,11 @@ import {join, relative} from 'path';
1212
import {canMigrateFile, createMigrationProgram} from '../../utils/typescript/compiler_host';
1313

1414
import {migrateTemplate} from './migration';
15-
import {AnalyzedFile, MigrateError} from './types';
15+
import {AnalyzedFile} from './types';
1616
import {analyze} from './util';
1717
import {getProjectTsConfigPaths} from '../../utils/project_tsconfig_paths';
1818
import {normalizePath} from '../../utils/change_tracker';
19+
import {MigrateError} from '../../utils/parse_html';
1920

2021
interface Options {
2122
path?: string;

packages/core/schematics/migrations/control-flow-migration/migration.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,15 @@ import {migrateCase} from './cases';
1212
import {migrateFor} from './fors';
1313
import {migrateIf} from './ifs';
1414
import {migrateSwitch} from './switches';
15-
import {
16-
AnalyzedFile,
17-
endI18nMarker,
18-
endMarker,
19-
MigrateError,
20-
startI18nMarker,
21-
startMarker,
22-
} from './types';
15+
import {AnalyzedFile, endI18nMarker, endMarker, startI18nMarker, startMarker} from './types';
2316
import {
2417
canRemoveCommonModule,
2518
formatTemplate,
2619
processNgTemplates,
2720
removeImports,
2821
validateMigratedTemplate,
2922
} from './util';
23+
import {MigrateError} from '../../utils/parse_html';
3024

3125
/**
3226
* Actually migrates a given template to the new syntax

0 commit comments

Comments
 (0)