Menu

Skip to content
Conventional Coding

Conventional Coding

A Conventional Blog for Convention Based Coders

Author: jason

Using aurelia-dialog with Aurelia and WebPack

Posted on June 6, 2016 by jason

The Aurelia-webpack libarary is pretty awesome. It makes excellent use of Promises to handle pop-ups, and while it has a few shortcomings it ticks 95% of the boxes with very little overheads and no external dependencies.

But… getting it working with webpack is another matter altogether!

Because aurelia-dialog has embedded css, the normal loading methods in the webpack loader struggle, and they either embed things where they shouldn’t or apply the wrong loader. In addition to this, the module loader fails to find viewmodels if you use the class instance resolution through the DI container, so you have to work around that too.

Fortunately it’s pretty straightforward:

Modify your webpack.config.json file to recognise and handle the dialog specific css and html templates:

First modify the AureliaWebpackPlugin section of your file to include the dialog sub-module:

JavaScript
1
2
3
4
5
    new AureliaWebpackPlugin({
      includeSubModules: [
          { moduleId: 'aurelia-dialog' }
      ]
    }),

Now, we modify the CSS loader to tell it to run the aurelia-dialog css files through the raw loader:

JavaScript
1
2
{ test: /\.css?$/, loader: 'style!css', exclude: /aurelia-dialog/ },
{ test: /\.css?$/, loader: 'raw', include: /aurelia-dialog/ }

Finally, when we want to invoke a dialog, we have to use the string path and name of the moduleid instead of the usual class reference, for example:

JavaScript
1
return this.dialogService.open({viewModel: 'services/myPopupWindowsVM', model: whatIwanttopassin})

And that’s all there is to it.

Posted in Aurelia | Leave a comment

Aurelia – Dirty checking a function part 2

Posted on June 6, 2016 by jason

One problem with dirty checking is that unless you actually check for a changed value you will fire too many updates on an underlying bound control.

Sometimes this doesn’t matter, but if you’ve got something bound to a repeat.for, then it certainly does!

So here’s an extension to the previous & dirty binding behavior that ensures the change is only bound (and corresponding method in your VM is only called) if the value actually changes, and adds a nifty new callback feature to detect the changes in our VM:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import {sourceContext} from 'aurelia-binding';
 
export class DirtyBindingBehavior {
  bind(binding, source, event, period=140) {
    if (!binding.updateTarget) {
      throw new Error('Only property bindings and string interpolation bindings can be dirty checked.  Trigger, delegate and call bindings cannot be dirty checked.');
    }
    binding.interceptedupdateTarget = binding.updateTarget;
    binding.updateTarget = (a) => {
      if (this.isDirtyCheck(binding.value, a))
      {
        let propname = binding.sourceExpression.expression.name;
        let callevent = event || binding.source.controller.viewModel[`${propname}Changed`];
        if (typeof event == 'function')
          callevent(a, binding.value, propname);
        binding.interceptedupdateTarget(a);
      }
    };
    binding.dirtyTimer = setInterval(t => binding.call(sourceContext), period);
  }
 
  unbind(binding, source) {
    clearInterval(binding.dirtyTimer);
    binding.updateTarget = binding.interceptedupdateTarget;
    binding.interceptedupdateTarget = null;
  }
 
  isDirtyCheck(previous,current) {
    // Date types always change objects, so treat them specially
    if (typeof current.getMonth === 'function' && typeof previous.getMonth === 'function')
      return (previous.getTime() != current.getTime())
    // Basic types accept a simple comparator
    if (previous != current)
      return true;
    // but objects need to be deep-compared
    return JSON.stringify(previous) != JSON.stringify(current);
  }
}

The syntax for using this is:

XHTML
1
<p>Hi ${user.firstname & dirty} ${getLastname() & dirty}</p>

However, unlike the standard binding techniques, this binding will trigger a firstnameChanged and ‘getLastnameChanged` events, even if those properties are nested inside another object, or if they are methods!

You can also group your changes by specifying the event to be called in your VM:

XHTML
1
<p>Hi ${user.firstname & dirty:event=PropertyChanged} ${getLastname() & dirty:event=PropertyChanged}</p>

We can now provide a function such as PropertyChanged(newvalue, oldvale, propertyname) to detect the changes as they occur:

JavaScript
1
2
3
PropertyChanged(n,o,p) {
  console.log(`${p} changed from ${o} to ${n}`);
}

So wrapping this up in something usable:

XHTML
1
2
3
4
5
<p>First name: <input value.bind='user.firstname'></p>
<p>Last name: <input value.bind='user.lastname'></p>
<hr></hr>
<p>Separate fields: ${user.firstname & dirty:event=PropertyChanged} ${getLastname() & dirty:event=PropertyChanged}</p>
<p>Function: ${getFullname() & dirty:event=PropertyChanged}</p>

As we change things we get:

Simple!

Posted in Aurelia | Leave a comment

Aurelia – Easy logging with the LogManager

Posted on May 27, 2016 by jason

Writing debug output while developing is great. After a few days you have pages and pages of logs in your browser console, and when it comes time to run tests or deploy to UAT you can trawl through thousands of lines of code and comment them all out!

Or… you can use the built in Aurelia logger!  This lets turn on or off error output, and even choose the level so you can show only serious errors at deployment time. You can even add runtime options to switch the error level so you can get more detailed output on your live system.

So how do we make this as easy to use as the console? Simple, we simply create a module exposing the Aurelia logger like this:

log.js

log.js
JavaScript
1
2
import {LogManager} from "aurelia-framework";
export var log = LogManager.getLogger('insight');

Then in out code we say something like

JavaScript
1
import {log} from "../services/log";

Then, whenever we want to simply say

JavaScript
1
2
3
log.debug('Toaster loaded: ', this.toasterService);
log.info('Yes, I made it this far!');
log.error('Serious problem loading waffles');

Now, in our startup code, instead of the usual .developmentLogging() command, we can add something with a little more detail as to what we want to display, such as

JavaScript
1
2
3
4
5
import {LogManager} from "aurelia-framework";
import {ConsoleAppender} from "aurelia-logging-console";
 
LogManager.addAppender(new ConsoleAppender());
LogManager.setLevel(LogManager.logLevel.debug);

This tells Aurelia that by default we want our logs to go to the console, although we could also direct them to a remote logging service, and also sets the level at which we’d like to display them.

We can also now change the log level based on the URL:

JavaScript
1
2
3
LogManager.setLevel(window.location.search.match(/.*\?debug.*/i)
          ? LogManager.logLevel.debug
          : LogManager.logLevel.error);

Alternatively we could look for localhost in the host name to always enable debug logging on local test machines.

Note the use of the name ‘insight’ in the getLogger method. You can add your own application name there, and it will appear in the console log like this:

Awesome stuff!

Posted in Aurelia Development | Leave a comment

Aurelia – Dirty checking a function…

Posted on May 24, 2016 by jason

What happens if we have a function in our View that takes parameters?

JavaScript
1
2
3
userFullName() {
return this.firstName + ' ' + this.lastName;
}

Easy! We just say <div>${userFullName()}</div>!

But what happens if the users first or last name changes dynamically? Oh dear, functions are only evaluated once at bind time…

Hang on! Let’s make it a property accessor! They are by default dirty-checked!

JavaScript
1
2
3
get userFullName() {
return this.firstName + ' ' + this.lastName;
}

Easy! We just say <div>${userFullName}</div>!

OK… so now it’s updated every 120ms or so, and we can optimise it by adding @computedFrom() in front:

JavaScript
1
2
3
4
@computedFrom('firstName','lastName')
get userFullName() {
return this.firstName + ' ' + this.lastName;
}

So now it will only update when one of those dependent variables changes. Awesome.

Now, I use full-name in several places on-screen, so I want the full name displayed with a variable delimiter, so let’s add a parameter to the call of ‘delim’.

Uh-oh, accessors don’t allow parameters, so it’s back to a method. But methods don’t allow dirty checking or @computedFrom… or @observable…

There are two suggested options; Signals or dummy dependency parameters:

Signals involve adding a ‘signal’ call whenever you want something rebound, and as a messaging system they can be acknowledged by many fields.  In this case we can say

XHTML
1
<div>${userFullName(' ') & signal:'my-signal'}</div>

then in our code we might create lastNameChanged and firstNameChanged methods that call the signal method on an injected BindingSignaller:

JavaScript
1
signaler.signal('my-signal');

I’m not wild on this, as I don’t like arbitrary string event names, I don’t want to write interceptors for every property that might ever need a signal.

An alternative is to add dummy properties in the binding so that Aurelia automatically rebinds when one of them changes (thanks to some of @danyow’s awesome magic dependency detection).

JavaScript
1
2
3
userFullName(delimiter, ...params) {
return this.firstName + ' ' + this.lastName;
}

The syntax ...params is called a ‘spread’ operator and means ‘as many things as you like here’ (rather like the old **args in C coded apps)

Now in our view we can say <div>${userFullName(' ', firstName, lastName)}</div> and our function will only be called when a dependent property updates! Awesome…ish. Now we have exposed the underlying implementation of our model into our view, and what if our method has a dependency on the time, or on 5 different private variables?

A final option is to do some sort of periodic update.  We can use signals in a time:

JavaScript
1
setInterval(() => signaler.signal('my-signal'), 5000);

or we could write a binding behavior:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import {sourceContext} from 'aurelia-binding';
 
export class DirtyBindingBehavior {
  bind(binding, source, frequency=500) {
    if (!binding.updateTarget) {
      throw new Error('Only property bindings and string interpolation bindings can be dirty checked.  Trigger, delegate and call bindings cannot be dirty checked.');
    }
    binding.dirtyTimer = setInterval(t => binding.call(sourceContext), frequency);
  }
 
  unbind(binding, source) {
    clearInterval(binding.dirtyTimer);
  }
}

This example means we can say

XHTML
1
<div>${userFullName(' ') & dirty}</div>

to have the field auto-update every 500ms, or we can override the frequency inline to be every second:

XHTML
1
<div>${userFullName(' ') & dirty:1000}</div>

This is not ideal, as we can’t have a userFullNameChanged event method triggered on our model, but it is a workaround that requires very little intrusive code.

Use any dirty checking style binding behavior with extreme caution.  Performance can take a significant hit, but if it’s a suitable method, then go for it!

Posted in Aurelia Development Javascript | Leave a comment

WebPack bundle size blowout? Perhaps there’s more in there than you expect!

Posted on May 6, 2016 by jason

After writing a relatively simple application I discovered that the bundle size for my application had grown to 10.4MB!

Well, after a bit of diving into the un-minimized bundle I realised that when I included brace (a browserify compatible version of ace editor) it was helpfully including the syntax and support code for every syntax.

This isn’t webpack’s fault, it’s because somewhere in the solution there’s an expression such as require('mode/'+lang), so webpack does some smart regex on it and bundles the entire mode/ folder so it can always resolve at runtime, no matter what the variable lang is set to.

However, I know that I only use a handful of those, so how do we tell webpack to ignore the others?

It’s quite simple. There’s a plugin installed by default in webpack called ContextReplacementPlugin. This allows you to define a regex expression for the folder you want to filter items from, then specify the files to include in that folder.

So, for brace (or ace) we just use something like this:

JavaScript
1
new ContextReplacementPlugin(/brace[\\\/]mode$/, /^\.\/(javascript|html|json|css|text)$/)

We might as well do the same for moment, as in our case we only want a few en-* based language variations:

JavaScript
1
new ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(en-uk|en-us|en-au)$/),

(Don’t forget to add var ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin');  to the top of your webpack.config.js file)

It’s well worth checking the webpack build listing to see exactly what it’s including in there!

| Leave a comment

Dynamically adding row templates to a table in Aurelia – as-element

Posted on May 3, 2016 by jason

Seems an odd thing to thing to blog on, because it’s pretty simple, yes? We’ll just stick a <compose> tag inside the <table> tags, and choose the appropriate view to display for each row!:

XHTML
1
2
3
<table>
<compose repeat.for="r of ['A','B','A','B']" view='./template_${r}.html'></compose>
</table>

And we’ll create a couple of row templates called template_A.html:

XHTML
1
<template><tr><td>I'm an A Row</td><td>Col 2A</td><td>Col 3A</td></tr></template>

and template_B.html:

XHTML
1
<template><tr><td>I'm an B Row</td><td>Col 2B</td><td>Col 3B</td></tr></template>

Unfortunately things are not quite this simple.  When the browser loads in the template it very helpfully validates the structure of the HTML, notices that you have an invalid tag inside your table definition, and very unhelpfully removes it for you before Aurelia even gets a look-in.

So what is we add containerless to our compose statement? That will remove the ‘compose’ tags!  Well, still no good, as the browser has already removed the inner tag.

So, what we want is a way of saying “take this tag, which is valid in this location, but make it act as though it’s a completely different tag”

That’s where the attribute as-element comes in.  We can give Aurelia a <tr> tag but tell it to treat its contents as though it were a compose tag!

XHTML
1
2
3
<table>
<tr repeat.for="r of ['A','B','A','B']" as-element="compose" view='./template_${r}.html'>
</table>

Now why emphasise ‘contents’ in that sentence? Well, we can’t remove the containing tag completely, so in this case we have to remove the <tr> tags from our two templates:

template_A.html:

XHTML
1
<template><td>I'm an A Row</td><td>Col 2A</td><td>Col 3A</td></template>

template_B.html:

XHTML
1
<template><td>I'm an B Row</td><td>Col 2B</td><td>Col 3B</td></template>

 

Posted in Aurelia Javascript | Leave a comment

Calling external javascript from within Aurelia templates

Posted on May 2, 2016 by jason

While we’re used to simply sticking a <script> tags inside templates, this doesn’t work in Aurelia because the browser doesn’t treat injected DOM elements in the same way as traditional DOM manipulation.

So what happens when we want to do something like inject Google Ads or some sort of dynamically generated script from a remote location?

The code below is designed to address this.  It takes a URL as a parameter, then imply injects a script element to the body of your page, but maintains a reference so the block can be removed when the current tag is removed.

To use it, simply include the custom element like this:

XHTML
1
<scriptinjector url="http://whereverserveris/includethis.js"></scriptinjector>

You can add an optional binding attribute of is-async.bind='true' if you’d like the script to run asynchronously (see http://www.w3schools.com/tags/att_script_async.asp)

XHTML
1
<scriptinjector url="http://whereverserveris/includethis.js" is-async.bind='true'></scriptinjector>

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import {bindingMode, customElement, bindable, noView} from "aurelia-framework";
 
@noView()
@customElement('scriptinjector')
export class scriptinjector {
 
  @bindable url;
  @bindable isAsync;
  @bindable({defaultBindingMode: bindingMode.oneWay}) scripttag;
 
  attached() {
    if (this.url) {
      this.scripttag = document.createElement('script');
      if (this.isAsync) {
        this.scripttag.async = true;
      }
      this.scripttag.setAttribute('src', this.url);
      document.body.appendChild(this.scripttag);
    }
  }
 
  detached() {
    if (this.scripttag) {
      this.scripttag.remove();
    }
  }
}

Don’t forget to make the custom element visible to your view by using

<require from='scriptinjector'></require>

or by making it a global resource (Making features global in Aurelia)

But please don’t abuse this to inject things like jQuery into your solution 🙂  This is intended for very specific applications, where you have little or no control over an external script.

Credits to @TylerJPresley for the idea

| Leave a comment

Making features global in Aurelia

Posted on April 18, 2016 by jason

To avoid adding <require from='../components/mything'></require> to every view I use those components in, I create a file called globals.ts

JavaScript
1
2
3
4
5
6
7
8
9
10
export function configure(config) {
  config.globalResources([
    'component/date-format',
    'component/sort',
    'component/filter',
    'component/debug',
    'component/datepicker',
    'component/jsonEditor'
  ]);
}

and I add this to the main bootstrapper in my main.ts like this:

JavaScript
1
.plugin('component/globals'); // install our app's resources

Being Aurelia, there is nothing magical about the concept of a plugin, and behind the scenes it simply calls the configure() method during initialisation.  This makes it a convenient place to do some initialisation and avoids polluting my main start-up classes with references to other classes.

| Leave a comment

DateTime Picker in Aurelia (or one of many other jQuery attached components)

Posted on April 17, 2016 by jason

I wanted a simple, light(ish) weight date and time selector for our project.

Looking around, I found several datetimepicker NPM projects, and chose one (https://www.npmjs.com/package/jquery-datetimepicker) that gives a reasonably attractive appearance with (in my opinion) a much friendlier selection layout than many out there.

(Note that as with many jQuery plugins in JSPM you have to use jspm install npm:jquery-datetimepicker  -o "{format: 'global'}")

Adding it to Aurelia proved a little tricky though. First I thought I’d quickly ‘bodge’ it in to check the functionality, so I added some code to the attached() method of my view to call the jquery extension it had added:

XHTML
1
2
3
4
5
6
<input
  value.bind="options.deactivateDate"
  placeholder="Deactivate at..."
  type="datetime"
  ref="dt_activate"
/>

JavaScript
1
$(this.dt_activate).datetimepicker();

But things didn’t quite go as expected. While the popup appeared, and the value changed, it wasn’t being bound to the underlying deactivateDate in my object.

Well, it turns out that this is an issue in that jQuery doesn’t always fire change and input events when modifying values in input fields, so the easiest way to solve this is simply to call the event yourself.

So, I might as well bundle this whole thing into a custom attribute, saving the hassle of adding anything in attached() as this will be resolved automatically at the appropriate time:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import {inject, customAttribute} from 'aurelia-framework';
 
@customAttribute('datepicker')
@inject(Element)
export class DatePicker {
  constructor(private element) {
  }
 
  attached() {
    ($(this.element) as any).datetimepicker()
      .on('change', e => fireEvent(e.target, 'input'));
  }
 
  detached() {
    // remove it in here if possible!
  }
}
 
function fireEvent(element, name) {
  var event = document.createEvent('Event');
  event.initEvent(name, true, true);
  element.dispatchEvent(event);
}

I save this as datepicker.tsand add it to the list of global resources (so I don’t have to bother using <require> to import it), and my final front-end code looks like this:

XHTML
1
2
3
4
5
6
<input
  value.bind="options.deactivateDate"
  placeholder="Deactivate at..."
  type="datetime"
  datepicker
/>

The only other thing to do is to tidy the display up a bit, so it’s not displaying the date and time in full UTC format.

Simply done using a ValueConverter (using moment imported from NPM):

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
import * as moment from 'moment'
 
export class DateFormatValueConverter {
  toView(value) {
    console.warn('to', value);
    return moment(value).format('YYYY-MM-DD HH:mm');
  }
  fromView(value) {
    console.warn('from', value);
    return moment(value,'YYYY-MM-DD HH:mm');
  }
}

Bear in mind that this is being displayed in current time, not UTC, so you may choose to modify the converter to display locally but read and write as UTC to the underlying object.

So what does it look like?

Simple but effective.

Posted in Aurelia Development Javascript Typescript | 4 Comments

Dirty-Checking a Javascript object or value

Posted on April 12, 2016 by jason

Another quick change detection script that uses dirty-checking.

If you know that the number of elements or object complexity is relatively low, or if you’re hitting the Aurelia issues with array monitoring, why not try something different?

 

While a little naive in implementation (using stringify and parse to deep-copy) this gives back nice information as to exactly which changed node was first detected to fire the callback.

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
export class ChangeDetector {
 
  constructor() {
  }
 
  public observe(target:Object, property:string, callback:(n:any, o:any, name:string)=>void, checkspersecond?:number):()=>void {
 
    var subscription:{ timer:any, target:Object, property:string, previous:Object } = { timer:{}, target, property, previous:{} };
 
    subscription.timer = setInterval(() => this.compare(subscription, callback) , 1000/(checkspersecond || 7));
 
    return () => { clearInterval(subscription.timer); }
  }
 
  private compare(subscription:any, callback) {
    let s=subscription.target[subscription.property];
    let path = 'this';
    var diffs = this.finddiff(s, subscription.previous,0,path);
    if (diffs[0]) { callback(diffs[2], diffs[1], diffs[0] ); }
    subscription.previous = JSON.parse(JSON.stringify(s)) ;
  }
 
  private finddiff = function(previous,current, depth:number, path:string){
    let isarray = (current instanceof Array);
    for (var p in current) {
      if(typeof(current[p]) !== typeof(previous[p])) return [path+'.'+p,current[p] , previous[p]];
      if((current[p]===null) !== (previous[p]===null)) return [path+'.'+p,current[p],previous[p]];
      switch (typeof(current[p])) {
        case 'undefined':
          if (typeof(previous[p]) != 'undefined') return [path+'.'+p,undefined,previous[p]];
          break;
        case 'object':
          if(current[p]!==null && previous[p]!==null
             && (current[p].constructor.toString() !== previous[p].constructor.toString()))
                return [path+'.'+p, current[p], previous[p]];
          let nested = this.finddiff(previous[p],current[p], depth+1, path + (isarray ? '[' : '.')  + p + (isarray ? ']' : ''));
          if(!!nested.length) return nested;
          break;
        case 'function':
          if (p != 'equals' && current[p].toString() != previous[p].toString()) return [path+'.'+p, current[p],previous[p]];
          break;
        default:
          if (current[p] !== previous[p]) return [path+'.'+p, current[p], previous[p]];
      }
    }
    return [];
  }
 
}

 

Posted in Aurelia Development Javascript Typescript | Leave a comment

Post navigation

  • Older posts
  • Newer posts

Recent Posts

  • Javascript dates, adding days, and when exactly is this time tomorrow?
  • Aurelia Validation events
  • Aurelia – Debugging EventAggregator
  • Aurelia Validation – Part 3 – Custom rules and validations
  • Aurelia-Validation – Part 2 – Displaying our errors
  • Aurelia-Validation – The Aurelia Way
  • Aurelia Validation – the Treacherous way…
  • Aurelia – Dynamically choosing modules based on roles…
  • Aurelia – Error: No module factory available for dependency type: ContextElementDependency
  • Aurelia Async Bindings
  • Using aurelia-dialog with Aurelia and WebPack
  • Aurelia – Dirty checking a function part 2
  • Aurelia – Easy logging with the LogManager
  • Aurelia – Dirty checking a function…
  • WebPack bundle size blowout? Perhaps there’s more in there than you expect!
  • Dynamically adding row templates to a table in Aurelia – as-element
  • Calling external javascript from within Aurelia templates
  • Making features global in Aurelia
  • DateTime Picker in Aurelia (or one of many other jQuery attached components)
  • Dirty-Checking a Javascript object or value

Categories

  • angularjs
  • Architecture
  • Aurelia
  • Development
  • Interesting
  • Javascript
  • Typescript
  • Uncategorized
  • Validation
  • WebPack

Archives

  • January 2018
  • September 2016
  • August 2016
  • July 2016
  • June 2016
  • May 2016
  • April 2016
  • March 2016
  • February 2016

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org
©2016 Jason Sobell
Proudly powered by WordPress
Theme: Flint by Star Verte LLC