Skip to content

Instantly share code, notes, and snippets.

@bigopon
Forked from mattduffield/index.html
Last active March 3, 2021 02:11
Show Gist options
  • Save bigopon/a655c883e47e4de0404405d647627514 to your computer and use it in GitHub Desktop.
Save bigopon/a655c883e47e4de0404405d647627514 to your computer and use it in GitHub Desktop.
ValueConverter and CustomElement Issue 0.7
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Dumber Gist</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<base href="/">
</head>
<!--
Dumber Gist uses dumber bundler, the default bundle file
is /dist/entry-bundle.js.
The starting module is pointed to "main" (data-main attribute on script)
which is your src/main.js.
-->
<body>
<my-app></my-app>
<script src="/dist/entry-bundle.js" data-main="main"></script>
</body>
</html>
{
"dependencies": {
"aurelia": "0.10.0-dev.202102251102"
}
}
<use-shadow-dom></use-shadow-dom>
<form class="form-input flex flex-row ${class}" submit.trigger="onSubmit($event)">
<div if.bind="isIconPrefix()"
class="flex flex-none input-prefix">
<i class="fal fa-${mapTypeToIcon()} user-select-none"></i>
</div>
<input id="${inputId}"
type="${type}"
data-mode="${mode}"
class="flex-1 ${inputClass}"
value.bind="value"
checked.bind="checked"
placeholder.bind="placeholder"
disabled.bind="disabled || isBusy"
>
<div if.bind="isBusy"
class="flex flex-none is-busy">
<i class="fal fa-spinner fa-spin user-select-none"></i>
</div>
<datalist id="${inputId}List">
</datalist>
</form>
/**
* Name: form-input.js
* Desc: This custom element handles text fields
*
* Usage:
* <form-input value.bind="currentItem.email"
* has-reset=true reset-click.call="cardFilterReset($event)"></form-input>
*
* Reference:
* https://codepen.io/burnaDLX/pen/JJrjbz
*/
import {inject, bindable, BindingMode} from 'aurelia';
//import {composeEvent, getPath, pluckValue, wait} from '../../../util';
@inject(Element)
export class FormInput {
@bindable inputId = '';
@bindable dataLabel = '';
@bindable dataAttributes = '';
@bindable type = 'text';
@bindable mode = '';
@bindable({mode: BindingMode.twoWay}) value;
@bindable({mode: BindingMode.twoWay}) checked;
@bindable placeholder = '';
@bindable class = '';
@bindable inputClass = '';
@bindable autocomplete = '';
@bindable disabled = false;
@bindable isBusy = false;
inputTypes = [
{name: 'address', value: 'address-card'},
{name: 'car', value: 'car-side'},
{name: 'email', value: 'envelope'},
{name: 'number', value: 'calculator'},
{name: 'search', value: 'search'},
{name: 'tel', value: 'phone'},
{name: 'time', value: 'watch'},
{name: 'url', value: 'globe-americas'}
];
safeAttributes = [
'set-focus',
'list',
'max',
'maxlength',
'min',
'minlength',
'readonly',
'required',
'pattern',
'data-grouplength',
'data-delimiter'
];
constructor(element) {
this._element = element;
}
get element() {
if (this._element.shadowRoot) {
return this._element.shadowRoot;
} else {
return this._element;
}
}
binding() {
if (!this.mode) {
this.mode = this.type;
}
}
attaching() {
const el = this.element.querySelector('input');
const attrs = this.dataAttributes.split(',');
attrs.forEach(att => {
if (att) {
if (el) {
const value = att.trim();
el.setAttribute(value, '');
}
}
});
for (const att of this._element.attributes) {
let {name, value} = att;
if (this.safeAttributes.includes(name)) {
el.setAttribute(name, value);
}
}
if (this.dataLabel) {
el.setAttribute('data-label', this.dataLabel);
}
}
// isIconPrefix(type) {
isIconPrefix() {
const type = this.mode;
const found = this.inputTypes.find(f => f.name === type);
if (found) {
return true;
}
return false;
}
// mapTypeToIcon(type) {
mapTypeToIcon() {
const type = this.mode;
const found = this.inputTypes.find(f => f.name === type);
if (found) {
return found.value;
}
return '';
}
onKeydown(e) {
if (e.key === 'Enter') {
this.element.dispatchEvent(composeEvent('on-enter'));
return false;
}
return true;
}
onSubmit(e) {
return false;
}
}
import Aurelia from 'aurelia';
import { MyApp } from './my-app';
Aurelia.app(MyApp).start();
<!--
Try to create a paired css/scss/sass/less file like my-app.scss.
It will be automatically imported based on convention.
-->
<!--
There is no bundler config you can change in Dumber Gist to
turn on shadow DOM.
But you can turn shadow DOM on by adding a meta tag in every
html template:
<use-shadow-dom>
-->
<import from="./form-input"></import>
<import from="./proper-case-value-converter"></import>
<h1>${message}</h1>
<br>
<p>
<div>The following works with the Value Converter:</div>
<label>First Name</label>
<br>
<input value.bind="first_name | properCase">
</p>
<p>
<div>The following DOES NOT work with the Value Converter:</div>
<label>First Name</label>
<form-input value.bind="first_name | properCase"></form-input>
</p>
export class MyApp {
message = 'Hello Aurelia 2!';
first_name = '';
}
export class ProperCaseValueConverter {
fromView(value) {
if (value && typeof value == 'string') {
return capitalize(value);
}
return value;
}
toView(value) {
if (value && typeof value == 'string') {
return capitalize(value);
}
return value;
}
}
function capitalize(str) {
return str.split(' ').map(m => {
if (m && m.length > 1) {
return m[0].toUpperCase() + m.substr(1).toLowerCase();
} else {
return m.toUpperCase();
}
}).join(' ');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment