This post expands on the Angular 2 post from a couple of weeks ago involving route links and parameters to include an “optional” route parameter. Using the use case from the same topic with Aurelia from last week’s post which is if a user ends up on the contact detail page with no contact ID they will be presented with the option to add a new contact. The starting point for the code can be found here. Keep in mind any changes in this post are taking place in the Angular project.
Route with an “optional” parameter
The reason for the quotes around optional is that with Angular’s current router I have found no way to make a route optional. As a work around two routes can be added that point to the same component. The following code is in the app.module.ts file of the ClientApp/app folder. The first handles calling the contact detail component without an ID and the second makes the call with an ID.
The contact detail view model found in the contactdetail.component.ts file a class level property is needed to track of the contact detail component was called with an ID or not.
hasContactId: boolean;
Next, in the ngOnInit function has been changed to set the new property based on the route params having an ID set or not. If a contact ID is found then the details for that contact are loaded. The following is the full function.
In the associated view a placeholder for creating a new contact was added in the contactdetail.component.html file. This placeholder was added just above the link back to the contact list. This placeholder will only show if the detail components are loaded with no ID.
<h3 *ngIf="!hasContactId">
Place holder for creating a new contact
</h3>
Add create link to the contact list
To finish a “Create New Contact” link is added to the contact list view found in the contactlist.component.html file which will call the contact detail component without a contact ID.
<a [routerLink]="['/contact-detail']">Create New Contact</a>
In the example solution, this link will show above the table of contacts.
Wrapping up
The finished code can be found here. If you have tried both Angular 2 and Aurelia leave a comment on how you think they compare and which you prefer.
This post expands on the Aurelia post from a couple of weeks ago that involved router links and routing parameters to optional route parameters. The use case for this post is if a user ends up on the contact detail page with no contact ID they will be presented with the option to add a new contact. The starting point for the code can be found here. Keep in mind any changes in this post are taking place in the Aurelia project.
Route with optional parameter
Making a route parameter optional is as simple as adding a question mark to the end of the parameter name. The following is the before and after of the contact detail route found in the app.ts file in the ClientApp/app/components/app folder.
For more information on routing see the Aurelia docs.
Contact detail changes
In the contact detail view model which is in the contactDetail.ts file a class level property is added for if the component was activated with a contact ID or not.
hasContactId: boolean;
The activate function is changed to set the new class level variable to false if the function is called parms.id is falsy as well as to only pull contact details if it has a contact ID.
A placeholder for creating a new contact was added to the contact detail view found in contactDetail.html file. This placeholder was added just above the link back to the contact list. This placeholder will only show if the detail components are loaded with no ID.
<h3 if.bind="!hasContactId">
Placeholder for creating a new contact
</h3>
Add create link to the contact list
Finally, add a link in the contactList.html file that sends the user to the contact detail view, but without sending a contact ID.
<a route-href="route: contactdetail">Create New Contact</a>
In the example code this was added before the table of contacts, but of course, it could be anywhere.
Wapping up
The code in it’s completed state can be found here. The same functionality using Angular 2 will be coming up next week.
As with last week’s post this post is going to cover multiple topics related to while creating a contact detail page to go along with the existing contact list page that is part of the ASP.NET Basics repo, but this time using Angular 2 instead of Aurelia. The code before any changes can be found here. If you are using the sample application keep in mind all the changes in this post take place in the Angular project.
Creating a detail view and view model
Create contactdetail.component.html in ClientApp\app\components\contacts. This view that will be used to display all the details of a specific contact. It will also link back to the contact list. The following image shows the folder structure after the view and view model have been added.
*ngIf is adding/removing the associated div based on a contact being set or not.
{{value}}Â is Angular’s one-way binding syntax. For more details check out the docs.
<a routerLink=”/contact-list”>Â is using Angular to generate a link back to the contact list component.
View model
For the view model add contactdetail.component.ts in the ClientApp\app\components\contacts folder which is the same folder used for the view.
Make not of the imports needed to make this view model work. To start off Contact is needed to define what the definition of a contact is and ContactService is being used to load the data for a specific contact.
Angular’s core is imported to allow the view model to set as a component using @Component decorator as well as to all implementation of OnInit lifecycle hook.  Angular’s router is being used in the ngOnInit function to allow access the parameters of the route that caused the route to be triggered using this.route.params.
The switchMap operator from reactive extensions is used to map the id from the route parameters to a new observable that has the result of this.contactService.getById.
The existing ContactService doesn’t provide a function to get a contact by a specific ID so one needs to be added.
The following calls the API in the Contacts project and uses the result to create an instance of a Contact as a promise which is returned to the caller.
The base URL was also moved to a class level variable so that it could be shared.
Add a route with a parameter
To add the new contact detail to the list of routes that the application handles open app.module.ts in the ClientApp/app folder. First, add an import at the top of the file for the new component.
import { ContactDetailComponent } from './components/contacts/contactdetail.component';
Next, add the ContactDetailComponent to the declarations array of the @NgModule decorator.
path is the pattern used to match URLs. In addition, parameters can be used in the form of :parameterName. The above route will handle requests for http://baseurl/contact-detail/{id} where {id} is an ID of a contact. As demonstrated above in the ngOnInit function of the view model route.params can be used to access route parameters.
component is used to locate the view/view model that goes with the route.
Integrating the detail view with the contact list
The contact list view and view model needed the following changes to support the contact detail page.
View model
A variable was added for the ID of the select contact was as well as a onSelect function which takes a contact and gets called when a contact is selected. The following is the fully contact list view model.
The changes to the view model were not required to add the contact detail page, but are used show how to set up a click handler the view side. In the future, the selected contact will come in handy when the list and details were shown at the same time.
View
The amount of data being displayed was reduced to just ID and name. A column was added with a link to the details page. The following is the full view.
(click)=”onSelect(contact)” will cause the onSelect function of the view model to be called with the related contact when the associated element is clicked.
[routerLink]=”[‘/contact-detail’, contact.id]” use the router to create a line to the contact details page passing the contact ID as a parameter.
As a reminder of how to use a route’s parameter here is the ngOnInit function from the contact detail view model.
As with the related Aurelia post, there are a lot of topics covered in this post, but they are all related to the process of adding a new page and route to the application.
The code including all the changes for this post can be found here.
This post is going to cover multiple of topics that I hit while creating a contact detail page to go along with the contact list that is part of my ASP.NET Basics repo. The code before any changes can be found here. If you are following along with the sample application keep in mind all the changes in this post take place in the Aurelia project.
Creating a detail view and view model
Create contactDetail.html file inside of ClientApp\app\components\contacts. This is the view that will be used to display all the details of a specific contact as well as a link back to the contact list. The following image shows the folder structure with the view and view model already added.
View
The following is the full contents of the view. This will be followed up few a calls out of Aurelia specific things going on.
if.bind will keep the contact details out of the DOM if the condition fails. In this case, if the contact is null.
${value}Â is one of Aurelia’s bind syntaxes. For more details check out their docs.
<a route-href=”route: contactlist”>Â is using Aurelia’s router to generate a link back to the contact list component.
View model
Next, create a contactDetail.ts file inside of ClientApp\app\components\contacts which is the view model that goes with the view created above.
The view model gets an instance of the ContactService injected which is used to pull a contact’s detail information during the activate lifecycle hook. Notice the first parameter of the function (parms) which is where the route parameters are passed in.
The existing ContactService doesn’t provide a function to get a contact by a specific ID so one needs to be added.
The following calls the API in the Contacts project and uses the result to create an instance of a Contact as a promise which is returned to the caller.
Next, the router needs to be made aware of the new contact details. Open app.ts inside of the ClientApp/app/components/app folder. This file contains all the routes for the application. The bit we are interested in is the config.map which is an array of routes the application handles. Contact details is a new route which means adding a new object to the config.map array.
The route is the pattern used to match URLs. In addition, parameters can be used in the form of :parameterName. The above route will handle requests for http://baseurl/contact-detail/{id} where {id} is an ID of a contact. If a route has a parameter it will be made available to the activate function via the parms parameter in the view model.
moduleId is used to locate the view/view model that goes with the route.
nav controls if the route will be included in the routers navigation model. This is used to build the menu in this application. Contact details shouldn’t show in the menu which is why nav is set to false. For more details on Aurelia’s router check out the docs.
Integrating the detail view with the contact list
The contact list view and view model needed changes to support the contact detail page.
View model
The change to the view model was the simplest. A variable for the ID of the select contact was added as well as a function that gets called when a contact is selected. The following is the fully contact list view model.
import { inject } from 'aurelia-framework';
import { Contact } from './contact';
import { ContactService } from './contactService';
@inject(ContactService)
export class ContactList {
contacts: Contact[];
selectedContactId: number = null;
constructor(private contactService: ContactService) {}
created() {
this.contactService.getAll()
.then(contacts => this.contacts = contacts);
}
select(contact) {
this.selectedContactId = contact.id;
}
}
The changes to the view model were not really required to add the contact detail page, but they are there to show how to setup a click delegate on the view side. In the future, the selected contact could come in handy if the list and details were shown at the same time.
View
On the view, the amount of data being displayed was reduced to show just contact ID and name. A column was added with a link to the details page that is now used to show the rest of information about a contact. The following is the full view.
click.delegate=”select($contact)” will cause the select function of the view model to be called when the associated element clicked and passes the relevant contact object. The docs go into more depth on when to use delegates vs triggers.
The details link contains a lot of concepts. route-href is binding the anchor to Aurelia’s router.
route: contactdetail is telling the router which route to load.
params.bind: {id:contact.id} is telling the link to pass the contact’s ID to through the router to the view model that is being loaded. The following is the activate function of the contact detail view model as a reminder of the parameter’s usage.
This post cover a lot of topics, but they were all things I had to review in the course of adding contact details. My hope is this post will shortcut your own research and get you back to your task at hand. The finished code can be found here.
Leave a comment with any thoughts and/or questions.