diff --git a/integration/mdc-migration/golden/src/app/components/chips/chips.component.html b/integration/mdc-migration/golden/src/app/components/chips/chips.component.html
index fc32a278e89b..f097b1ae3485 100644
--- a/integration/mdc-migration/golden/src/app/components/chips/chips.component.html
+++ b/integration/mdc-migration/golden/src/app/components/chips/chips.component.html
@@ -15,12 +15,12 @@
Chips example
Favorite Fruits
-
+
{{fruit.name}}
-
+
{
it('should update standalone chips', async () => {
await runMigrationTest('', '');
});
+
+ it('should update mat-chip with an *ngFor', async () => {
+ await runMigrationTest(
+ `
+
+ {{chip}}
+
+ `,
+ `
+
+ {{chip}}
+
+ `,
+ );
+ });
+
+ it('should update a chip listbox with a nested ng-container', async () => {
+ await runMigrationTest(
+ `
+
+
+
+ {{chip}}
+
+
+
+ `,
+ `
+
+
+
+ {{chip}}
+
+
+
+ `,
+ );
+ });
+
+ it('should update a chip with an *ngIf', async () => {
+ await runMigrationTest(
+ '',
+ '',
+ );
+ });
+
+ it('should update a chip grid with an *ngFor', async () => {
+ await runMigrationTest(
+ `
+
+ {{chip}}
+
+
+ `,
+ `
+
+ {{chip}}
+
+
+ `,
+ );
+ });
});
diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts b/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts
index ff90a640bd17..56e610a10b30 100644
--- a/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts
+++ b/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.spec.ts
@@ -48,6 +48,49 @@ function runClearAttributeTest(html: string, result: string): void {
}
describe('#visitElements', () => {
+ describe('visitElements', () => {
+ it('should traverse elements with an *ngFor', () => {
+ const visitedElements: string[] = [];
+ const template = `
+
+
+
+
+
+ `;
+
+ visitElements(parseTemplate(template).nodes, node => visitedElements.push(node.name));
+ expect(visitedElements).toEqual(['parent', 'child', 'grandchild']);
+ });
+
+ it('should traverse elements inside ng-container', () => {
+ const visitedElements: string[] = [];
+ const template = `
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ visitElements(parseTemplate(template).nodes, node => visitedElements.push(node.name));
+ expect(visitedElements).toEqual([
+ 'ng-container',
+ 'parent',
+ 'ng-container',
+ 'child',
+ 'ng-container',
+ 'grandchild',
+ ]);
+ });
+ });
+
describe('tag name replacements', () => {
it('should handle basic cases', async () => {
runTagNameDuplicationTest('', '');
diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.ts b/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.ts
index f6d4188c1f45..6ac6dc2e88e6 100644
--- a/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.ts
+++ b/src/material/schematics/ng-generate/mdc-migration/rules/tree-traversal.ts
@@ -10,6 +10,7 @@ import {
ParsedTemplate,
TmplAstElement,
TmplAstNode,
+ TmplAstTemplate,
parseTemplate as parseTemplateUsingCompiler,
} from '@angular/compiler';
@@ -32,9 +33,18 @@ export function visitElements(
nodes.reverse();
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
- if (node instanceof TmplAstElement) {
+ const isElement = node instanceof TmplAstElement;
+
+ if (isElement) {
preorderCallback(node);
+ }
+
+ // Descend both into elements and templates in order to cover cases like `*ngIf` and `*ngFor`.
+ if (isElement || node instanceof TmplAstTemplate) {
visitElements(node.children, preorderCallback, postorderCallback);
+ }
+
+ if (isElement) {
postorderCallback(node);
}
}
@@ -46,8 +56,8 @@ export function visitElements(
*
* For more details, see https://github.com/angular/angular/blob/4332897baa2226ef246ee054fdd5254e3c129109/packages/compiler-cli/src/ngtsc/annotations/component/src/resources.ts#L230.
*
- * @param html text of the template to parse
- * @param filePath URL to use for source mapping of the parsed template
+ * @param template text of the template to parse
+ * @param templateUrl URL to use for source mapping of the parsed template
* @returns the updated template html.
*/
export function parseTemplate(template: string, templateUrl: string = ''): ParsedTemplate {