Skip to content

Instantly share code, notes, and snippets.

@AshleyGrant
Forked from jdanyow/app.html
Last active February 5, 2019 18:21
Show Gist options
  • Save AshleyGrant/8fb1a6c144253b7f361145b1b5f7b05c to your computer and use it in GitHub Desktop.
Save AshleyGrant/8fb1a6c144253b7f361145b1b5f7b05c to your computer and use it in GitHub Desktop.
Wizardry With Binding Behaviors
<template>
<require from="./dynamic-expression-binding-behavior"></require>
<require from="./debug"></require>
<form role="form">
<div class="form-group col-sm-7" repeat.for="field of fields">
<label for="${field.expression}">
${field.label}:
</label>
<input type="text" value.bind="model & dynamicExpression:field.expression"
id="${field.expression}" class="form-control" />
</div>
</form>
<debug></debug>
</template>
export class App {
model = {
name: 'Ashley Grant',
address: {
address1: '1 Main Street',
address2: '',
city: 'Tallahassee',
state: 'FL',
zip: '32399'
}
};
fields = [{
label: 'Name',
expression: 'name'
},{
label: 'Address 1',
expression: 'address.address1'
},{
label: 'Address 2',
expression: 'address.address2'
},{
label: 'City',
expression: 'address.city'
},{
label: 'State',
expression: 'address.state'
},{
label: 'Zip',
expression: 'address.zip'
}];
}
<template>
<pre><code>${json}</code></pre>
</template>
export class Debug {
bindingContext = null;
updateJson() {
if (this.bindingContext === null) {
this.json = 'null';
} else if (this.bindingContext === undefined) {
this.json = 'undefined'
} else {
// todo: use a stringify function that can handle circular references.
this.json = JSON.stringify(this.bindingContext, null, 2);
}
}
bind(bindingContext) {
this.bindingContext = bindingContext;
this.updateJson();
this.interval = setInterval(::this.updateJson, 150);
}
unbind() {
this.bindingContext = null;
clearInterval(this.interval);
}
}
import {inject} from 'aurelia-dependency-injection';
import {Parser} from 'aurelia-binding';
import {rebaseExpression} from './expression-rebaser';
@inject(Parser)
export class DynamicExpressionBindingBehavior {
constructor(parser) {
this.parser = parser;
}
bind(binding, source, rawExpression) {
// Parse the expression that was passed as a string argument to
// the binding behavior.
let expression = this.parser.parse(rawExpression);
// Rebase the expression
expression = rebaseExpression(expression, binding.sourceExpression);
// Squirrel away the binding's original expression so we can restore
// the binding to it's initial state later.
binding.originalSourceExpression = binding.sourceExpression;
// Replace the binding's expression.
binding.sourceExpression = expression;
}
unbind(binding, source) {
// Restore the binding to it's initial state.
binding.sourceExpression = binding.originalSourceExpression;
binding.originalSourceExpression = null;
}
}
import {ExpressionCloner, AccessMember, CallMember} from 'aurelia-binding';
export class ExpressionRebaser extends ExpressionCloner {
constructor(base) {
super();
this.base = base;
}
visitAccessThis(access) {
if (access.ancestor !== 0) {
throw new Error('$parent expressions cannot be rebased.');
}
return this.base;
}
visitAccessScope(access) {
if (access.ancestor !== 0) {
throw new Error('$parent expressions cannot be rebased.');
}
return new AccessMember(this.base, access.name);
}
visitCallScope(call) {
if (call.ancestor !== 0) {
throw new Error('$parent expressions cannot be rebased.');
}
return new CallMember(this.base, call.name, this.cloneExpressionArray(call.args));
}
}
export function rebaseExpression(expression, baseExpression) {
let visitor = new ExpressionRebaser(baseExpression);
return expression.accept(visitor);
}
<!doctype html>
<html>
<head>
<title>Aurelia</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body aurelia-app>
<h1>Loading...</h1>
<script src="https://jdanyow.github.io/rjs-bundle/node_modules/requirejs/require.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/config.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/bundles/aurelia.js"></script>
<script src="https://jdanyow.github.io/rjs-bundle/bundles/babel.js"></script>
<script>
require(['aurelia-bootstrapper']);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment