jq-repeat
v2.0.1
Published
A simple, yet highly customizable jQuery plugin for dynamic DOM templating with Mustache. Supports automatic sorting, nested templates, and custom index keys.
Downloads
232
Maintainers
Readme
jq-repeat
A simple, yet highly customizable jQuery plugin to handle all of your client-side repetitive DOM needs. Simple, quick and powerful templating using Mustache syntax. Modeled after ng-repeat with automatic DOM synchronization.
Requirements
- jQuery 3.x (http://jquery.com/)
- Mustache 4.x (https://github.com/janl/mustache.js)
Installation
NPM
npm install jq-repeatInclude in HTML
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/4.2.0/mustache.min.js"></script>
<script src="dist/js/jq-repeat.min.js"></script>Quick Start
Template Setup
Add a jq-repeat attribute with a unique scope name to any element you want to use as a repeating template:
<ul>
<li jq-repeat="toDo">
<span class="item">{{ item }}</span>
<span class="status">{{ done }}</span>
</li>
</ul>Use Mustache syntax ({{ variable }}) for text interpolation and {{{ variable }}} for unescaped HTML.
Adding Items
Items are automatically rendered when you push data to the scope:
$.scope.toDo.push({ item: 'Get milk', done: 'Yes' });
// Add multiple items at once
$.scope.toDo.push(
{ item: 'Collect underwear', done: 'Yes' },
{ item: '?', done: 'No' },
{ item: 'Profit', done: 'No' }
);Core Features
Automatic Sorting
Sort items automatically with the jr-order-by attribute:
<li jq-repeat="users" jr-order-by="name">
{{ name }} - {{ age }}
</li>
<li jq-repeat="scores" jr-order-by="points" jr-order-reverse="true">
{{ player }}: {{ points }}
</li>When jr-order-by is set, items are automatically inserted and maintained in sorted order.
Custom Index Keys
Use a custom property as the index with jq-index-key:
<div jq-repeat="users" jq-index-key="userId">
{{ userName }}
</div>$.scope.users.push({ userId: 'user123', userName: 'John' });
$.scope.users.update('userId', 'user123', { userName: 'John Doe' });Nested Templates
jq-repeat supports nested repeating templates:
<div jq-repeat="departments">
<h2>{{ name }}</h2>
<ul>
<li jq-repeat="employees">
{{ firstName }} {{ lastName }}
</li>
</ul>
</div>Access parent data in nested templates using _parent:
<li jq-repeat="employees">
{{ firstName }} works in {{ _parent.name }}
</li>Array Methods
The scope object extends Array, so all standard array methods work with automatic DOM synchronization:
push(...items)
Add items to the end (or in sorted position if jr-order-by is set):
$.scope.toDo.push({ item: 'New task', done: 'No' });pop()
Remove and return the last item:
const last = $.scope.toDo.pop();shift()
Remove and return the first item:
const first = $.scope.toDo.shift();unshift(...items)
Add items to the beginning (or in sorted position if jr-order-by is set):
$.scope.toDo.unshift({ item: 'Urgent task', done: 'No' });splice(index, howMany, ...itemsToAdd)
Remove and/or add items at a specific position:
// Remove 2 items starting at index 1
$.scope.toDo.splice(1, 2);
// Replace 1 item at index 2
$.scope.toDo.splice(2, 1, { item: 'Updated task', done: 'Yes' });
// With custom index key
$.scope.users.splice('user123', 1); // Remove user with userId 'user123'reverse()
Reverse the order of items:
$.scope.toDo.reverse();indexOf(keyOrValue, value)
Find the index of an item:
// With custom index key
const index = $.scope.users.indexOf('user123');
// By property value
const index = $.scope.users.indexOf('name', 'John');
// By object reference
const index = $.scope.users.indexOf(userObject);update(keyOrIndex, valueOrData, dataToUpdate)
Update an item with automatic DOM re-rendering (throttled at 50ms):
// Update by index
$.scope.toDo.update(0, { done: 'Yes' });
// Update with custom index key
$.scope.users.update('user123', { userName: 'Jane Doe' });
// Update by key/value pair
$.scope.items.update('id', 42, { quantity: 10 });getByKey(key, value)
Get an item by key/value:
const user = $.scope.users.getByKey('userId', 'user123');remove(keyOrValue, value)
Remove an item:
// By custom index
$.scope.users.remove('user123');
// By key/value
$.scope.items.remove('id', 42);empty()
Remove all items:
$.scope.toDo.empty();jQuery Helper Methods
$(element).scopeGet()
Get the RepeatList scope for an element:
$('.jq-repeat-toDo').first().scopeGet(); // Returns $.scope.toDo$(element).scopeGetEl()
Get the closest jq-repeat element:
$('.item').scopeGetEl(); // Returns the <li jq-repeat-scope="toDo"> element$(element).scopeItem()
Get the data object for a specific rendered item:
const itemData = $('.jq-repeat-toDo').first().scopeItem();$(element).scopeItemUpdate(data)
Update a specific item:
$('.jq-repeat-toDo').first().scopeItemUpdate({ done: 'Yes' });$(element).scopeItemRemove()
Remove a specific item:
$('.jq-repeat-toDo').first().scopeItemRemove();Customization Hooks
__put($el, item, list)
Called when an item is added to the DOM. Default implementation just shows the element:
$.scope.toDo.__put = function($el, item, list) {
$el.fadeIn(300);
};__take($el, item, list)
Called when an item is removed from the DOM:
$.scope.toDo.__take = function($el, item, list) {
$el.fadeOut(300, function() {
$(this).remove();
});
};__putUpdate($oldEl, $newEl, item, list)
Called when an item is updated:
$.scope.toDo.__putUpdate = function($oldEl, $newEl, item, list) {
$oldEl.fadeOut(150, function() {
$newEl.fadeIn(150);
$oldEl.replaceWith($newEl);
});
};parseKeys
Transform data before rendering:
$.scope.toDo.parseKeys.timestamp = function(value, key, data) {
return new Date(value).toLocaleString();
};Template Variables
Special variables available in templates:
_parent- Access parent scope data in nested templates_index- Current item's index in the array_list- Reference to the RepeatList instancenestedTemplates- Array of nested template HTML
Building
Build the distribution files:
npm run buildThis creates:
dist/js/jq-repeat.js- Unminified versiondist/js/jq-repeat.min.js- Minified version with source map
Testing
Run tests:
npm testBrowser Compatibility
Works in all modern browsers that support ES6 features including:
- Classes
- Arrow functions
- Proxies
- Template literals
- Spread operator
For older browsers, use a transpiler like Babel.
Credits
- Written by William Mantly
- Big thanks to Derek Hu for creating NPM and bower package, and other general housekeeping
- Also, thanks to Raja Kapur for advice and guidance
License
MIT License - see LICENSE file for details
