Routing in SPAs refers to the process of navigating between different views or pages within a single HTML document. This is achieved by updating the URL and rendering the appropriate content without requiring a full page reload.
Angular Router is an internal package that handles these navigation tasks, providing a seamless and responsive user experience.
Example of navigation
An example:
user clicks a button to navigate to a new application page
the browser URL changes
the SPA router destroys a part of the UI (the previous page) and creates the new page, simulating a navigation
First, we have to define the router rules. What does it mean?
That we have to define a set of rules to associate a specific component, that represents a "page", to a browser URL.
A component that is associated with the route is often known as "Routed Component"
Rule
Component
/
Load the Home Page (or redirect to another page, i.e. "shop")
/shop
Load the Shop component
/cart
Load the Cart component
/counter
Load the Counter component
For instance, using these rules, the Shop component will be loaded when the user visits the /shop url, the Cart Component when the /cart url is visited, and so on...
AppComponent (whose selector is app-root) is the root component of our application and is mounted once when the application starts.
In its HTML template we'll create:
a "navigation bar": some buttons we'll use to change the browser URL when users click them
a router-outlet component: a special Angular component that acts as a placeholder. This is the place where our Routed component will be loaded
As we said several times, we're building a Single Page Application.
It means that only one HTML file will be loaded in all the application lifecycle, index.html.
When a user changes page, the whole HTML page won't reloaded again but the router-outlet will automatically load a new component in according to the browser URL, and this component will act as a new page.
The diagram below shows how we'll organize our application:
So let's start creating a new Angular application.
Run the npx -p @angular/cli@latest command on your terminal to install and run the Angular CLI.
The ng new demo command indicates we're creating a new Angular project named demo:
terminal
Select:
Stylesheet format: CSS
PreRender (And Server Side Rendering): NO
Parameters:
-t: use inline templates when components are generated
-s: use inline styles
-S: don't generate unit tests
These settings are globally saved in the angular.json configuration file so they will be also applied when you'll you run generators commands to create your components using the CLI.
NodeJS v.18.19.1 - better Node 20.x - is required. I really suggest to use NVM , Node Version Manager (Windows - Mac ), or similar tools, to install several NodeJS versions on your machine
Here you can see a short video with the installation process explained so far:
no audio
The project name I have used in the video is ngrx-demo but feel free to use the name you prefer.
Now open the project in your favorite editor.
Open src/app.component.ts and you'll see that Angular CLI already added a router-outlet in the component HTML template:
Open the terminal in your project root folder and run the npm start command to start the application in "dev mode":
You can now visit the application in your browser at http://localhost:4200/ and this is the result:
we see the "Welcome to demo" message
the router-outlet does not load anything, since we still have to define the router rules and create the components, one for each page we want to add to the project.
Open terminal in the root of the project and run the following commands:
terminal
or using (short) alias:
terminal
Here how the project folder should look like:
Watch the video to see the procedure
The installation video was recorded using Angular v.18, when the --export-default feature was still not available.
no audio
export default in v.19
The --export-default option is available from Angular v.19 and it's very useful to simplify the process to lazy load the routes, as explained in the next lesson.
This flag exports your component using the default option.
Without the option the generated component will look like the following one:
features/counter/counter.component.ts
With the --export-default option it will add the default flag:
Open app.routes to define 3 router rules, one for each page.
Since we have export the routed components as default we don't need to import them using curly braces { ComponentClass } :
app.routes.ts
That's all!
Now when we visit one of the URL, for instance http://localhost:4200/shop, the ShopComponent will be automatically loaded in the router-outlet component as you can see in the screenshot below:
However when we visit the root URL http://localhost:4200/ the router-outlet doesn't load anything.
In fact, we have to provide a default behavior for the root of the project: /.
We could simply create a new HomeComponent and define a new rule just as we did before, or redirect users to another page.
In this case, we define a rule to automatically redirect users to the shop page when they open the application:
app.routes.ts
However when we open the application to the default URL http://localhost:4200/ we'll get this error
You can see this error opening the console panel in your browser Dev Tools:
DevTools
As the error says, the fix we have to do is very simple.
Just add pathMatch: 'full' to the router rule:
app.routes.ts
Why?
The default behavior is pathMatch: 'prefix'.
pathMatch: 'prefix': means any URL starting with the specified path would trigger the route. This is not ideal for redirects from the root path because it could potentially match many URLs unintentionally.
pathMatch: 'full': ensures that the URL exactly matches the specified path before triggering the route. For a root redirect, this makes sure only the exact root URL ('') will trigger the redirect.
The final version of app.routes.ts:
app.routes.ts
shop, cart and counter rules allow us to define the primary routes and which component should be loaded when the URL matches one of these paths.
the '' path is the default route. So users are redirected to /shop when they open site at the first time.
Add 3 buttons in AppComponent to create a navigation bar.
We use the routerLink directive to redirect users, so every time a button is clicked, users will be redirected to the specified URL.
The router-outlet is the placeholder where the routed component will be loaded in according to the router rule and the browser URL:
src/app.component.ts
Result:
routerLink vs anchors
Why do we use routerLink instead of the <a> anchor element?
Using the Angular routerLink directive over the traditional HTML <a> tag provides several advantages when dealing with navigation in a single-page application (SPA):
Smooth Navigation: routerLink leverages Angular's router to navigate between views without causing a full page reload. This ensures a seamless and faster user experience as only the necessary components are re-rendered.
State Preservation: The application state is maintained across navigations, avoiding the loss of data that might happen with a full page reload.
Since the NavBar layout will become complicated soon, maybe it might be better to create an external component for it.
First create a component using the CLI:
terminal
or using alias:
terminal
--flat tells the generator to avoid the creation of a specific folder for that component.
Since we set "inline templates" and "inline styles", the generator creates only one file for a component so we don't need a folder to contain it.
Now the component will hold the 3 buttons used to navigate and nothing more:
core/components/nav-bar.component.ts
We can now remove the buttons from AppComponent and create an instance of the NavBar Component using the app-nav-bar selector.
We also need to add the NavBarComponent to the imports properties:
By the time you read this book, some versions of the libraries used may have changed.
So here you can find the complete package.json in case you want to check and install the same versions used in this book: