Friday, June 24, 2016

I love Aurelia - Data binding always just works

Today, I needed to add a Twitter Bootstrap Tooltip to my Aurelia app. Easy enough, just create a custom attribute to handle the javascript registering and unregistering, then add the data- attributes to make it all work.

Except, this tooltip contains the password rules, and I want to use it in several places on my app. I don't want to create another custom attribute, I just want to bind the title to a value from my viewmodel.

So I write:

<input type="password" value.bind="password" bootstrap-tooltip 
       data-container="body" data-html="true" data-placement="bottom" data-toggle="tooltip" 
       title.bind="passwordRules">

and, of course, it just works. That's what I love about the syntax of Aurelia. They don't have to think of every use-case, they built the right abstraction in the first place.

FYI, if you get here looking for how to do the custom attribute, here's that code (thanks to Jeremy Danyow):
import {inject} from 'aurelia-framework';
import $ from 'jquery';
import 'bootstrap';

@inject(Element)
export class BootstrapTooltipCustomAttribute {
  constructor(element) {
    this.element = element;
  }

  bind() {
    $(this.element).tooltip();
  }

  unbind() {
    ${this.element).tooltip('destroy');
  }
}

Friday, May 06, 2016

Getting started with MediatR and Unity

I've been able to put off figuring our how to properly manage the WebApi controllers in this new project because everything has been in "just make it work" mode, and I was not happy with any of the patterns I had used before. I've been reading about MediatR for a while now, and yesterday I had the chance to try and use it to manage the controller actions.

Short story, it worked almost right away. That was cool. However, MediatR requires a bit more "inside knowledge" type of configuration than do a lot of packages that I have used in the past. In this case, I had to figure out how to set up my Unity containers so that MediatR would be happy with them. Thankfully, there is code on the site that configures a Unity container, but it didn't work for me. This is the code currently in the MediatR samples (here):

    container.RegisterTypes(
        AllClasses.FromAssemblies(GetType().Assembly),
        WithMappings.FromAllInterfaces,
        GetName,
        GetLifetimeManager);

When I used this, I got an error at startup telling me that I was attempting to override and existing mapping to System.Web.Http.Controllers.IHttpController, moving it from one controller class in my project to another. Clearly, I had to tweak the registration. In the end, this is what I came up with:

    container.RegisterTypes(
        MediatRType()
        WithMappings.FromAllInterfaces,
        GetName,
        GetLifetimeManager);
and
    private IEnumerable MediatrTypes()
        {
            var _t = GetType().Assembly.DefinedTypes;
            var types = _t.Where(f => !f.IsInterface && f.GetInterfaces().Any(x => x.IsGenericType && (x.GetGenericTypeDefinition() == typeof(INotificationHandler<>) || x.GetGenericTypeDefinition() == typeof(IAsyncNotificationHandler<>) || x.GetGenericTypeDefinition() == typeof(IRequestHandler<,>) || x.GetGenericTypeDefinition() == typeof(IAsyncRequestHandler<,>) || x.GetGenericTypeDefinition() == typeof(IRequest<>))));
            return types;
        }

I'm thinking I should issue a pull request; I think this is a better mechanism.

Thursday, March 17, 2016

Aurelia - sharing some code

As I mentioned in my previous post, I'm getting ready to put some code out on GitHub. This is a first for me, so I'm sure I missed a couple of things. But my first repository is now up, a wrapper around the bootstrap-switch component. You can install it via jspm.

Let me know what I haven't configured correctly.

Cleaning up jspm forks in my Aurelia project

These are just some notes so that the next time I need this, I will know where to look. And if they happen to help anyone else, all the better.

A couple of nights ago I grabbed the latest and then did a jspm update on my site. Everything ran great until the end, when I suddenly found myself with 7 forks. Now, you have to know, this project has been perfect for weeks now. The last time this happened, I threw up my hands and just grabbed the latest package.json and config.js from the github repository. Today, I decided it was time to man up and figure out what was happening. Here is what I learned.

Some time ago, for reasons that may no longer exist, I added specific dependencies on aurelia-pal, aurelia-templating and aurelia-depenency-injection to my project. (I will learn later today if I still need those). Because I had specific dependencies on those projects, as they upgraded, I eventually fell behind. To be honest, I'm not sure why I fell behind, but a couple of days ago, the update ended up installing both the newest versions needed by the framework and the specific version I had added to my config.js.

The solution was simply to update the hard-coded dependencies in config,js. In my case, I deleted them, since I'm not even sure I need the direct reference.

So, what I learned is that the forks come from config.js. Maybe those who are more familiar with jspm already knew this, but I didn't.

And for now, I do. Until I learn more. Then I might just update this post.

Wednesday, December 30, 2015

Aurelia - handling validation of bound properties in a custom element

As I have mentioned before, much of my application consists of custom elements. This is one of the major tools that Aurelia provides for managing complexity. However, there is a trade-off, and it comes from the asynchronous nature of the framework. Once I move some of my UI and code into a custom element, the relationship between the parent and the child becomes asynchronous, managed through the data binding process. This means that the custom element does not have access to the data in the parent in its constructor, but only once the attached() method is called.

I have a couple of custom elements with their own validation, and in some cases, I want the message for the validation to be dependent on properties that are data bound. If I set the validation up in the constructor, I won't get the correct message.

So I set it up in attached(). It's really that simple. Some of my validation is in the constructor, and some in attached().

Friday, December 18, 2015

Aurelia - Initializing properties in custom elements

I'm working on wrapping a couple of external controls into Aurelia custom elements. I'm nearly done, and about to put them out onto Github. In my initial implementation, I only exposed the capabilities of the underlying control that I was going to use, but now that I'm about to push them into the public, I thought I should probably make some effort at exposing a bit more.

In one case, I have a control that offers about 20 properties that can be configured, but in reality, most will be set only at initialization, so I decided as a first pass to make them one-time, initialization-only properties. But I didn't want to clutter my component with 20 properties, so an init property seemed the best solution (thanks, BTW, to @stoffeastrom for his help on getting the syntax right). Here's what I ended up with.

In the view model, I have:

import {inject, bindingMode, bindable} from 'aurelia-framework';

@bindable ({
    name: 'init', 
    defaultBindingMode: bindingMode.oneTime
})
@inject(Element)
export class MyElementCustomElement {
    constructor(element, bindingEngine) {
        this.element = element;
    }

    bind() {
        let init = {};
        if (this.init) {
            Object.assign(init, this.init);
        }

        // Use init to initialize the underlying control
    }
}

Then, when I use the custom element, I write:

<my-element init.bind="{size: 'small', onText: 'Readonly', offText: 'Editable'}"></my-element>

The properties size, onText and offText are properties of the underlying control.

One thing that caught me was the use of init.bind, rather than just init. When you have a bindable property on a custom element, but you want to bind it to a static string, you don't use .bind. Since my first thought was that the set of initial properties was a static entity, I didn't need .bind. Wrong. I want Aurelia's binding engine to parse the property into an object for me so that I can use it to initialize the underlying control. Thus, I have to use .bind, even though the property is not bound to my view model.

Again, is there anything I want to do that Aurelia won't help me with?

Aurelia - binding and custom elements

One more thing that seems to bite me with custom elements. By default, attributes of custom elements are one-way bound. That means, if I do

    <my-element attribute.bind="somethingFromMyViewModel"></my-element>

Then if the custom element changes the value of attribute, that change will not be reflected in somethingFromMyViewModel. The simple fix is to do:

    <my-element attribute.bind="somethingFromMyViewModel"></my-element>

That has the downside of having to remember it every time. If you have a view model, then you can change the default for a binding. To simply change this one binding to two way, you need only do add:
import {bindable, bindingMode} from 'aurelia-framework';

@bindable ({
  name: 'attribute',
  defaultBindingMode: bindingMode.twoWay
})
export class MyElementCustomElement {
}

Unfortunately, right now you have to have a view model to change the default binding. If you have an HTML-only component, you are stuck.

Thursday, December 17, 2015

Aurelia - making custom element global

This isn't anything earth-shattering. In fact, you can probably find almost the exact same thing somewhere else. But part of my purpose in writing this blog is to centralize the knowledge that I have acquired while working on this Aurelia project so that my team can come here to learn. In that spirit, a short post on making resources globally available.

If you have a custom element (or attribute, but I have not yet worked with a custom attribute, weird), you can reference it in your html file with a simple require:

<require from="../components/my-custom-element"></require>

Simple enough, and you can then use the custom element in your view. However, that can get tedious, especially with elements that you use all over your web site. For that, Aurelia provides a very simple mechanism, aurelia.use.globalResources. Simply add it to your main.js chain, passing the path to your view/view-model pair, and you're good:

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging()
    .globalResources('./components/my-custom-element');

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

This is great for one or two custom elements, but as your app grows and you centralize more of your look and feel into re-usable custom elements, this can get unwieldy. For that, another method comes into play: aurelia.use.feature. Simply move all of your custom elements into a single folder (you already did that anyways, right?) add an index.js to that folder, and change the above to:

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging()
    .feature('components');

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

The index.js file in the components folder has a method configure with a call to globalResources, with all of the custom elements as parameters:

export function configure(aurelia) {
  aurelia.globalResources('./my-custom-element', './some-custom-attribute', './file-loader');

There is no limit on the number of parameters other than a javascript limit on the number of parameters. If you hit that limit, or for more practical reasons, you can have multiple calls to globalResources chained as well:

export function configure(aurelia) {
  aurelia
    .globalResources('./my-custom-element', './some-custom-attribute', './file-loader')
    .globalResources('./more-good-stuff');
}

Currently, I have two folders of features: One contains my custom elements, the other my value converters. Each has its own index.js file and both are referenced in main.js (this is my actual main.js as of this writing):

export function configure(aurelia) {
  aurelia.use
    .standardConfiguration()
    .developmentLogging()
    .plugin('aurelia-validation', (config) => { config.useViewStrategy(TWBootstrapViewStrategy.AppendToMessage); })
    .plugin('aurelia-dialog')
    .feature('resources')
    .feature('components');

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

}


One little side note. Don't forget the ./ at the beginning of paths to resources in the same folder. In my experience, nothing bad happens until you are close to deadline, then the templating engine fails to find your resource :-) Actually, it's just the right way to do it, and it will break some things if you omit it.

Aurelia - A use case for view-model.ref

A couple of days ago I blogged on how to get access to the view model of a custom element. When I wrote it, my use case was calling a method of the view model from the containing component. As happens so often, once I had done this, another use case came up. I think this one is sufficiently interesting to warrant another post.

I have two independent components. One displays the current version of a banner image, and the other is the styled file picker that I use to select a file. What I want is for the component that shows the current banner image to display an indicator when the user has selected a new image but hasn't saved it, since I cannot show the new image on the web page until they actually upload it.

What I don't want to do is add a property to the view model of the page. The page itself doesn't care about this interaction and doesn't need to do anything to mediate it. It is an accidental participant in the process, and so adding a property just to allow the two components to interact seems ugly. Fortunately, I don't have to. The file upload component already has a property hasFileSelected, and the display component needs a property imageChanged, so I can just write the following in the HTML:

    <banner-image src.bind="bannerImageUrl" image-changed.bind="filePicker.hasFileSelected"></banner-image>
    <file-picker url.bind="ui.bannerImageUrl" view-model.ref="filePicker"></file-picker>

Notice how the banner-image component binds the image-changed property to the file-picker's hasFileSelected using the ref. Simple. Everything is done in the view, where it makes the most sense.

This is one of the things that I am loving about Aurelia, the ability to leverage on HTML when it makes sense. Sometimes, the complexity of a javascript view model is more than you need, and with Aurelia, you don't need it.

Tuesday, December 15, 2015

How I got an image to the backend of my Aurelia site

Yesterday's task was supposed to be easy enough: everything else in my configuration page is being saved to the backend, time to make the banner image save. I'm using the Aurelia fetch client, and I figured it couldn't be that hard.

You'll notice I said "yesterday's", because I went to be last night with my banner images still firmly locked into the front end. However, stepping away, and some sleep, and I have a solution. It is NOT idea, I think. There may be a better solution, and if I find one, I will blog about it here.

In the end, I was not able to coerce the fetch client to send the data in a way that I could consume it. I will keep looking. But all of the examples of sending form data via AJAX to a .NET backend used jquery, so I dropped into jquery.

My C# is pretty straightforward WebApi 2:

    [Route("user/{zid}/frontend/{feId}/banner")]
    [HttpPost]
    public IHttpActionResult SaveBanner(string zid, string feId)
    {
        if (!System.Web.HttpContext.Current.Request.Files.AllKeys.Any()) return Ok();

        var httpPostedFile = System.Web.HttpContext.Current.Request.Files["BannerImage"];
        if (httpPostedFile == null) return Ok();

        using (var ms = new MemoryStream())
        {
            httpPostedFile.InputStream.CopyTo(ms);
            var response = _repository.SetBanner(zid, feId, ms.GetBuffer() });
            if (response.Success) return Ok();
            return BadRequest();
        }
    }

The javascript is a bit trickier. I know it is going to be possible to save the banner image and all of the other settings in one call to the backend, but right now it's done with two. So I end up with javascript that first uses the fetch client to save the other settings, represented by a JSON string, and then a jquery ajax call to save the image:

    updateUISettings(feId, feSettings, bannerImage) {
        let url = `/vt/user/${this.zid}/frontend/${feId}`;
        
        let content = {
            Name: feName,
            Settings: feSettings
        };
        return this.put(url, content)
            .then(response => {
                if (bannerImage) {
                    let bannerUrl = `{$root}/${url}/banner`;
                    var data = new FormData();
                    data.append("BannerImage", bannerImage);
                
                    return new Promise((accept, reject) => {
                        $.ajax({
                            type: "POST",
                            url: bannerUrl,
                            contentType: false,
                            processData: false,
                            data: data
                        })
                        .done((data, textStatus, xhr) => {
                            accept(response);
                        })
                        .fail((xhr, textStatus) => {
                            reject(textStatus);
                        });
                    });
                } else {
                    return response;
                }
            });
    }

Amazingly, it works.

For which I am grateful, as I have a demo today, and I wanted this front-end configuration piece to be complete.

Aurelia - Leveraging the view model of an included element.

Thanks to everyone on the Gitter channel who helped me get this to work.

I have a simple little component that happens to have its own "api", a method it exports from its viewmodel so that containers can interact with it. I needed to be able to call it, but couldn't figure out how.

The Cheat Sheet clearly indicates that you can use ref to create a reference to a view model, but I never thought about the implications, since the only time I had used ref was to use that reference in the HTML in a view-only control. But this ref that you create is also usable from the view model of the container. That means, I can do this:
    <my-image url.bind="bannerImageUrl" view-model.ref="image"></my-image>

and then reference it from the container javascript, like this:
    this.image.doSomething();

It turns out that using ref just adds that name to your view model, as a reference to that entity. This is pretty cool, since you can do:
  • ref="someIdentifier" or element.ref="someIdentifier" - This gets you the HTML element from the DOM, which means that you can manipulate is from both your HTML and your javascript.
  • attribute-name.ref="someIdentifier" - This gets you the view model for a custom attribute. Since this is a javascript object, you can do anything with it you would expect.
  • view-model.ref="someIdentifier" - This gets you the view model for a custom attribute. Again, this is just javascript, hack away!
  • view.ref="someIdentifier" - This gets you the View object behind the custom element's view. As teh docs say, this is not the DOM element (you use ref for that) but rather a class from the Aurelia framework that you acn leverage to query and manipulate the view. This class is documented in the templating section of the docs.
  • controller.ref="someIdentifier" - This gets you the controller for the custom element. Again, this class is documented in the templating section of the docs.

I think that I shall never plumb the depths of the binding system for Aurelia. There is almost nothing you cannot do, it seems.