Skip to content

Instantly share code, notes, and snippets.

@AdamWillden
Last active July 24, 2017 12:48
Show Gist options
  • Save AdamWillden/1c40e1039593d25b06567322db4f8b17 to your computer and use it in GitHub Desktop.
Save AdamWillden/1c40e1039593d25b06567322db4f8b17 to your computer and use it in GitHub Desktop.
<template>
<require from="./dynamic-element"></require>
<button click.trigger="changeModelOnTextBox()">Change Text</button>
<button click.trigger="toggle()">Toggle</button>
<div if.bind="show">
<div repeat.for="control of controls">
<dynamic-element type.bind="control.type" model.bind="control.model"></dynamic-element>
</div>
</div>
</template>
import { DatePicker } from './date-picker';
import { TextBox } from './text-box';
export class App {
show = true;
controls = [
{label: 'Entry Date', type: DatePicker, model: '2017-01-01' },
{label: 'Code', type: TextBox, model: 'This is some other text'}
];
toggle() {
this.show = !this.show;
}
changeModelOnTextBox() {
let texboxIndex = this.controls.findIndex(x => x.label === 'Code');
this.controls[texboxIndex].model = 'I changed the model!';
}
}
<template class="foo">
<slot name="before">
<p>This is a cool textbox ::</p>
</slot>
<div style="border: 1px solid red">
<slot>Default Content</slot>
</div>
<slot name="after">
<p>This was a cool texbox ^^</p>
</slot>
</template>
export class BetterTextBox {}
<template>
<h2>Date-Picker</h2>
<input type="date" value.bind="model" />
</template>
import { bindable, bindingMode } from 'aurelia-framework';
export class DatePicker {
@bindable({ defaultBindingMode: bindingMode.twoWay }) model;
bind() {
//alert("bind");
}
attached() {
//alert("attached");
}
detached() {
//alert("detached");
}
}
import { bindingMode, createOverrideContext } from 'aurelia-binding';
import { inject, Container } from 'aurelia-dependency-injection';
import { bindable, noView, ViewCompiler, ViewResources, ViewSlot, viewResources } from 'aurelia-templating';
import { ResourceLoader } from './resource-loader';
const twoWayBinding = { defaultBindingMode: bindingMode.twoWay };
@noView()
@inject(
Container,
ViewResources,
ViewCompiler,
ViewSlot,
ResourceLoader,
)
export class DynamicElement {
@bindable() type;
@bindable(twoWayBinding) model;
get tagName() {
return this.type.name.split(/(?=[A-Z])/).join('-').toLowerCase();
}
get html() {
return `<${this.tagName} model.bind="model"></${this.tagName}>`;
}
constructor(
container,
resources,
viewCompiler,
viewSlot,
resourceLoader,
) {
this.container = container;
this.resources = resources;
this.viewCompiler = viewCompiler;
this.viewSlot = viewSlot;
this.resourceLoader = resourceLoader;
}
bind() {
this.resourceLoader.load(this.type, this.resources, this.container);
this.bindingContext = { model: this.model };
}
attached() {
this.resourceLoader
.awaitLoad(this.type, this.resources)
.then(() => {
var viewFactory = this.viewCompiler.compile(`<template>${this.html}</template>`, this.resources);
var view = viewFactory.create(this.container);
// Issue: Comment the lines as indicated in main.js
// I don't want to have to specify the items in global resources
// If I comment the line below then the view is rendered correctly but there are no bindings
// How can I get this line to work without errors (what is the global resources method doing that I am not)?
view.bind(this.bindingContext, createOverrideContext(this.bindingContext, this));
this.viewSlot.add(view);
});
}
modelChanged(newModel) {
this.bindingContext.model = newModel;
}
}
<!doctype html>
<html>
<head>
<title>Aurelia</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body aurelia-app="main">
<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>
export function configure(aurelia) {
aurelia.use
.standardConfiguration()
.developmentLogging()
.globalResources([
'./better-input'
])
.globalResources([
//'./date-picker', // comment this line
//'./text-box' // comment this line
]);
aurelia.start().then(a => a.setRoot());
}
import { HtmlBehaviorResource } from 'aurelia-templating';
import { metadata } from 'aurelia-metadata';
function getTagName(type) {
return type.name.split(/(?=[A-Z])/).join('-').toLowerCase();
}
function isRegistered(type, resources) {
let tagName = getTagName(type);
return !!resources.getElement(tagName);
}
export class ResourceLoader {
// TODO loading needs to consider resources being loaded for...
loading = new Map();
load(type, resources, container) {
if (isRegistered(type, resources)) {
return this.awaitLoad(type, resources);
}
let resource = metadata.getOrCreateOwn(metadata.resource, HtmlBehaviorResource, type);
HtmlBehaviorResource.convention(type.name + 'CustomElement', resource);
resource.initialize(container, type);
resource.register(resources);
let promise = resource.load(container, type)
.then(() => this.loading.delete(type));
this.loading.set(type, promise);
return promise;
}
awaitLoad(type, resources) {
if (!isRegistered(type, resources)) {
return Promise.reject();
}
return this.loading.get(type) || Promise.resolve();
}
}
<template>
<h2>Text-Box</h2>
<h3>Basic</h3>
<input type="text" value.bind="model" />
<h3>Better</h3>
<better-input>
<div slot="before">Just to test slots ::</div>
<input type="text" value.bind="model" />
<div slot="after">Just to test slots ^^</div>
</better-input>
</template>
import { bindable, bindingMode } from 'aurelia-framework';
export class TextBox {
@bindable({ defaultBindingMode: bindingMode.twoWay }) model;
bind() {
//alert("bind");
}
attached() {
//alert("attached");
}
detached() {
//alert("detached");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment