Using standalone components with an Angular project allows you to remove the concept of ngModules which has been part of Angular for many years. In an existing application, this can remove many boilerplate .module files and in a new application, it means you can avoid the concept of ngModules almost entirely.
Ionic has officially supported Standalone Components since version 6.3.0, and now that they have been blessed by the Angular team as "stable" in both Angular 14 and 15 projects you can start using them safely in your Ionic project.
Sample Code
A sample of the Ionic Tabs starter application can be found here:
https://github.com/sean-perkins/ionic-angular-standalone
Migrating your Code
The following steps can be applied to migrate a typical tabs-based application to use Standalone Components and remove ngModules.
1. Check angular.json
First, open your angular.json file and check that you do not have an entry of aot:false. Many projects still have AOT compilation turned off and this will result in the following error when aot is set to false:
JIT compilation failed for component class AppComponent
2. Migrating Pages and Components
A page or component usually has a file called [name].module.ts with contents similar to:
@NgModule({
imports: [IonicModule, CommonModule, FormsModule,
ExploreContainerComponentModule, Tab1PageRoutingModule
],
declarations: [Tab1Page]
})
exportclassTab1PageModule {}
You can delete this module file then edit [name].component.ts and add:
@Component({
standalone:true,
imports: [IonicModule, CommonModule, FormsModule, ExploreContainerComponent],
selector:'app-tab1',
templateUrl:'tab1.page.html',
styleUrls: ['tab1.page.scss']
})
exportclassTab1Page {
...
You will notice we've set standalone to true and I've copied almost all of the imports. For pages, we've omitted the routing module (more on that below).
3. Migrating Routes
By default, most Ionic projects will use lazy-loaded modules as part of their routes. So in a typical app with tabs you'll have a file called [name-routing].module.ts with:
const routes: Routes = [{
path:'tabs', component:TabsPage,
children: [
{
path:'tab1',
loadChildren: () =>import('../tab1/tab1.module').then(m=>m.Tab1PageModule)
},
{
path:'tab2',
loadChildren: () =>import('../tab2/tab2.module').then(m=>m.Tab2PageModule)
},
{
path:'tab3',
loadChildren: () =>import('../tab3/tab3.module').then(m=>m.Tab3PageModule)
},
...
Instead of lazy loading a module using loadChildren we'll convert these to lazy load the component using loadComponent:
export const routes: Routes = [{
path:'tabs',
component:TabsPage,
children: [
{
path:'tab1',
loadComponent: () =>import('../tab1/tab1.page').then(m=>m.Tab1Page)
},
{
path:'tab2',
loadComponent: () =>import('../tab2/tab2.page').then(m=>m.Tab2Page)
},
{
path:'tab3',
loadComponent: () =>import('../tab3/tab3.page').then(m=>m.Tab3Page)
},
...
You should also
- Make sure you put export before the routes variable (so we can use it elsewhere later)
- Remove the @ngModule section from the file
- Rename the file from [name-routing].module.ts to [name-routing].ts
4. Use Environment Injector
You can skip this step if you are using Ionic Framework 7 or higher.
You will need to specify an EnvironmentInjector in your Tabs component (or App Component if you don't use tabs) like below in tabs.page.html:
<ion-tabs [environmentInjector]="environmentInjector">
Then add it to your constructor in tabs.page.ts:
constructor(public environmentInjector: EnvironmentInjector) {
Note: The requirement for EnvironmentInjector is specific to Ionic as we support versions of Angular below 14. Once the minimum supported version is above v14 then this step won't be required.
5. Migrating App Component
In a typical Ionic app, an app.component.ts file also uses a module that we can make standalone. Here is what it looks like before:
@Component({
selector:'app-root',
templateUrl:'app.component.html',
styleUrls: ['app.component.scss'],
})
After it will look like this:
@Component({
selector:'app-root',
standalone:true,
imports: [IonicModule],
templateUrl:'app.component.html',
styleUrls: ['app.component.scss']
})
Similarly, we'll refactor the app-routing.module.ts file to app.routes.ts:
import { Route } from'@angular/router';
export const routes: Route[] = [
{
path:'',
loadChildren: () => import('./tabs/tabs.routing').then((m) =>m.routes),
},
];
6. Migrating Main.ts
Your main.js is typically where you bootstrap the application and this usually looks like this:
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err=>console.log(err));
As we have deleted AppModule in prior steps we need to bootstrap using this method:
import { routes } from './app/app.routes';
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
importProvidersFrom(IonicModule.forRoot({})),
provideRouter(routes),
],
});
Notice that we are using the method bootstrapApplication to load the AppComponent and we are specifying routes using provideRouter where the routes are imported from app.routes.ts.
Summary
In summary, to migrate to using standalone components you need to move imports to your component before deleting your module file and make sure your application is bootstrapped correctly.
The benefits of doing this include fewer files in your project, fewer concepts to understand, and as a result fewer bugs in your code.
Comments
0 comments
Article is closed for comments.