Skip to content

Instantly share code, notes, and snippets.

@fragsalat
Forked from jdanyow/app.html
Last active March 15, 2019 09:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fragsalat/e86e3f91abe31188a3cbe1e8b6952984 to your computer and use it in GitHub Desktop.
Save fragsalat/e86e3f91abe31188a3cbe1e8b6952984 to your computer and use it in GitHub Desktop.
Aurelia Gist
<template>
<h1>Children selected: ${allSelected}</h1>
<button click.delegate="add98Children()">Add 98 children</button>
<button click.delegate="add1Children()">Add 1 children</button>
<ul>
<li repeat.for="child of children">
${child.id} <input type="checkbox" checked.bind="child.selected" />
</li>
</ul>
</template>
import {computedFromList} from './computed-from-list';
export class App {
children = [{id: 0, selected: false}, {id: 1, selected: false}];
selectChildren(child) {
child.selected = true;
}
add1Children() {
this.children.push({id: this.children.length, selected: false})
}
add98Children() {
new Array(98).fill(0).forEach((v, i) => {
this.children.push({id: this.children.length + i, selected: false});
});
}
@computedFromList('children[*].selected')
get allSelected() {
console.log('get');
if (!this.children.length) return false;
return this.children.every(child => child.selected);
}
}
import {Parser, Expression, ComputedExpression, createOverrideContext} from 'aurelia-binding';
class ComputedListExpression extends Expression {
/**
* @param {string} expressionStr Expression string for one dependency
*/
constructor(expressionStr) {
super();
const parser = new Parser();
this.expressions = expressionStr.split('[*].').map(part => parser.parse(part));
}
/**
* Connect template interpolation to dependency. Once dependency is changed and subscribers are called this ensures
* the binding is notified for changes.
* @param {Binding} binding
* @param {Scope} rootScope
*/
connect(binding, rootScope) {
let currentScopes = [rootScope];
// Iterate trough expressions e.g. children => Array<Child>, isSelected => boolean
for (let expression of this.expressions) {
let scopes = [];
currentScopes.forEach(scope => {
scopes = scopes.concat(this.connectAndEvaluate(expression, binding, scope));
});
currentScopes = scopes;
}
}
/**
* Connect current expression to binding with current scope
* @param {Expression} expression
* @param {Binding} binding
* @param {Scope} scope
* @returns {Array<Scope>}
*/
connectAndEvaluate(expression, binding, scope) {
expression.connect(binding, scope);
const scopes = [];
let results = expression.evaluate(scope);
// If result is not a list make it to one
if (!Array.isArray(results)) {
results = [results];
}
results.forEach(result => {
scopes.push({bindingContext: result, overrideContext: createOverrideContext(result)});
});
return scopes;
}
}
/**
* Mark getter to be computed from a list. This decorator allows to use properties of objects in arrays as dependencies.
* This works like common computedFrom except that arrays can be accessed by appending [*]. to properties of type array
* @param {Array<string>} expressions Expressions like children[*].property
* @returns {Function}
*/
export function computedFromList(...expressions) {
return function(target, property, descriptor) {
const dependencies = expressions.map(expression => new ComputedListExpression(expression));
descriptor.get.dependencies = new ComputedExpression(property, dependencies);
};
}
<!doctype html>
<html>
<head>
<title>Aurelia</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</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