Saving Data
Remake uses custom attributes to store data and add web app behavior. You can use these attributes to create a fully working web app.
See the Remake Recipes for some step-by-step examples or the TLDR summary of all the attributes.
object
Add this object
attribute to an HTML element to let Remake know there's data on it. Remake scans the page for all object
attribute and converts them into data.
Example of an object
element:
<div object></div>
This is valid Remake code and will be converted into {}
when the page is saved.
Remake can convert an element into one of two data structures:
- object
- array
Next, we'll learn about arrays.
array
Add this array
attribute to an HTML element to let Remake know there's data on it. Remake scans the page for all array
attribute and converts them into data.
Example of an array
element:
<div array></div>
This is valid Remake code and will be converted into []
when the page is saved.
key
This attribute allows you to label data inside a parent object.
Normally, in Remake, if there's an object
inside another object
, their data will be merged into a single object:
The following code, for example, produces a single object.
<div data-o-type="object">
<div data-o-type="object">
</div>
</div>
Output:
{}
To prevent this merge from happening and instead label the nested object, you can use the key
attribute.
<div object>
<div object key="someKeyName">
</div>
</div>
Output:
{
someKeyName: {}
}
Now the nested object is inside the other object and labeled as someKeyName
.
key:some-example-key
This attribute lets you attach key/value pairs to an object
element.
This attribute is how Remake stores data in HTML.
For example:
<div
object
key:first-name="David"
key:favorite-color="green"
></div>
Remake will convert this element into an object
that has two keys and two values:
{firstName: "David", favoriteColor: "green"}
Good to know:
- You can attach as many key/value pairs to the same element as you want.
- Remake only understands text as a value (no numbers or dates for now, but this will change)
- Key names are automatically camel-cased for you when they're saved (e.g.
key:some-key
is converted intosomeKey
) - There's one special key in Remake:
key:id
. It's useful for storing data to a specific place.
key:some-example-key="@"
If you set a key equal to @
followed by a valid command, Remake will look elsewhere for the value of they key.
Read on to learn about all the valid commands.
Native property commands
Every native HTML property is a valid command:
@id
@className
@type
@src
@href
@value
@checked
@innerText
@innerHTML
@style
@title
@alt
@for
@placeholder
Every normal HTML property command tell Remake to simply look in the named property inside the current element for the value of the key (e.g. elem.src
).
Special commands
There are two special commands:
@attr:
- Useful for looking up the value of custom attributes (e.g.
@attr:data-x
)
- Useful for looking up the value of custom attributes (e.g.
@search
- Searches the current element for a
target:
attribute that matches the original key name - Executes any commands on that
target:
element to get the final value
- Searches the current element for a
Reacting To Data Changes
watch:some-example-key
Use this attribute to react to changes on another key's value. The key it reacts to must be on the same element or an ancestor element.
The value for this attribute can be any of the native property commands listed in the section above this one (e.g. @innerText
or @src
).
You can also use this attribute to call custom functions.
watch:some-example-key="customFunction1(arg1, arg2) customFunction2(arg1, arg2)"
In this example, customFunction1
and customFunction2
would be defined when you first initialize Remake, inside the watchFunctions
object.
Good to know:
- By convention, this attribute should be attached to the element it's modifying.
- This attribute is very useful for displaying the same values in multiple places across a page while using the same data source.
For example, let's say you wanted to have a button on a landing page that had the same text no matter where it was displayed, you could do this:
<div object key:button-text="Buy Now!">
<button watch:button-text="@innerText"></button>
<button watch:button-text="@innerText"></button>
<button watch:button-text="@innerText"></button>
</div>
With this setup, if the value of buttonText
ever changed, all of the buttons will get the new value inserted into their innerText
.
Updating Data
edit:some-example-key
Clicking on an element with this attribute will trigger an inline edit popover. The key it's editing must be on the same element or an ancestor element.
A simple example:
<div object key:my-text="A simple note">
<button edit:my-text>Edit text</button>
</div>
If you want to edit two keys at the same time, simply add another edit:
attribute.
Editing two keys at once:
<div object key:my-age="34" key:my-name="David">
<button edit:my-age edit:my-name>Edit my info</button>
</div>
Removing the "remove" button
Remake supports removing the "remove" button from the inline edit popover.
<div object key:my-text="A simple note">
<button edit:my-text:without-remove>Edit text</button>
</div>
This is useful if there's a piece of data in your app that you want to be editable, but not deletable.
Other edit areas
Remake supports editing multi-line text inside the popover. The following example will trigger an auto-expanding textarea
instead of a single line input:
<div object key:my-text="A simple note">
<button edit:my-text:textarea>Edit text</button>
</div>
On the roadmap: Support for other edit areas, like radio buttons and dropdowns and color pickers is coming soon. Sign up to hear about when they're released.
Good to know:
- If, when a user clicks the "remove" button inside the inline edit popover, you want to set all of the data to empty strings instead of removing the data from the page altogether, use this modifier
edit:some-example-key:with-erase
update:some-example-key
Add this attribute to any <input>
(e.g. <input type="text">
, <input type="color">
, <input type="file">
, etc.), <textarea>
, or <select>
element.
Whenever the value of these elements changes, Remake will update the value on an element with a matching key:
. The key it's updating must be on the same element or an ancestor element.
For example:
<div object key:favorite-animal="giraffe">
<label><input type="radio" update:favorite-animal value="giraffe"> giraffe</label
<label><input type="radio" update:favorite-animal value="pangolin"> pangolin</label
<label><input type="radio" update:favorite-animal value="zebra"> zebra</label
</div>
You can also attach the update:
attribute to any other HTML element (e.g. <button>
, <div>
, etc.) to make clicking on it trigger an update. In this case, the value will be taken from the value of the update:
attribute.
For example:
<div object key:favorite-animal="giraffe">
<button update:favorite-animal="giraffe">Choose giraffe</button>
<button update:favorite-animal="pangolin">Choose pangolin</button>
<button update:favorite-animal="zebra">Choose zebra</button>
</div>
new:example-item-name
If you click on an element with this attribute, Remake will do its best to render a template and add it to the page.
Remake looks for a template that matches the name:
- In your
{{#for}}
loops - In the templates in your
app/partials
directory
The template is rendered server-side and then passed back to the client-side to be added to the page.
Controlling where the template is inserted
You can pass some options to the value of this attribute: top
or bottom
or a CSS selector (e.g. .my-list
).
Remake will use the top
or bottom
argument to decide where in the list to insert the new item. By default this is set to bottom
.
And it will use the CSS selector argument to find the list you want the item to be inserted into. By default this is set to [array]
, so it just finds the closest element with the array
attribute.
For example:
<ul class="todo-list" array></ul>
<button new:todo-item=".todo-list top"></button>
This will render the template todoItem
and insert it at the top of the element with the todo-list
class.
toggle:some-example-key
This attribute will toggle the value of a key that matches its name. The key it's toggling must be on the same element or an ancestor element.
The values it toggles between are on
and off
.
temporary:key:some-example-key
This attribute behaves exactly the same as its counterpart, key:some-example-key
, with two exceptions:
- When the value of a
temporary:key:
attribute changes, a save event isn't triggered - The key and value of a
temporary:key:
attribute is invisible to the save function (their data simply isn't saved)
It's very useful for attaching temporary state to the page (e.g. toggling menus, sidebars, or tabs)
default:some-example-key
If a key:
that matches this attribute is going to be set to a value of an empty string (e.g. ""
or even " "
), replace the value with the value of this attribute instead.
save
Clicking on an element with this attribute will trigger a save.
remove
When an element with this attribute is clicked, it will find the closest element with data and remove that element from the page. It will look for data first on the current element and then on all of its ancestor elements.
erase
When an element with this attribute is clicked, it will find the closest element with data and set all of its data to empty strings. It will look for data first on the current element and then on all of its ancestor elements.
Some Tips for working with Remake
Styling
Remake transforms your page into one big piece of data.
This makes it a lot easier than normal to style your page based on which data is set and which data isn't.
For example, lets say you wanted to implement a Dark Mode theme on your page. Your HTML might look like this:
<body object key:dark-mode="on">
<button toggle:dark-mode>Toggle Dark Mode</button>
</body>
Now, in your CSS you can style the page normally if Dark Mode is not enabled and differently if it is:
body {
background: #fff;
color: #222;
}
body[key\:dark-mode="on"] {
background: #222;
color: #fff;
}
Tip: You must escape the :
in CSS selectors with a back slash \
.
Advanced Data Attributes
ignore-data
Remake will skip over this element when saving data for a page.
no-save
Remake won't trigger a save event if data inside an element with this attribute changes.
disable-events
Remake events triggered by the new:
, save
, edit:
, update:
, toggle:
, remove
attributes will NOT trigger inside of an element with this attribute.
custom-save
If you want to handle the save event yourself, add this attribute above the elements you're editing and pass in the name of a custom save function that you define when initializing Remake (in the saveFunctions
object).
Reasons you might want to do this:
- You want to save a section of the page to a custom API endpoint
- You want to save a section of the page to a particular place in the user's data
For example:
<div custom-save="customSaveFunction">
<div object key:some-data="@innerText" edit:some-data>Hello!</div>
</div>
Whenever a user saves the some-data
key after clicking on the element, it will be saved using the customSaveFunction
instead of the normal Remake save method.
sync
Used on Remake's inline edit popovers. It makes it so data in the popover is synced back into the page before being saved.
This attribute is useful if you're creating your own inline edit popovers. To understand how it works, start by looking in _remake/client-side/inputjs/editableAttribute.js
.