Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Bell committed Jan 10, 2017
0 parents commit 5b7e31c
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Repeat Template
[![Published on webcomponents.org](https://img.shields.io/badge/webcomponents.org-published-blue.svg)](https://beta.webcomponents.org/element/owner/my-element)

It does what it says on the wrapper. It repeats elements inside the template element.
We pass **data in** via standard html attributes and listen to **custom events out**.

## Usage
- Pass in an stringified array of objects via a **repeat** attribute.
- repeat-template will send out a number of custom events (correlating to the length of the array data you passed in)
- Set up a custom event listener, it will contain an object with a reference to the duplicated `element` and `data` which you can then inject into the element where ever you want

```html
<repeat-template id="repeater">
<template>
<h1>Name</h1>
<img src="http://placehold.it/50x50">
</template>
</repeat-template>
```
```js
<script>
// Dummy Data
var data = [
{
name: "Ernst Haeckel",
profilePicture: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Ernst_Haeckel_1860.jpg/220px-Ernst_Haeckel_1860.jpg"
},
{
name: "Lazar Markovich Lissitzky",
profilePicture: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/El_Lissitzky_-_1o_Kestnermappe_Proun_%28Proun._1st_Kestner_Portfolio%29_-_Google_Art_Project.jpg/220px-El_Lissitzky_-_1o_Kestnermappe_Proun_%28Proun._1st_Kestner_Portfolio%29_-_Google_Art_Project.jpg"
}
];
// Add ID or Class to element so it can be targeted
var repeaterEl = document.getElementById('repeater');

// Listen to Custom Event that will broadcast each cloned element and its associated data.
// You can then modify the stamped element before it is inserted into the DOM
repeaterEl.addEventListener('repeatTemplateEvent', function(e){
var duplicatedElement = e.detail.element;
var data = e.detail.data;

// Do you modifications
duplicatedElement.querySelector('h1').innerHTML = data.name;
duplicatedElement.querySelector('img').setAttribute('src', data.profilePicture);
})

// Dynamically Add the data to the element via JS
repeaterEl.setAttribute('repeat', JSON.stringify(data));
</script>
```

## Browser Support (With polyfills)
Simply include [Webcomponent-lite](https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.23/webcomponents-lite.min.js)


| Polyfill | IE10 | IE11+ | Chrome* | Firefox* | Safari 7+* | Chrome Android* | Mobile Safari* |
| ---------- |:----:|:-----:|:-------:|:--------:|:----------:|:---------------:|:--------------:|
| Custom Elements | ~ |||||||
| HTML Imports | ~ |||||||
| Templates ||||||||

*Indicates the current version of the browser

~Indicates support may be flaky. If using Custom Elements or HTML Imports with Shadow DOM,
you will get the non-flaky Mutation Observer polyfill that Shadow DOM includes.

## Tests
TODO

## Size
2.23kb Minifed

## [License](http://couto.mit-license.org/)
1 change: 1 addition & 0 deletions dist/repeat-template.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "repeat-template",
"version": "1.0.0",
"description": "Webcomponent custom element that can be used to repeat internal dom elements",
"main": "webpack.config.js",
"scripts": {
"test": "jest",
"dist": "webpack --config webpack.config.js -p"
},
"keywords": [
"web",
"components",
"web-componets",
"custom-elements",
"template"
],
"author": "Michael Bell",
"license": "MIT",
"devDependencies": {
"babel-core": "~6.21.0",
"babel-loader": "~6.2.10",
"babel-preset-es2015": "~6.18.0",
"jest-cli": "~18.1.0",
"webcomponents.js": "~0.7.23",
"webpack": "~1.14.0"
}
}
46 changes: 46 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>repeat-template example</title>

<script src="https://cdnjs.cloudflare.com/ajax/libs/webcomponentsjs/0.7.23/webcomponents-lite.js"></script>
<link rel="import" href="repeat-template.html">
</head>
<body>

<repeat-template id="repeater" repeat="">
<template>
<h1></h1>
<img src="http://placehold.it/50x50" alt="">
</template>
</repeat-template>


<script>
//Demo of applying dynamic content and listening to events
var data = [
{
name: "Ernst Haeckel",
profilePicture: "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Ernst_Haeckel_1860.jpg/220px-Ernst_Haeckel_1860.jpg"
},
{
name: "Lazar Markovich Lissitzky",
profilePicture: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/El_Lissitzky_-_1o_Kestnermappe_Proun_%28Proun._1st_Kestner_Portfolio%29_-_Google_Art_Project.jpg/220px-El_Lissitzky_-_1o_Kestnermappe_Proun_%28Proun._1st_Kestner_Portfolio%29_-_Google_Art_Project.jpg"
}
];
var repeaterEl = document.getElementById('repeater');
//Listen to Event
repeaterEl.addEventListener('repeatTemplateEvent', function(e){
var duplicatedElement = e.detail.element;
var data = e.detail.data;

//Modify each of the template elements before they are stamped into the dom.
duplicatedElement.querySelector('h1').innerHTML = data.name;
duplicatedElement.querySelector('img').setAttribute('src', data.profilePicture);
})

repeaterEl.setAttribute('repeat', JSON.stringify(data));
</script>
</body>
</html>
1 change: 1 addition & 0 deletions src/repeat-template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script src="repeat-template.js"></script>
77 changes: 77 additions & 0 deletions src/repeat-template.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Polyfill
(function () {

if ( typeof window.CustomEvent === "function" ) return false;

function CustomEvent ( event, params ) {
params = params || { bubbles: false, cancelable: false, detail: undefined };
var evt = document.createEvent( 'CustomEvent' );
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
return evt;
}

CustomEvent.prototype = window.Event.prototype;

window.CustomEvent = CustomEvent;
})();

class RepeatTemplate extends HTMLElement {
constructor() {
super();
this.template = this.querySelector('template');
}
// Listen to Repeat attribute
static get observedAttributes() {
return ['repeat'];
}

attributeChangedCallback(attrName, oldVal, newVal) {
//Called when an attribute is changed, appended, removed, or replaced on the element.
if (attrName == "repeat" && newVal) {
let parsedData = this.parseJson(newVal)
if (parsedData) {
this.render(parsedData);
}
}
}

parseJson(repeatData) {
let parsedData = null;
try {
parsedData = JSON.parse(repeatData);
} catch (e) {
throw new Error("Invalid JSON string provided.");
}
return parsedData;
}

callCustomEvent(data, element, parentElement) {
// create and dispatch the event
var event = new CustomEvent("repeatTemplateEvent", {
detail: {
data: data,
element: element
}
});
parentElement.dispatchEvent(event);
}

render(parsedData) {
let parentNode = this;
let template = this.template;
let emitEvent = this.callCustomEvent;

//TODO optimise when changing data dynamically
parentNode.innerHTML = '';

parsedData.forEach(function(data) {
//Duplicate Template
let clone = document.importNode(template, true);
//Emit Event
emitEvent(data, clone.content, parentNode)
//Append Child
parentNode.appendChild(clone.content);
});
}
}
customElements.define('repeat-template', RepeatTemplate);
21 changes: 21 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
var path = require('path');
var webpack = require('webpack');

module.exports = {
entry: './src/repeat-template.js',
output: {
path: __dirname,
filename: '/dist/repeat-template.js'
},
module: {
loaders: [
{
loader: 'babel-loader',
test: path.join(__dirname, 'src'),
query: {
presets: 'es2015',
},
}
]
}
};

0 comments on commit 5b7e31c

Please sign in to comment.