Implementing MVVM

Welcome to Part 3 of this series reviewing the Pluralsight course Aurelia Fundamentals by Brian Noyes.

briannoyes

Brian is your Aurelia Author

Brian is CTO and Architect at Solliance, an expert technology solutions development company.

Brian is a Microsoft Regional Director and MVP, and specializes in rich client technologies including XAML and HTML 5, as well as building the services that back them with WCF and ASP.NET Web API.

You can follow Brian through his blog at http://briannoyes.net

Also in this series:

Part 1 – Aurelia Prerequisites
Part 2 – Getting Started
Part 3 – Implementing MVVM
Part 4 – Using Dependency Injection
Part 5 – Routing Fundamentals
Part 6 – Routing Beyond the Basics

Implementing MVVM

Separation of Concerns

MVVM stands for Model-View-ViewModel. It is mostly about trying to achieve good separation of concerns.

Brian uses the laundry of an analogy for separation of concerns. Are you someone who separates your clothes out into separate piles according to the type of clothing? Or do you just throw everything together?

LegacyCode

Legacy Code with no Separation of Concerns – a.k.a. the big ball of mud

You save a bit of time at first by not organizing your clothes. But when you need to get dressed it takes a lot more time to find what you are looking for.

Brian shows an example of HTML and JavaScript with no separation of concerns. The structure, interaction logic and UI element access is all happening in the same file making it hard to understand what should go where.

Taking the time upfront to organize your code will save you a lot of time and frustration over the longer term.

SeparationOfConcerns

Separation of Concerns

Using the MVVM pattern, and a framework such as Aurelia, we get good separations of concerns.

MVVM Goals and Benefits

Brian explains the following goals:

  • Maintainability
  • Testability
  • Extensibility

MVVM Key Concepts

MVVM is an architecture for structuring your client side code, which is a derivative of the MVC pattern.

Perhaps the main difference between MVC and MVVM is there is an ongoing interaction between the view and the viewModel in MVVM.

Often in MVC the View and the Controller have different lifetimes, but that is never the case with MVVM.

Also in MVC, interaction between the different elements is typically done through method calls. MVVM is instead designed for a rich data-binding system.

MVVM Pattern Responsibilities

Brian discusses the responsibilities of each of the elements in the MVVM pattern, starting with the model:

Model

The model contains the client side data-structures. It can have computed properties and validation logic.

View

The view is the structural definition of what the user see on the screen. It also contains the bindings to properties and methods on the ViewModel, and these are usually HTML attributes.

ViewModel

The main responsibility of the ViewModel is to provide data to the view for presentation and manipulation.

It also encapsulates the interaction logic.

Brian shows an example of the ViewModel allowing the model to work directly with the view. He calls this exposing a model object directly.

We also see a couple of examples of wrapped model data. This is not an exact mapping between model and view as we have additional data set in our ViewModel. The examples Brian gives are:

  • A boolean showCustomerAlert which is set based on other model data
  • An orders collection where each order is composed of many pieces of model data

Finally we see an example of client state: isLoggedIn

Client Services / Repositories layer

These have shared functionality or data access and are often consumed by one or more ViewModels.

This layer exists to decouple the ViewModels from external dependencies, such as Web API calls. The client repository is responsible for talking to these services, and can act as a data caching container.

MVVM Approaches in Aurelia

There are several approaches for hooking up our Views and ViewModels.

In this part of the course we focus on compose element

conductor

Compose element lets us point to a view and a viewmodel and pull them in as a block of UI

The second approach is to use the routing and navigation system of Aurelia.

compass

The final approach is using custom elements, which will be covered later in the course.

Using the Compose Element to setup an MVVM Hierarchy

The approach that Brian likes to take is to sketch out the main elements on the page and where they will appear on the page. For example the CommunityApp Page Structure:

  • Header / Nav menu at the top
  • Events List in the main section, composes of many events
  • Sponsor List on right hand side

In this demo Brian installs jspm and express again (see the Prerequisites module for more on those) and uses jspm to install aurelia-bootstrapper, aurelia-framework and bootstrap.

We also see that we should update the following sections of our config.js:

  • BabelOptions – es7 decorators and classProperties
  • Paths –  src folder

The root of our Single Page App is index.html and this contains script elements which load system.js, config.js and aurelia-bootstrapper.

The body tag has the attribute aurelia-app=”main”.

This references a small amount of aurelia setup code that we create in main.js. This is a configure function that sets the root to a view or viewmodel. The default name is “app” but in Brian’s demo we use “shell”.

We also need shell.js and shell.html

All MVVM views in Aurelia have the <template> element at the root.

The Aurelia framework includes a require element, which allows us to pull in content from a module that has been loaded.

In shell.html, Brian pastes in bootstrap code for setting up a nav bar.

shell.js is just an empty exported class for now.

That’s the Header / Nav menu done already. Next we create sponsors.html and sponsors.js and add a container-fluid div containing the events list and sponsors list.

Each of these use a compose element with the view-model attribute specifying the name of each ViewModel.

Brian runs the web server and opens index.html. We see our navigation menu is rendered as expected.

Leveraging Compose Element Options

We don’t have to specify a ViewModel in our compose element. Instead we can specify a view.

If we do this, Aurelia will assume that we don’t need a ViewModel here, but there wil be bindings to the parent ViewModel.

Brian demonstrates this in shell.js by setting parentprop to “Hug your parents!” and binding to this from events.html

${parentprop}

“Hug your parents!” is rendered in the events section of the page.

Next Brian shows us that we can specify both a view and a ViewModel in our compose element.

Implementing Composite View Hierarchies with the Compose Element

Here we see the repeat.for binding expression.

We also see the activate method on a ViewModel

By the end of this lesson, we’ve rendered tow events to the screen:

  1. Aurelia Fundamentals
  2. Data Centric SPAs with Breeze.js

Override View Resolution Conventions in Aurelia

The default is to assume that the view and the ViewModel have the same name and are located in the same directory.

One common convention in MVVM is to put all of the views into their own views directory, and all of the ViewModels in their own viewmodels directory.

To achieve this we must override the Aurelia convention in our main.js configure function as follows:

  • import ViewLocator
  • redefine convertOriginToViewUrl with our own implementation

For further details see Dwayne Charrington’s Using Views From Different Locations in Aurelia.

Another way is to explicitly specify the view name including the .html extension. However in the case of routing we don’t have a single view, we have many. This is where the convention based mechanism becomes very important.

Continue to Part 4 – Using Dependency Injection in Aurelia

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s