One of the most desirable features in Angular is to lazy load a component the time you need it. This approach provides many benefits to the loading speed of the application as it downloads only the required components when you need them. Furthermore, it is a very straightforward procedure through routing that is documented in the Angular docs. However, what if you do not want to use the router, or you want to lazy load a component programmatically through your code?
scaffolding a sample form app
To highlight that scenario, let’s create a minimal angular web app without routing with a button that shows a form when we click it. We will use, also the Angular Material to have a simple and beautiful design.
The application comprises two different components: the AppComponent and the LazyFormComponent.
The AppComponent shows the main app, which contains a button that shows the LazyFormComponent when pressed.
What if we want to load the LazyFormComponent and their related material modules when we press the button and not the whole app?
We cannot use the route syntax to lazy load our component. Moreover, if we try to remove the LazyFormComponent from AppModule, the app fails because the Ivy compiler cannot find the required Angular Material modules needed for the form. This error leads to one of the critical aspects of Angular: The NgModule is the smallest reusable unit in the Angular architecture and not the Component, and it defines the component’s dependencies.
There is a proposal to move many of these configurations to the component itself, making the use of NgModule optional. A very welcoming change that will simplify the mental model which programmers have on each angular application. But until that time, we need to create a new module for our LazyFormComponent, which defines its dependencies.
For a NgModule with one component, defining it in the same file with the component for simplicity is preferable.
So, the steps to display our lazy component is:
define where we want to load our component in the template with the ng-template tag,
define its view query through ViewChild decorator, which gives us access to the DOM and defines the container to which the component will be added,
finally, dynamic import the component and add it to the container
The AppComponent has transformed now as (the changed lines are highlighted):
In Angular 13, a new API exists that nullifies the need for ComponentFactoryResolver. Instead, Ivy creates the component in ViewContainerRef without creating an associated factory. Therefore the code in loadForm() is simplified to:
The above approach works for the simplest components, which do not depend on other services or components. But, If the component has a dependency, for example, a service, then the above approach will fail on runtime.
Let’s say that we have a BackendService for our form submission form:
Furthermore, we do not need to inject the Compiler service because the compilation occurs implicitly with Ivy. So, instead of compiling the module, we only get the reference to it with the createNgModuleRef function:
What if we want to pass some values or listen to some events from our lazy loading component? We cannot use the familiar syntax for a defined component in a template. Instead of that, we can access them programmatically.
For example, we want to change the text of the submit button on LazyFormComponent, and we want to be informed when the form is submitted. We add the required attributes, an Input() attribute for the prop buttonTitle and an Output() for the formSubmitted event:
Vue’s primary motivation behind the introduction of Composition API was a cost-free mechanism for reusing logic between multiple components or apps. Is there a way to use that approach for AlpineJs without sacrificing its simplicity?
One of the most frequent requirements when writing AlpineJs components is the communication between them. There are various strategies for how to tackle this problem. This article describes the four most common patterns that help pass information between different Alpinejs components.