Live Demo
Hello World Demo
Fetching resources served with Resgate can either be done through HTTP(s):
Or by using ResClient, a javascript library that gets both data and updates through WebSocket:
<pre id="output"></pre>
const ResClient = resclient.default; // Creating a client instance. let client = new ResClient('wss://api.resgate.io'); // Get the resource from the service. // Try changing 'example.model' to 'example.users'. client.get('example.model').then(data => { let json = JSON.stringify(data, null, 2); output.textContent = json; }).catch(err => { output.textContent = err.message; });
Edit Text Demo
This sandboxed version of the Edit Text Example lets you edit and synchronize a text between multiple browser clients.
<p>Try running the demo in two separate tabs to observe client synchronization.</p> <input id="input"></input> <div id="err"></div>
const ResClient = resclient.default; // Creating the client instance. let client = new ResClient('wss://api.resgate.io'); // Get sandbox ID then from localStorage, // or generate and store a random one. let sandbox = localStorage.getItem('sandboxId') || Math.random().toString(36).substr(2, 8); localStorage.setItem('sandboxId', sandbox); // Get the model from the service. client.get(`demo.${sandbox}.model`).then(model => { // Create an input element let input = document.getElementById('input'); input.value = model.message; // Call set to update the remote model input.addEventListener('input', () => { model.set({ message: input.value }); }); // Listen for model change events. // The model will be unsubscribed after calling model.off model.on('change', () => { input.value = model.message; }); }).catch(err => { document.getElementById('err').textContent = err.message; });
Book Collection Demo
A sandboxed version of the Book Collection Example, using Modapp for component rendering. React and Vue.js versions of the example client are available as well.
Run the client in two separate browser tabs to observe real time client synchronization.
<header class="shadow"> <h1>Book Collection Demo</h1> <button id="reset">Reset</button> </header> <div class="top"> <div class="new-container"> <label for="new-title"><span>Title</span><input id="new-title" /></label> <label for="new-author"><span>Author</span><input id="new-author" /></label> <button id="add-new">Add</button> </div> <div id="error-msg"></div> </div> <hr> <div id="books"></div>
body { background: #eee; font-family: Arial, Helvetica, sans-serif; padding: 0; margin: 0; } header { background: #000; color: #fff; padding: 16px 1em; } h1 { margin: 0; padding: 0; line-height: 32px; font-size: 24px; } .top { margin: 1em 1em; } .shadow { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); } #books { max-width: 800px; margin: 0 1em; } .new-container { margin: 1em 0; line-height: 2em; } .new-container label { margin-right: 10px; } label { display: inline-block; font-weight: bold; } label span { display: inline-block; width: 64px; } #error-msg { color: #800 } button { display: inline-block; border: none; background: none; color: #006; } button:hover { background: rgba(0,0,0,0.12); } #reset { position:absolute; right: 20px; top: 24px; color: #fff; } #reset:hover { background: rgba(255,255,255,0.25); } .list-item { padding: 8px 0; } .card { background: #fff; padding: 1em 1em; box-sizing: border-box; } .action { float: right } .editing > .card { background: #eaeaff; } .edit { display: none; } .editing .edit { display: inherit; } .editing .view { display: none; } .card h3 { margin: 0 0 8px 0; } .card .author { font-style: italic; } .edit-input { display: inline-block; } .edit-input label { display: block; } .edit-input label + label { margin-top: 6px; }
const { Elem, Txt, Button, Input } = window["modapp-base-component"]; const { CollectionList, ModelTxt } = window["modapp-resource-component"]; const ResClient = resclient.default; // Creating the client instance. let client = new ResClient('wss://api.resgate.io'); // Get sandbox ID then from localStorage, or generate a random one. let sandbox = localStorage.getItem('sandboxId') || Math.random().toString(36).substr(2, 8); localStorage.setItem('sandboxId', sandbox); // Error handling let errMsg = new Txt(); let errTimer = null; errMsg.render(document.getElementById('error-msg')); let showError = (err) => { errMsg.setText(err && err.message ? err.message : String(err)); clearTimeout(errTimer); errTimer = setTimeout(() => errMsg.setText(''), 7000); }; // Add reset click callback document.getElementById('reset').addEventListener('click', () => { client.call(`library.${sandbox}.books`, 'reset').catch(showError); }); // Add new click callback document.getElementById('add-new').addEventListener('click', () => { let newTitle = document.getElementById('new-title'); let newAuthor = document.getElementById('new-author'); client.call(`library.${sandbox}.books`, 'new', { title: newTitle.value, author: newAuthor.value }).then(() => { // Clear values on successful add newTitle.value = ""; newAuthor.value = ""; }).catch(showError); }); // Get the collection from the service. client.get(`library.${sandbox}.books`).then(books => { // Here we use modapp components to render the book list. // It is a protest against all these frameworks with virtual DOMs. // Why use virtual DOMs when it is faster with vanilla javascript? new Elem(n => n.component(new CollectionList(books, book => { let c = new Elem(n => n.elem('div', { className: 'list-item' }, [ n.elem('div', { className: 'card shadow' }, [ n.elem('div', { className: 'view' }, [ n.elem('div', { className: 'action' }, [ n.component(new Button(`Edit`, () => { c.getNode('titleInput').setValue(book.title); c.getNode('authorInput').setValue(book.author); c.addClass('editing'); })), n.component(new Button(`Delete`, () => books.call('delete', { id: book.id }).catch(showError))) ]), n.elem('div', { className: 'title' }, [ n.component(new ModelTxt(book, book => book.title, { tagName: 'h3'})) ]), n.elem('div', { className: 'author' }, [ n.component(new Txt("By ")), n.component(new ModelTxt(book, book => book.author)) ]) ]), n.elem('div', { className: 'edit' }, [ n.elem('div', { className: 'action' }, [ n.component(new Button(`OK`, () => { book.set({ title: c.getNode('titleInput').getValue(), author: c.getNode('authorInput').getValue() }) .then(() => c.removeClass('editing')) .catch(showError); })), n.component(new Button(`Cancel`, () => c.removeClass('editing'))) ]), n.elem('div', { className: 'edit-input'}, [ n.elem('label', [ n.component(new Txt("Title", { className: 'span' })), n.component('titleInput', new Input()) ]), n.elem('label', [ n.component(new Txt("Author", { className: 'span' })), n.component('authorInput', new Input()) ]) ]) ]) ]) ]) ); return c; }, { className: 'list' })) ).render(document.getElementById('books')); }).catch(err => showError(err.code === 'system.connectionError' ? "Connection error. The demo service seems to be unreachable." : err ));
Tip
Add, edit, and delete as much as you like. The list of books will be reset 15 min after last modification.
You can manually trigger a reset by clicking the Reset button.