Aurelia

Unexpected token import with gulp

I have started to play with the release version of Aurelia. My current goal is to see what it takes to get going with Aurelia and ASP.NET Core now that both are RTM. I have hit a couple of road blocks that have ended up being new post of their own. For example this post that covers converting a new ASP.NET Core application to use gulp is one example. Today’s post is going to cover another issue I hit trying to use the gulp tasks created by the Aurelia CLI. There will not be anything Aurelia related in this post that will another post at a later date.

gulp setup

My gulpfile.js is nothing but a reference a directory of tasks. The full file looks like the following.

require('require-dir')('tasks');

Then I have a single task in tasks/exampleTask.js that consists of the following.

import gulp from 'gulp';

gulp.task('helloGulp', function(done){
 console.log('Hello Gulp!');
 done();
});

The error

With the above in place if you look at the task runner explorer you will see that Gulpfile.js shows a failed to load error instead of the helloGulp task.

gulpfailedtoload

As suggested by task runner explorer open the output window. There are many different things that use the output window so be sure and change show output from option to Task Runner Explorer. With that done you will be able to see why the task failed to load. The following is the error I am getting.

Failed to run "C:\ProjectDirectory\Gulpfile.js"...
cmd.exe /c gulp --tasks-simple
C:\ProjectDirectory\tasks\exampleTask.js:3
import gulp from 'gulp';
^^^^^^
SyntaxError: Unexpected token import
    at Object.exports.runInThisContext (vm.js:76:16)
    at Module._compile (module.js:528:28)
    at Object.Module._extensions..js (module.js:565:10)
    at Module.load (module.js:473:32)
    at tryModuleLoad (module.js:432:12)
    at Function.Module._load (module.js:424:3)
    at Module.require (module.js:483:17)
    at require (internal/module.js:20:19)
    at requireDir (C:\ProjectDirectory\node_modules\require-dir\index.js:116:33)
    at Object.<anonymous> (C:\ProjectDirectory\gulpfile.js:1:85)

The fix

I did some googling and I found this post by Mark Goodyear on using ES6 (or ES 2015) with gulp. It turns out the tasks generated by the Aurelia CLI are using ES 2015 and in order to use ES 2015 with gulp there are a few steps that must be taken first. Mark does a great job explaining those steps, but I am going to include a summary from the Visual Studio perspective.

Verify the devDependencies section in package.json contains the following. require-dir is only required if your gulpfile or tasks are using it.

"devDependencies": {
  "gulp": "3.9.1",
  "babel-preset-es2015": "^6.9.0",
  "require-dir":  "^0.3.0" 
}

Next create a .babelrc file at the same level as the package.json file with the following contents.

{
  "presets": [ "es2015"]
}

Then rename gulpfile.js to gulpfile.babel.js.

Back in the Task Runner Explorer hit the refresh button in the top left of the window which should now load your list of tasks under Gulpfile.babel.js with no errors.

taskrunnerrefersh

 

Unexpected token import with gulp Read More »

Aurelia Validation the Replacement Library

The post from last week on Aurelia Validation is now useless as this blog post from the Aurelia team states validation has been completely overhauled. This post is going to feel very similar to last weeks, but using the new validation library. The details on adding a main.js will match exactly from last weeks post, but is being included to make sure the examples in this post are complete.

Installation

Validation in Aurelia is provided using a plugin in which must be installed before being used. Make sure you have npm and jspm installed. For more information on getting up and running with Aurelia check out this post that will guide you through the process and links to a Github repo with matching code.

From the console execute this command jspm install aurelia-validatejs to download and install the files needed for validation.

In order to load plugins a named Aurelia-App is need to allow more control of the bootstrapping process. In Views/Home/Aurelia.cshtml make the following change.

Before:
<div aurelia-app>

After:
<div aurelia-app="main">

Now that this Aurelia application has been named “main” Aurelia will look for a matching main.js file and call its configure function during the bootstrapping process. Here is the main.js I am using. Note that the validation plugin in is being loaded. For my project main.js is located in wwwroot/Aurelia.

export function configure(aurelia) {
    aurelia.use
      .standardConfiguration()
      .developmentLogging()
      .pluginin('aurelia-validatejs');

    aurelia.start().then(() => aurelia.setRoot());
}

Usage

The first step in using validation is to add its import to the top of the class that will be using it.

import {ValidationEngine, Validator, required, email} from 'aurelia-validatejs';

Next setup the validation rules using decorators and inject validation via the constructor and set up the validation rules. The plugin also supports a fluent style of adding validation to property, but I ran into issues getting it working so I just stuck with decorators for this post.

static inject() { return [Validator]; }

@required 
Name = '';

@required 
@email 
Email = '';

constructor(validator) {
    this.reporter = ValidationEngine.getValidationReporter(this);
}

The above makes sure that Name is required and that email is required and conforms to the rule of what an email address. This is only a small sample of the built in validations provided by check out this page for a sample of the other provided validations.

Show Validation Failures in a View

The validation plugin in provides a way to display validation messages with the appropriate field. The following is a part of a view that contains name and email address that are bound to the properties from above.

<form>
    <div class="form-group">
        <label>Name</label>
        <input type="text" value.bind="Name & validate" class="form-control">
    </div>
    <div class="form-group">
        <label>Email</label>
        <input type="email" value.bind="Email & validate" class="form-control">
    </div>
</form>

By adding & validate as part of the value bind statement the plug in knows where the validation messages show be shown.

Warning

If you run into a “Cannot read property ‘bindingContext’ of null” when trying to implement the new validation plugin make sure your class constructor contains:

this.reporter = ValidationEngine.getValidationReporter(this);

From what I can tell this requirement will be temporary. This is an alpha release of the overhaul and has a few rough edges such as the binding context gotcha and the fluent API issues I mentioned above. With the track record of the Aurelia team I am sure the issues I hit will be resolved quickly.

Aurelia Validation the Replacement Library Read More »

Aurelia Validation

Update: this post is now out of date an updated version can be found here.

Client side validation is an important part of client side frameworks and can provide users with immediate feedback as well as check away to stop before posting data to the server. This post is going to look at validation with in Aurelia.

Installation

Validation in Aurelia is provided using a plugin in which must be installed before being used. Make sure you have npm and jspm installed. For more information on getting up and running with Aurelia check out this post that will guide you through the process and links to a Github repo with matching code.

From the console execute this command jspm install aurelia-validation to download and install the files needed for validation.

In order to load plugins a named Aurelia-App is need to allow more control of the bootstrapping process. In Views/Home/Aurelia.cshtml make the following change.

Before:
<div aurelia-app>

After:
<div aurelia-app="main">

Now that this Aurelia application has been named “main” Aurelia will look for a matching main.js file and call its configure function during the bootstrapping process. Here is the main.js I am using. Note that the validation plugin in is being loaded. For my project main.js is located in wwwroot/Aurelia.

export function configure(aurelia) {
    aurelia.use
      .standardConfiguration()
      .developmentLogging()
      .pluginin('aurelia-validation');

    aurelia.start().then(a => a.setRoot());
}

Usage

The first step in using validation is to add its import to the top of the class that will be using it.

import {Validation} from 'aurelia-validation';

Next the inject validation via the constructor and set up the validation rules.

static inject() { return [Validation]; }
constructor(validation) {
    this.Name = '';
    this.Email = '';
    this.validation = validation.on(this)
        .ensure('Name').isNotEmpty().hasLengthBetween(3, 50)
        .ensure('Email').isNotEmpty().isEmail();
}

The above makes sure that Name is required and has a length between 3 and 50 characters and that email is required and conforms to the rule of what an email address contain. This is only a small sample of the built in validations provided by check out this page for a demo of the other provided validations.

Show Validation Failures in a View

The validation plugin in provides a custom attribute that will loop all nested child elements and display validation messages with the appropriate field. The following is a part of a view that contains name and email address that are bound to the properties from above.

<form role="form" validate.bind="validation">
    <div class="form-group">
        <label>Name</label>
        <input type="text" value.bind="Name"placeholder="name" class="form-control">
    </div>
    <div class="form-group">
        <label>Email</label>
        <input type="email" value.bind="Email" placeholder="email" class="form-control">
    </div>
</form>

You can see that the validate custom attribute is bound to the validation property of the class defined above. Since the controls are in a form group the validation plugin is able to infer where bound field is show validation errors in the appropriate area. Check out this page for more details on visualization of validation errors. The default visualization is based on Twitter Bootstrap, but that can be changed the details of which can be found here.

Issues

Unfortunately I ran into some problems with trying to implement validation in a more complex situation dealing with an object that is replaced via binding. I doubt this is a problem with Aurelia. If anyone has any experience with validation on objects that are fully replaced via binding please let me know. Expect a blog post once I get my issue figured out.

Aurelia Validation Read More »

Angular 2 vs Aurelia Basic Syntax

The ASP.NET Core project with Angular 2 and Aurelia from last week’s post now has feature parity between Angular 2 and Aurelia. With the applications in sync now is a good time to compare syntax for basic operations between the two frameworks.

Templates

Function Angular 2 Aurelia
Binding {{title}}  ${title}
Input Binding <input [(ngModel)]="contact.Name">  <input value.bind="contact.Name">
Loops *ngFor="#contact of contacts"  repeat.for="contact of contacts"
Events (click)="onSelect(contact)"  click.delegate="$parent.select(contact)"
Conditional Elements <div *ngIf="contact">  <div if.bind="contact">
Conditional CSS [class.selected]="contact === selectedContact"  class="${contact === $parent.selectedContact ? 'selected' : "}"
Component Rendering <contact-detail [contact]="selectedContact"></contact-detail>  <contact-detail contact.bind="selectedContact"></contact-detail>

Component Lifecycle Hooks

The hooks provided by the frameworks don’t exactly line up, but the following is a list with a list of hooks and descriptions taken for the docs of both frameworks. The hooks are listed in the order they are executed in the component’s lifecycle. For more details look at the docs for Angular 2 and Aurelia (search for “The Component Lifecycle”).

Angular 2

ngOnChanges Called when an input or output binding value changes
ngOnInit After the first ngOnChanges
ngDoCheck Developer's custom change detection
ngAfterContentInit After component content initialized
ngAfterContentChecked After every check of component content
ngAfterViewInit After component's view(s) are initialized
ngAfterViewChecked After every check of a component's view(s)
ngOnDestroy Just before the directive is destroyed

Aurelia

constructor() The view-model's constructor is called first.
created(owningView: View, myView: View) If the view-model implements the created callback it is invoked next. At this point in time, the view has also been created and both the view-model and the view are connected to their controller. The created callback will receive the instance of the "owningView". This is the view that the component is declared inside of. If the component itself has a view, this will be passed second.
bind(bindingContext: Object, overrideContext: Object) Databinding is then activated on the view and view-model. If the view-model has a bind callback, it will be invoked at this time. The "binding context" to which the component is being bound will be passed first. An "override context" will be passed second. The override context contains information used to traverse the parent hierarchy and can also be used to add any contextual properties that the component wants to add.
attached() Next, the component is attached to the DOM (in document). If the view-model has an attached callback, it will be invoked at this time.
detached() At some point in the future, the component may be removed from the DOM. If/When this happens, and if the view-model has a detached callback, this is when it will be invoked.
unbind() After a component is detached, it's usually unbound. If your view-model has the unbind callback, it will be invoked during this process.

The Winner?

Both Angular 2 and Aurelia continue to improve as they progress through their beta stages. Aurelia seems to be more stable at this point with little to no breaking changes since they entered beta. Angular 2 will have an initial head start with the inertia of Angular 1 which will make it an easier sell at some organizations.

As is evident by the comparison above these frameworks are taking different approaches. There is no clear winner and thankfully there doesn’t have to be. Both frameworks will be successful.

At this point in time I would be comfortable going live with a project on Aurelia. Angular 2 is making huge steps forward, but feels like it need a little more time to bake before I would want to use it in a production application.

If you had an application going live soon which would you chose?

Angular 2 vs Aurelia Basic Syntax Read More »

ASP.NET Core Project with Angular 2, Aurelia and an API

I have been exploring Aurelia and more recently Angular 2 and while doing so I thought it might be nice to run both frameworks from the same project.  My first crack at this can be found in this repo on Github.

Content

  • Contact model, a simplified version of the one used in previous blogs
  • ContactsController and related razor views created using Visual Studio’s scaffolding tools based on the contact mode
  • ContactsApiController is the end point for the Angular 2 and Aurelia applications
  • Angular 2 application that closely match the one from last week’s post
  • Aurelia application is currently just a proof that Angular 2 and Aurelia could run in the same project. This application will be updated to connect to the project’s web API.

Getting Started

Ensure that node and jspm are install.

After acquiring the code open the solution. If using Visual Studio the npm based packages will be restored automatically. If not using Visual Studio then run  npm install from the console. This will handle all the files needed by Angular 2.

Next run the jspm install -y  command to install the Aurelia related packages.

Make sure the database is created and up to date with the following two commands.

dnx ef database update -c ApplicationDbContext
dnx ef database update -c ContactsDbContext

In wwwroot open the config.js file and verify the paths section looking like the following. Jspm install seems to rewrite the github and npm portions of the paths section which removed the “../”. This is more than likely a configuration issue that I hope to fix in the future.

paths: {
  "*": "../Aurelia/*",
  "github:*": "../jspm_packages/github/*",
  "npm:*": "../jspm_packages/npm/*"
}

Finally run the angular2 gulp task from the task runner. The application should now run with no issues.

First Run

Make sure to register a new user as both the contacts controllers require an authorized user and filter down the contacts to display based on the logged in user.

The menu bar will contain links for Angular 2, Aurelia and Razor. Use the razor link to create some data. This is the generated razor views mentioned above. It is also the only way to add data through the application currently.

The Angular 2 link will of course launch the Angular 2 application that will display a list of contacts for the current user.

The  Aurelia like will launch the Aurelia application which just contains the very basic application from the getting started guide.

Going Forward

The plan is to develop the Angular 2 and Aurelia applications together. The Aurelia application will be the first to get some time to get up to the same level as the Angular 2 application.

It is also my hope that having this project will be a good reference for you when reading the examples in future blog posts.

ASP.NET Core Project with Angular 2, Aurelia and an API Read More »

Refactor Round 2

In last week’s post accessing a web API was refactored to a central service in an Aurelia application instead of being spread across the application. In this post we will push the refactor even further. The service will change from a pass through to the backing web API to be the data provider for the Aurelia application.

The first set of changes is to the service, which may be a bad name with the changes that are being made. GetAll will now keep a copy of the contact retrieved for the web API.

Before:
GetAll() {
    return this.http.fetch('contacts')
        .then(response => response.json())
        .catch(error => console.log(error));
}
After:
GetAll() {
    return this.http.fetch('contacts')
        .then(response => response.json())
        .then(contacts => this.contacts = contacts)
        .catch(error => console.log(error));
}

As an example of the implications of this change we will look at the Get function which require a contact ID. Instead of hitting the web API to pull the details of contact the information is pull from the service’s local copy that was cached in the GetAll function above.

Before:
Get(id) {
    return this.http.fetch(`contacts/${id}`)
        .then(response => response.json())
        .catch(error => console.log(error));
}
After:
Get(id) {
    return new Promise((resolve) => {
        resolve(this.contacts.filter(contact => contact.Id == id)[0])
    });
}

With the above changes the view model for the contact list contains very little code. With the binding of the contact list now bound to the service changes to contacts are automatically reflected in the contact list. This removed the need for the event aggregator. The full code for the list view model follows.

import {inject} from 'aurelia-framework';
import {ContactService} from 'Aurelia/contactService';

@inject(ContactService)
export class List {

    constructor(contactService) {
        this.contactService = contactService;
        this.contactService.GetAll()
             .then(() => this.contacts = this.contactManager.contacts);
    }
}

All the view models had similar reductions in the amount of code required. There are many more options on the best way to factor this code. A next step could be to keep the web API access separate from the a new business class used to manage and cache the contact data once it has been retrieved.

Refactor Round 2 Read More »

Refactor of ASP.NET 5 Web API Access from Aurelia

This post is going to cover refactoring of client side code based in Aurelia to centralize access to an ASP.NET 5 web API. This will remove the need for the fetch and configuration APIs in most classes which will be replaced by access via a contact service. This is of course based on the same contacts application I have been using in most of my previous posts. I am going to limit the examples to what is need to display a contact list, but the same concepts would apply to all aspects of contact interaction.

To begin I created a new ContactService.js file which will be used to handle all interactions with the ASP.NET 5 web API.

import {inject} from 'aurelia-framework';
import {HttpClient, json} from 'aurelia-fetch-client';
import 'fetch';
import {EventAggregator} from 'aurelia-event-aggregator';
import {Configure} from 'aurelia-configuration';
import {ContactUpdatedMessage} from 'Aurelia/ContactUpdatedMessage';

@inject(HttpClient, EventAggregator, Configure)
export class ContactService {

    constructor(http, eventAggregator, configAurelia) {
        http.configure(config => {
            config
                .useStandardConfiguration()
                .withBaseUrl(configAurelia.get('api.baseUrl'));
        });

        this.http = http;
        this.eventAggregator = eventAggregator;
    }

    GetAll() {
        return new Promise((resolve) => {
            resolve(this.http.fetch('contacts')
                .then(response => response.json(),
                    err => console.log(err)));
        });
    }
}

The above class utilizes the configuration for the API base URL as explained in this post. The event aggregator is also included and would be used to notify of changes on a contacts. The event aggregator is not actually used in the shown code but example usage can be found here.

Note that the GetAll function returns a promise which is built off of the promise that the http fetch returns. Promises help with async operations are needed and are what enabled the then() function that makes reacting when an async operation is completed very simple. They are not the subject of this post but I wanted to make special note of them because they are new in the latest version of JavaScript.

Next are the changes to the list class which is the view model for the contact list. All the http related imports get removed and an import for the contactService is added. For classes don’t need notification of contact updates the EventAggregator and ContactUpdatedMessage could be removed as well.

Before:
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';
import {EventAggregator} from 'aurelia-event-aggregator';
import 'fetch';
import {ContactUpdatedMessage} from 'Aurelia/ContactUpdatedMessage';
import {Configure} from 'aurelia-configuration';
After:
import {inject} from 'aurelia-framework';
import {EventAggregator} from 'aurelia-event-aggregator';
import {ContactUpdatedMessage} from 'Aurelia/ContactUpdatedMessage';
import {ContactService} from 'Aurelia/contactService';

In the inject decorator HttpClient and Configure are replaced with ContactService.

Before:
@inject(HttpClient, EventAggregator, Configure)
After:
@inject(EventAggregator, ContactService)

Next the constructor changed to remove http related items and to save a reference to the ContactService.

Before:
constructor(http, eventAggregator, configAurelia){
    http.configure(config => {
        config
          .useStandardConfiguration()
          .withBaseUrl(configAurelia.get('api.baseUrl'));
    });

    this.http = http;
    eventAggregator.subscribe(ContactUpdatedMessage, message => {
        let updatedContact = 
	     this.contacts.filter(contact => contact.Id == message.contact.Id)[0];
        Object.assign(updatedContact, message.contact);
    });
}
After:
constructor(eventAggregator, contactService){
    eventAggregator.subscribe(ContactUpdatedMessage, message => {
        let updatedContact = 
             this.contacts.filter(contact => contact.Id == message.contact.Id)[0];
        Object.assign(updatedContact, message.contact);
    });
    this.contactService = contactService;
}

Finally the direct call to the web API is replaced with a call to the ContactService.

Before:
created(){
    return this.http.fetch('contacts')
      .then(response => response.json())
      .then(contacts => this.contacts = contacts);
}
After:
created(){
    return this.contactService.GetAll()
      .then(contacts => this.contacts = contacts);
}

Following the above example, the remaining locations where the web API is accessed directly can be replaced with the ContactService.

Update

Something hit me when reading this post today. Aurelia’s fetch client returns a promise so there is no need to create a new promise in the ContactService. Here is the GetAll function from above updated to not declare a new promise.

Before:
GetAll() {
    return new Promise((resolve) => {
        resolve(this.http.fetch('contacts')
            .then(response => response.json(),
                err => console.log(err)));
    });
}
After:
GetAll() {
    return this.http.fetch('contacts')
        .then(response => response.json())
        .catch(error => console.log(error));
}

There maybe case where creating is a new promise is the correct thing to do, but in this case it was unnecessary.

Refactor of ASP.NET 5 Web API Access from Aurelia Read More »

Basic Configuration with Aurelia

If you have been following my Aurelia posts using an ASP.NET 5 web API then you will have noticed that I have been hardcoding the API url. In this post I am going to cover the basics of configuration in Aurelia which will allow the API url to be in a single location instead of spread all over the application.

Configuration will be done using the Aurelia-Configuration plugin. To install open a console window and navigate to the folder that contains the application’s package.json file and run the following command.

jspm install aurelia-configuration

If you are using Visual Studio to find your package.json make sure to click the show all files button in the solution explorer. With the release of RC1 package.json is hidden by default.

First code change is in the html file that kicks off Aurelia. The changed part is on the first line with aurelia-app which changed to aurelia-app=”main”.

<div aurelia-app="main">
    <script src="../jspm_packages/system.js"></script>
    <script src="../config.js"></script>
    <script>
        System.import("aurelia-bootstrapper");
    </script>
</div>

Next add a main.js file in the wwwroot folder. This file will be called when Aurelia is bootstrapped and will control how Aurelia is bootstrapped. Everything in this file is the default Aurelia bootstrapping process other than “.plugin(‘aurelia-configuration’)” which is the part that needs to be added for configuration to work.

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging()
    .plugin('aurelia-configuration');

  aurelia.start().then(a => a.setRoot());
}

By default the configuration plugin looks for an application.json inside of a config directory in the root directory. This tripped me up a bit as I was expecting this to be a config directory inside of wwwroot, but that is not exactly the case. Root in the case means root for the Aurelia application context. In my case my Aurelia app is launched from a HomeController which means the application.json file needed to be in wwwroot/Home/config. Here is my application.json file with the base url for my test API.

{
	"api": {
		"baseUrl": "http://localhost:18907/api/"
	}
}

Now to get access to the configuration information. First add an import for configuration.

import {Configure} from 'aurelia-configuration';

Add Configure to the inject decorator.

@inject(HttpClient, Router, EventAggregator, Configure)

And to the constructor.

constructor(http, router, eventAggregator, configAurelia)

Now the actual usage of a config value with a before and after for comparison.

Before:
.withBaseUrl('https://localhost:18907/api/');

After:
.withBaseUrl(config.get('api.baseUrl'));

Here is all of the above together for reference.

import {Configure} from 'aurelia-configuration';

@inject(HttpClient, Router, EventAggregator, Configure)
export class Detail{

    constructor(http, router, eventAggregator, configAurelia){
        http.configure(config => {
            config
              .useStandardConfiguration()
              .withBaseUrl(configAurelia.get('api.baseUrl'));
        });

        this.http = http;
        this.router = router;
        this.eventAggregator = eventAggregator;
    }

That is all there is for basic configuration with Aurelia. Check out the plugin’s site for examples of how set up configurations for different environments, setting the config directory as well as filename.

Basic Configuration with Aurelia Read More »

Aurelia’s Event Aggregator

Aurelia’s event aggregator is a lightweight pub/sub messaging system which I am going to make use of to update my contact list with edits to a contact are saved.

I started by creating the class that would be used to publish messages to the event aggregator. In this case the message is for notification that a contact was updated and will contain the contact that was updated.

export class ContactUpdatedMessage {
    constructor(contact) {
        this.contact = contact;
    }
}

Detail.js is the view model for editing of contacts needs imports for the new ContactUpdatedMessage and Aurelia’s event aggregator. The ContactUpdatedMessage is in the Aurelia folder of the application’s wwwroot which is why it has “Aurelia/” and not just ContactsUpdatedMessage in the from portion of the import statement.

import {EventAggregator} from 'aurelia-event-aggregator';
import {ContactUpdatedMessage} from 'Aurelia/ContactUpdatedMessage';

Add EventAggregator to the inject decorator of the details class. Next the constructor needs to be changed for injection of the event aggregator. Ignore the fact that the web API url is hardcoded. I know there is a better way to handle the url, but I have not had time to look into it yet. In the next to last line a reference to the injected event aggregator is saved.

@inject(HttpClient, EventAggregator)
export class Detail{

    constructor(http, eventAggregator){
        http.configure(config => {
            config
              .useStandardConfiguration()
              .withBaseUrl('https://localhost:18907/api/');
        });

        this.http = http;
        this.eventAggregator = eventAggregator;
    }

When a user clicks save on a contact the submit function is called. The call to the web API using fetch is an existing part of the submit function. The new bit is the call to the eventAggregator’s publish function with new ContactUpdatedMessage using the edited contact.

submit() {
    this.http.fetch('contacts/' + this.contact.Id, 
                    { method: 'put', 
                      body: json({id: this.contact.Id, 
                                  name: this.contact.Name}) })
             .then(response => response.json())
             .then(contact => this.contact = contact)
             .catch(e => {
                    console.log(e);
                    this.postResult = e.status + '-' + e.statusText;
                    });

    this.eventAggregator.publish(new ContactUpdatedMessage(this.contact));
}

List.js needs to be a subscriber for the ContactsUpdateMessage. The class needs the same new imports and injection of the event aggregator as the detail class. In the list class instead of saving a reference to the event aggregator its subscribe function will be used to listen for the contact updated messages. The second part of the subscribe function takes a function to be called when a contact updated message is received. In this example when a contact updated message is received the function finds the proper contact and replaces it with the updated version.

import {EventAggregator} from 'aurelia-event-aggregator';
import {ContactUpdatedMessage} from 'Aurelia/ContactUpdatedMessage';

@inject(HttpClient, EventAggregator)
export class List{
    contacts = [];

    constructor(http, eventAggregator){
        http.configure(config => {
            config
              .useStandardConfiguration()
              .withBaseUrl('https://localhost:18907/api/');
        });

        this.http = http;
        eventAggregator.subscribe(ContactUpdatedMessage, message => {
            let updated = this.contacts
                              .filter(contact => contact.Id == message.contact.Id)[0];
            Object.assign(updated, message.contact);
        });
    }

}

With the above changes any edits to a contact will be reflected in the contact list as soon as the contact is saved.

Aurelia’s Event Aggregator Read More »

Aurelia Beta and the Unexpected Token

Aurelia hit beta on November 16th. The team kicked off the beta the following five days of blog post.

Day 1 – The Beta is Here!
Day 2 – Plugins
Day 3 – Documentation
Day 4 – Ecosystem
Day 5 – Aurelia Interface

ASP.NET 5 hit release candidate 1 two days after Aurelia hit beta and writing the migration from beta 8 to rc1 was my priority and then I took Thanksgiving week off. To get back in the swing of things I rebuild my contacts application with ASP.NET RC1.

After getting the ASP.NET parts done and moved on to rebuilding the Aurelia portions. Using my original blog on getting started with Aurelia and the new Aurelia getting started guide I got everything installed.

As you may have guessed it was a no go. I kept getting an unexpected token on @inject on any view model that was using dependency injection. I did a lot of comparing the working version to the non-working version but the files were identical.

After a quick google I found the answer on stack overflow. The problem was the babel options which can be found in config.js in the wwwroot folder. Here is the section in question from my pre-beta application.

babelOptions: {
  "optional": [
    "runtime",
    "optimisation.modules.system"
  ],
  "stage": 0
}

And the new version.

babelOptions: {
  "optional": [
    "runtime",
    "optimisation.modules.system"
  ]
}

As Jeremy Danyow points out in the above stack overflow answer either es7.decorators needs added to the optional section or to set the stage option to 0. I ended up with the following based on the new samples from the Aurelia team, which also matches the answer from Jeremy.

babelOptions: {
  "optional": [
    "es7.decorators",
    "es7.classProperties",
    "runtime",
    "optimisation.modules.system"
  ]
}

 

Aurelia Beta and the Unexpected Token Read More »