Skip to content

Instantly share code, notes, and snippets.

@jdanyow
Last active March 30, 2018 14:46
Show Gist options
  • Save jdanyow/720d20b2db5adba92f62f7e665cf3b96 to your computer and use it in GitHub Desktop.
Save jdanyow/720d20b2db5adba92f62f7e665cf3b96 to your computer and use it in GitHub Desktop.
<template>
<require from="./dynamic-expression-binding-behavior"></require>
<require from="./debug"></require>
<label repeat.for="property of properties">
${property.label}
<input value.bind="model & dynamicExpression:property.expression">
</label>
<debug></debug>
</template>
export class App {
model = {
firstName: 'John',
lastName: 'Doe',
address: {
address1: '1 Main Street',
address2: '',
city: 'Burlington',
state: 'VT',
zip: '05401'
}
};
properties = [
{ label: 'First Name', expression: 'firstName' },
{ label: 'Last Name', expression: 'lastName' },
{ 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">
<style>
label, input {
display: block;
margin-bottom: 10px;
}
</style>
</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