Permalink
Browse files

fix(ContentNode): Fixed #2 which prevented ContentNode from working w…

…ith more than 10 interpolations. Various improvements. Improvements to docs
  • Loading branch information...
calebdwilliams committed Jul 25, 2018
1 parent 40e14c2 commit 209a6076988ef473fae00ecb37c23d7b5b2ed3b4
@@ -90,42 +90,57 @@ Templiteral exports a `Component` abstract class that provides a significant boi

In addition, `Component` adds a static getter for a render method (`renderer`) which will be called when any bound attribute changes. Along with the renderer, a new element method, `html` serves as an alias for `this.templiteral()`:

[See this demo on CodePen.](https://codepen.io/calebdwilliams/pen/qyOGJO?editors=1010#0)

```javascript
import { Component } from 'templiteral';
class HelloWorld extends Component {
static get boundAttributes() {
return ['who', 'now'];
}
static get renderer() { return 'render'; }
static get boundAttributes() { return ['who', 'now']; }
constructor() {
super();
this.who = 'world';
this.interval = setInterval(this.updateTime.bind(this), 100);
}
connectedCallback() {
super.connectedCallback();
setInterval(this.updateTime.bind(this), 100);
disconnectedCallback() {
super.disconnectedCallback();
window.clearInterval(this.interval);
}
updateTime() {
this.now = new Date().toLocaleString();
}
render() {
this.html`
<h1>Hello ${this.who}</h1>
<p>${this.now}</p>
`;
}
}
customElements.define('hello-world', HelloWorld);
```

The `<hello-world></hello-world>` element would now have attributes in sync with the data and would automatically re-render the time every 100 milliseconds.
The `<hello-world who="world"></hello-world>` element would now have attributes in sync with the data and would automatically re-render the time every 100 milliseconds.

The `Component` base class also includes a custom event emitter utility simply called `emit`. `Component.emit` takes two arguments, the first is a string representing the `CustomEvent` name and the second is the detail object on the event for passing information outside of the component. [These events are, by default, composed](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event) so they will bubble through barriers in the shadow DOM if one is attached.

[See this demo on CodePen.](https://codepen.io/calebdwilliams/pen/MBobmZ)

```javascript
import { Component } from 'templiteral';
class EmitExample extends Component {
render() {
this.html`
<button (click)=${() => this.emit('button-clicked', new Date())}">Will emit an event called <code>button-clicked</code></button>`;
}
}
```

One caveat to using `Component` is that the immediate renderer will not be called until all `boundAttributes` have been defined. Typically this should be done in the `constructor`, `connectedCallback` or `onInit`; however, when you override the `constructor`, `connectedCallback` or `disconnectedCallback` methods, make sure to call the method on `super` first to preserve functionality. `onInit` is a utility method that gets called when the component is done appending content to the DOM.

## Element references

@@ -141,6 +156,8 @@ and in your component file:
this.username = this.refs.username.value;
```

If you intend to perform some action on element references, it is probably best to use the `onInit` lifecycle method described above.

### Array templates

Loops are created using the built-in `Array` prototype methods and the use of the `fragment` function. `fragment` takes in a unique key for each element in the array. Normally, the item's index should suffice, but in cases where there will be significant re-rendering, something else might be necessary.
@@ -9,6 +9,7 @@ const propPattern = /^\[.*\]$/;


const modelPattern = /t-model/gi;
const matchPattern = /---!{\d+}!---/gi;

const modelSymbol = Symbol('t-model');
const removeSymbol = Symbol('RemoveTemplate');
@@ -29,31 +30,10 @@ class ContentNode {
this.indicies.forEach(index => this.compiler.partIndicies.set(index, this));
}

set value(_value) {
const newValue = this.base.replace(valuePattern, _value);
this.value !== newValue ?
this.node.nodeValue = newValue : null;
}

get value() {
return this.node.nodeValue;
}

setValue(values = []) {
this.node.nodeValue = this.base.replace(/---!{*.}!---/g, (match) =>
values[valueToInt(match)]
);
}

update(values) {
this.node.nodeValue = this.base.replace(/---!{*.}!---/g, match => {
const value = values[valueToInt(match)];
if (Array.isArray(value)) {
return value.join('');
} else {
return value === null ? '' : value;
}
});
this.node.nodeValue = this.base.replace(matchPattern, match =>
values[valueToInt(match)] === null ? '' : values[valueToInt(match)]
);
}
}

@@ -131,7 +111,7 @@ class AttributeNode {

update(values) {
this.boundAttrs.forEach(attribute => {
const bases = attribute.base.match(/---!{\d+}!---/gi) || [];
const bases = attribute.base.match(matchPattern) || [];
const baseIndicies = bases.map(valueToInt);
let attributeValue = attribute.base;

@@ -235,9 +215,7 @@ class Template {
_append(node) {
for (let i = 0; i < this.parts.length; i += 1) {
const part = this.parts[i];
if (part instanceof ContentNode) {
part.setValue(this.values, this.oldValues[i]);
} else if (part instanceof AttributeNode) {
if (part instanceof AttributeNode || part instanceof ContentNode) {
part.update(this.values, this.oldValues);
} else if (part instanceof DirectiveNode) {
part.init();

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -5,6 +5,7 @@ const propPattern = /^\[.*\]$/;


const modelPattern = /t-model/gi;
const matchPattern = /---!{\d+}!---/gi;

const modelSymbol = Symbol('t-model');
const removeSymbol = Symbol('RemoveTemplate');
@@ -25,31 +26,10 @@ class ContentNode {
this.indicies.forEach(index => this.compiler.partIndicies.set(index, this));
}

set value(_value) {
const newValue = this.base.replace(valuePattern, _value);
this.value !== newValue ?
this.node.nodeValue = newValue : null;
}

get value() {
return this.node.nodeValue;
}

setValue(values = []) {
this.node.nodeValue = this.base.replace(/---!{*.}!---/g, (match) =>
values[valueToInt(match)]
);
}

update(values) {
this.node.nodeValue = this.base.replace(/---!{*.}!---/g, match => {
const value = values[valueToInt(match)];
if (Array.isArray(value)) {
return value.join('');
} else {
return value === null ? '' : value;
}
});
this.node.nodeValue = this.base.replace(matchPattern, match =>
values[valueToInt(match)] === null ? '' : values[valueToInt(match)]
);
}
}

@@ -127,7 +107,7 @@ class AttributeNode {

update(values) {
this.boundAttrs.forEach(attribute => {
const bases = attribute.base.match(/---!{\d+}!---/gi) || [];
const bases = attribute.base.match(matchPattern) || [];
const baseIndicies = bases.map(valueToInt);
let attributeValue = attribute.base;

@@ -231,9 +211,7 @@ class Template {
_append(node) {
for (let i = 0; i < this.parts.length; i += 1) {
const part = this.parts[i];
if (part instanceof ContentNode) {
part.setValue(this.values, this.oldValues[i]);
} else if (part instanceof AttributeNode) {
if (part instanceof AttributeNode || part instanceof ContentNode) {
part.update(this.values, this.oldValues);
} else if (part instanceof DirectiveNode) {
part.init();
Oops, something went wrong.

0 comments on commit 209a607

Please sign in to comment.