App with just Aurelia binding, and templating?

Anyone know of instructions for enabling a simple web app to use only the Aurelia binding functionality?

And then what would be the second step in adding templating to the app (if they don’t always go together)?

Which libraries would be required, and what kind of runtime initialization?

Thanks!

function configure(aurelia: Aurelia): void {
 aurelia.use
        .defaultBindingLanguage()
        .defaultResources()
 aurelia.start().then(() => aurelia.setRoot('app', document.body));
}

Thanks Alexander-Taran.

The example you give is pulling in the Aurelia framework, starting it as if there is routing and so on. I don’t want to do that. I just want binding and maybe templating functionality without any other over-arching framework. I can manually tell the binding engine to bind the html to the viewmodel. My question is about how I would make this happen from the point of view of packaging and any necessary higher-level initialization. Is it not possible without Aurelia.start, setRoot and so on?

1 Like

I think what you may need to use is enhance instead of setRoot. I threw together a quick example on git hub which can be found here:aurelia enhance example
there is also a short description in the documentation about it.
Progressive Enhancement

1 Like

Interesting lancelot316! Yes, I was intending to use enhance, but didn’t know about the one that hangs off aurelia.start().

From the responses so far, I’m getting the impression that supplying configure(aurelia) and calling aurelia.start() are mandatory to do binding and templating. Do you think that is correct?

Yes… bottstrapper + framework compose basic services like DI, loader, PAL and so on.

1 Like

Yes I think that is correct. The configure(aurelia) function called as part of the bootstrapping of the framework. I think the simplest configure function you can have is something like

export function configure(aurelia) {
    aurelia.use
        .standardConfiguration()
        .feature('resources');
     
    aurelia.start().then(() => aurelia.enhance());
}

All your code for your components could then be placed in the resources folder and registered using the index.js file in that folder.

.standardConfiguration() will pull in router and history… Not what op wanted (-:

http://aurelia.io/docs/fundamentals/app-configuration-and-startup#bootstrapping-aurelia

1 Like

Maybe something like this would work better then

export function configure(aurelia) {
    aurelia.use
       .defaultBindingLanguage()
       .defaultResources()
       .eventAggregator();

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

I think this should configure the default data-binding language (.bind, .trigger, etc.), the default set of view resources (repeat, if, compose, etc.), and the event aggregator (app-wide pub/sub messaging).

more info can be found in the docs at Bootstrapping Aurelia

1 Like

aurelia-binding is a collection of classes that handle data binding for input, event, checked, select, property observation.

aurelia-templating is a collection of classes that handle html template compilation and rendering, creating Containers for instances to help proper dependency injections

aurelia-templating-binding is a collection of classes that help you to wire aurelia-templating and aurelia-binding together, as by default aurelia-templating does not understand attributes such as prop.bind="value". It’s the job of this lib to desugar those binding commands into proper binding expressions and instances. How special bindings, prop of a custom attribute or custom element should be created, is based on the information of resources (ViewResources class) passed by aurelia-templating when doing compilation.

aurelia-framework is a collection of classes that wire those thing together, to register resources, default binding language, to translate prop.bind="value"

aurelia-bootstrapper is a collection of functions that help ensure all requirements of an Aurelia application have been supplied, and init an instance of Aurelia.


From the look of those, it’s not very desirable to use only Aurelia binding. But if insisted, you can use the Parser to parse expression, and use it to evaluate value from a given object / value. BindingEngine to observe property of an object, or collection mutations. I bet you will eventually arrive where Aurelia currently is. But maybe you can do it better that what we have, so if you could give some more information on what you are trying to achieve, folks can help better.

3 Likes

Hi guys,

I’ve been looking at this feature occasionally over the years and I came back to this again.

What would be highly desirable is to have simple way to enhance single server rendered HTML page. I think this is use case that would help introduce bunch of people to Aurelia, if implemented properly.

Additionally, this is something that @EisenbergEffect promised during while making 1st presentations of still to be finalized Aurelia Framework back in the day.

Currently, Vue does this very well as described in Getting started examples:

Or, same example in the static page from scratch (Bootstrap 5.1 + Vue 2.6):

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
        <title>Test data-bindings on the static page with the Vue js</title>
    </head>
    <body>
        <div id="my-app" class="container">
            <h1>Form with binding, example</h1>
            <form class="form" v-on:submit.prevent>
                <div class="form-group">
                    <label>Message:
                        <input type="text" class="form-control" v-model="message" />
                    </label>
                </div>
                <button class="btn btn-primary" v-on:click="reverseMessage">Reverse Message</button>
            </form>
            <p>
                {{ message }}
            </p>
        </div>
        
        <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha256-85WHXrXVjFEoxDSBLNClPUOLEVNvf9FXcHfYpcYS4f0=" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
        <script deffer src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js" integrity="sha256-kXTEJcRFN330VirZFl6gj9+UM6gIKW195fYZeR3xDhc=" crossorigin="anonymous"></script>
        <script>
            new Vue({
                el: '#my-app',
                data: {
                    message: 'Hello Vue.js!'
                },
                methods: {
                    reverseMessage: function () {
                        this.message = this.message.split('').reverse().join('');
                        return false;
                    }
                }
            });
        </script>
    </body>
</html>

If this would be possible to achieve with Aurelia 2, even better!

1 Like

Hi guys,

I managed to make almost identical sample using Aurelia 2 from CDN:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
        <title>Test data-bindings on the static page with the Aurelia 2</title>
        <script type="importmap">
            {
                "imports": {
                    "aurelia": "https://cdn.jsdelivr.net/npm/aurelia@2.0.0-alpha.21/dist/native-modules/index.js",
                    "my-app": "/js/my-app.js"
                }
            }
        </script>
    </head>
    <body>
        <div id="my-app" class="container">
            <div class="card">
                <div class=card-header>
                    Form binding with Aurelia v2
                </div>
                <div class="card-body">
                    <form>
                        <label>
                            Message:
                            <input type="text" class="form-control" value.bind="message" />
                        </label>
                        <button class="btn btn-primary" click.trigger="reverseMessage()">Reverse Message</button>
                    </form>
                    <p>
                        ${ message }
                    </p>
                </div>
            </div>
        </div>
        
        <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha256-85WHXrXVjFEoxDSBLNClPUOLEVNvf9FXcHfYpcYS4f0=" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
        <script type="module" src="https://cdn.jsdelivr.net/npm/aurelia@2.0.0-alpha.21/dist/native-modules/index.js" integrity="sha256-fveymNY/nns8uk5KeuFTcdXdmAPvnXvNda5CJUCX/fU=" crossorigin="anonymous"></script>
        <script type="module">
            import Aurelia from 'aurelia';

            class MyApp {
                message = "Hello Aurelia 2!";

                reverseMessage() {
                    this.message = this.message.split('').reverse().join('');
                }
            }

            Aurelia
                .enhance({
                    host: document.querySelector('#my-app'),
                    component: MyApp
                });
        </script>
    </body>
</html>

Here is the Fiddle link.

If I could only improve it to load only needed components (no fetch-client, router, route-recognizer…), that would be awesome!

3 Likes

i think thats more up to how the hosted built aurelia2 file is. it already includes all the things needed, so you’d need a dedicated naked aurelia core.

1 Like

I agree for the main aurelia module - it has all the imports inside it, including once that are not needed for the use case where we just want to enhance element on the static page.

I would be fine going in direction of creating my own main.js with custom enhance method and importing only needed aurelia modules, but I’m not even sure if it’s possible to do in a such granular way.

1 Like

At the moment, the main bundle of the aurelia module is supposed to be used with a bundler, so that all the unnecessary bits for an application can be shaken off. What we can do is to provide some different dists that only include the basic, which is the equivalent of only kernel/runtime/runtime-html in it.

If an application only wants binding & templating, it can be done such as:

import { Aurelia, StandardConfiguration } from '@aurelia/runtime-html'

new Aurelia()
  .register(StandardConfiguation)
  .app({
    component: class MyApp {},
    host: document.querySelector('my-app')
  })
  .start()
2 Likes

@bigopon Thanks a lot, man! I have few corrections for your example to work, but you put me on the right track!

First, easy one, you have a typo in .register(StandardConfiguation), r missing in configuration. But more importantly, your example is throwing an exception, because of missing metadata for MyApp class.

So my JavaScript snippet ended up looking like this:

<script type="module">
    import { Aurelia, StandardConfiguration } from '@aurelia/runtime-html';

    class MyApp {
        message = "Hello Aurelia 2!";

        reverseMessage() {
            this.message = this.message.split('').reverse().join('');
        }
    };

    new Aurelia()
        .register(StandardConfiguration)
        .enhance({
            host: document.querySelector('#my-app'),
            component: MyApp
        });
</script>

I use native ES modules and <script type="importmap"> at the top of the page. Here is the link to working JS Fiddle.

This is full code of static HTML page:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
        <title>Test data-bindings on the static page with the Aurelia 2</title>
        <script type="importmap">
            {
                "imports": {
                    "@aurelia/runtime-html": "https://cdn.jsdelivr.net/npm/@aurelia/runtime-html@2.0.0-alpha.21/dist/native-modules/index.js"
                }
            }
        </script>
    </head>
    <body>
        <div id="my-app" class="container">
            <div class="card">
                <div class=card-header>
                    Form binding with Aurelia v2
                </div>
                <div class="card-body">
                    <form>
                        <label>
                            Message:
                            <input type="text" class="form-control" value.bind="message" />
                        </label>
                        <button class="btn btn-primary" click.trigger="reverseMessage()">Reverse Message</button>
                    </form>
                    <p>
                        ${ message }
                    </p>
                </div>
            </div>
        </div>
        
        <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js" integrity="sha256-85WHXrXVjFEoxDSBLNClPUOLEVNvf9FXcHfYpcYS4f0=" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.min.js" integrity="sha384-skAcpIdS7UcVUC05LJ9Dxay8AXcDYfBJqt1CJ85S/CFujBsIzCIv+l9liuYLaMQ/" crossorigin="anonymous"></script>
        <script type="module" src="https://cdn.jsdelivr.net/npm/@aurelia/runtime-html@2.0.0-alpha.21/dist/native-modules/index.js" integrity="sha256-tqalVl0aB3Jqx/px/QMCBSXH0VRzI9UTxOAe/VgVC/4=" crossorigin="anonymous"></script>
        <script type="module">
            import { Aurelia, StandardConfiguration } from '@aurelia/runtime-html';

            class MyApp {
                message = "Hello Aurelia 2!";

                reverseMessage() {
                    this.message = this.message.split('').reverse().join('');
                }
            };

            new Aurelia()
                .register(StandardConfiguration)
                .enhance({
                    host: document.querySelector('#my-app'),
                    component: MyApp
                });
        </script>
    </body>
</html>

I honestly think you guys should put this use-case in getting started documentation for version 2. This can be entry point for acquiring new Aurelia users.

2 Likes

glad to see you got your example working. Our docs btw are driven by a github repo, so feel free to create a PR where you see the example fit.

1 Like

@zewa666 I think it would be good if someone from the core team throws his opinion about my example, before we rush into writing docs.

It could be that this feature needs a bit more love, before final v2 release. For example, bundled version of runtime-html together with dependencies, as build artifact (and available on CDN) as @bigopon suggested.

I just compared performance of my View example to Aurelia 2 example. Even though they are both trivial at the moment, Vue “grabs” template and inserts correct values in half of the time that Aurelia needs. Most obvious part of the delay is time spent on network requests for each aurelia module.

2 Likes

in this case I’d ask you to turn this to an github issue and continue the necessary parts there if there’s additional work to be done. this helps with keeping things focused and allows priorization

1 Like

I found this example quite interesting.
Have you worked out how to observe properties?
I didn’t realize how to declare @observable and/or @bindable in this case.

Regards,

2 Likes