diff --git a/apps/angular/ionic-angular-modules/package.json b/apps/angular/ionic-angular-modules/package.json
index fd07ac0..b8b2374 100644
--- a/apps/angular/ionic-angular-modules/package.json
+++ b/apps/angular/ionic-angular-modules/package.json
@@ -18,7 +18,7 @@
"@angular/platform-browser": "^16.0.0",
"@angular/platform-browser-dynamic": "^16.0.0",
"@angular/router": "^16.0.0",
- "@ionic/angular": "^7.0.0",
+ "@ionic/angular": "^7.5.0",
"ionicons": "^7.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
diff --git a/apps/angular/ionic-angular-standalone/package.json b/apps/angular/ionic-angular-standalone/package.json
index 1522c62..d1f9b02 100644
--- a/apps/angular/ionic-angular-standalone/package.json
+++ b/apps/angular/ionic-angular-standalone/package.json
@@ -26,7 +26,7 @@
"@capacitor/haptics": "5.0.6",
"@capacitor/keyboard": "5.0.6",
"@capacitor/status-bar": "5.0.6",
- "@ionic/angular": "^7.0.0",
+ "@ionic/angular": "^7.5.0",
"ionicons": "^7.0.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
diff --git a/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.html b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.html
new file mode 100644
index 0000000..89b56ea
--- /dev/null
+++ b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.html
@@ -0,0 +1,13 @@
+
+
+ view-child
+
+
+
+
+
+
+ view-child
+
+
+
diff --git a/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.ts b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.ts
new file mode 100644
index 0000000..a29802a
--- /dev/null
+++ b/apps/angular/ionic-angular-standalone/src/app/view-child/view-child.page.ts
@@ -0,0 +1,22 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonContent, IonicModule } from '@ionic/angular';
+
+@Component({
+ selector: 'app-view-child',
+ templateUrl: './view-child.page.html',
+ standalone: true,
+ imports: [IonicModule, CommonModule, FormsModule],
+})
+export class ViewChildPage implements OnInit {
+ /**
+ * Referencing the template's ion-content results in a double call.
+ */
+ @ViewChild(IonContent)
+ content!: IonContent;
+
+ constructor() {}
+
+ ngOnInit() {}
+}
diff --git a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts
index b2df8a8..39c0cbe 100644
--- a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts
+++ b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.test.ts
@@ -167,6 +167,49 @@ describe("migrateComponents", () => {
);
});
+ it("should remove duplicate imports from existing declarations", async () => {
+ const project = new Project({ useInMemoryFileSystem: true });
+
+ const component = `
+ import { Component, ViewChild } from "@angular/core";
+ import { IonContent, IonicModule } from "@ionic/angular";
+
+ @Component({
+ selector: 'my-component',
+ template: '',
+ standalone: true,
+ imports: [IonicModule]
+ })
+ export class MyComponent {
+ @ViewChild(IonContent) content!: IonContent;
+ }
+ `;
+
+ const componentSourceFile = project.createSourceFile(
+ "foo.component.ts",
+ dedent(component),
+ );
+
+ await migrateComponents(project, { dryRun: false });
+
+ expect(dedent(componentSourceFile.getText())).toBe(
+ dedent(`
+ import { Component, ViewChild } from "@angular/core";
+ import { IonContent } from "@ionic/angular/standalone";
+
+ @Component({
+ selector: 'my-component',
+ template: '',
+ standalone: true,
+ imports: [IonContent]
+ })
+ export class MyComponent {
+ @ViewChild(IonContent) content!: IonContent;
+ }
+ `),
+ );
+ });
+
describe("hyperlinks", () => {
it("should detect and import routerLink used in the template", async () => {
const project = new Project({ useInMemoryFileSystem: true });
diff --git a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts
index 4084c94..ca9ec13 100644
--- a/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts
+++ b/packages/cli/src/angular/migrations/standalone/0002-import-standalone-component.ts
@@ -154,6 +154,12 @@ async function migrateAngularComponentClass(
componentClassName,
"@ionic/angular/standalone",
);
+ /**
+ * This removes the import from the class, if it is present.
+ * An example where it may exist is when the developer has
+ * a @ViewChild decorator that references an ionic component.
+ */
+ removeImportFromClass(sourceFile, componentClassName, "@ionic/angular");
} else if (ngModuleSourceFile) {
const componentClassName = kebabCaseToPascalCase(ionicComponent);
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 3ed00d4..ddb7b12 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -48,8 +48,8 @@ importers:
specifier: ^16.0.0
version: 16.0.0(@angular/common@16.0.0)(@angular/core@16.0.0)(@angular/platform-browser@16.0.0)(rxjs@7.8.1)
'@ionic/angular':
- specifier: ^7.0.0
- version: 7.0.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0)
+ specifier: ^7.5.0
+ version: 7.5.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0)
ionicons:
specifier: ^7.0.0
version: 7.0.0
@@ -139,8 +139,8 @@ importers:
specifier: 5.0.6
version: 5.0.6(@capacitor/core@5.4.0)
'@ionic/angular':
- specifier: ^7.0.0
- version: 7.0.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0)
+ specifier: ^7.5.0
+ version: 7.5.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0)
ionicons:
specifier: ^7.0.0
version: 7.0.0
@@ -2791,8 +2791,8 @@ packages:
- chokidar
dev: true
- /@ionic/angular@7.0.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0):
- resolution: {integrity: sha512-vsSOPoWyO8Wl2EcUG9VJN50HsLG5B08q2mz/D6WAWeG0VlFGS2OdjtBOsFT3UKWuznuACxnTPNdUCk9JtFCgRw==}
+ /@ionic/angular@7.5.0(@angular/core@16.0.0)(@angular/forms@16.0.0)(@angular/router@16.0.0)(rxjs@7.8.1)(zone.js@0.13.0):
+ resolution: {integrity: sha512-0eZB/2/4ArfBt6YcYDF8VwfK0J8VRmywpbzlmsQXrubOAqd+Xaq2yYfLmzRfyrdKBhg7TyA+L6MyJ6w0Y7fbXA==}
peerDependencies:
'@angular/core': '>=14.0.0'
'@angular/forms': '>=14.0.0'
@@ -2803,7 +2803,7 @@ packages:
'@angular/core': 16.0.0(rxjs@7.8.1)(zone.js@0.13.0)
'@angular/forms': 16.0.0(@angular/common@16.0.0)(@angular/core@16.0.0)(@angular/platform-browser@16.0.0)(rxjs@7.8.1)
'@angular/router': 16.0.0(@angular/common@16.0.0)(@angular/core@16.0.0)(@angular/platform-browser@16.0.0)(rxjs@7.8.1)
- '@ionic/core': 7.0.0
+ '@ionic/core': 7.5.0
ionicons: 7.1.2
jsonc-parser: 3.2.0
rxjs: 7.8.1
@@ -2822,11 +2822,11 @@ packages:
- supports-color
dev: true
- /@ionic/core@7.0.0:
- resolution: {integrity: sha512-pM8qOaea9ZbqZbGnoIswaeeTiHJKNQ9ziSNHSILDpdd4FjpxZjOeMgNUdvYzh5rX9fA6hEM2wodg7McIWHgvZQ==}
+ /@ionic/core@7.5.0:
+ resolution: {integrity: sha512-oreRvbKj8VqqO9JraxR/n56GC6MHQtnJEmZf/EFuw5ZvDV8My91uNIzLkb4P9SvPL5NRr/Z0TFem28cgRf5YVA==}
dependencies:
- '@stencil/core': 3.4.2
- ionicons: 7.1.2
+ '@stencil/core': 4.4.1
+ ionicons: 7.2.1
tslib: 2.5.0
dev: false
@@ -3323,9 +3323,9 @@ packages:
hasBin: true
dev: false
- /@stencil/core@3.4.2:
- resolution: {integrity: sha512-FAUhUVaakCy29nU2GwO/HQBRV1ihPRvncz3PUc8oR+UJLAxGabTmP8PLY7wvHfbw+Cvi4VXfJFTBvdfDu6iKPQ==}
- engines: {node: '>=14.10.0', npm: '>=6.0.0'}
+ /@stencil/core@4.4.1:
+ resolution: {integrity: sha512-SirGcrb5yKHCn2BwdM7HGVXuvCdmwiXlVczEj8jJxQIm42CAUQCUECxtZidTzp+oZBZnWLnoAvfanchJsgkQzA==}
+ engines: {node: '>=16.0.0', npm: '>=7.10.0'}
hasBin: true
dev: false
@@ -7386,6 +7386,12 @@ packages:
'@stencil/core': 2.22.3
dev: false
+ /ionicons@7.2.1:
+ resolution: {integrity: sha512-2pvCM7DGVEtbbj48PJzQrCADCQrqjU1nUYX9l9PyEWz3ZfdnLdAouqwPxLdl8tbaF9cE7OZRSlyQD7oLOLnGoQ==}
+ dependencies:
+ '@stencil/core': 4.4.1
+ dev: false
+
/ip@2.0.0:
resolution: {integrity: sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==}
dev: true