autoSaveTrigger
AutoSavePrime listens to input changes on elements under the scope and debounces them before making a save request. The default debounce interval is 3000ms. You can customise this interval by passing an object with the debounce interval set (in milliseconds).
Setting this property to null disables auto-saving altogether but you can save manually at any time by invoking autoSave.Save().
//Example usage
var autoSave = new AutoSave( null, {
autoSaveTrigger: {
debounceInterval: 10*1000 //Changes will be debounced over 10 seconds now before save
}
})
autoLoadTrigger
AutoSavePrime will populate a form with details from the datastore on page load (after the document is ready). Setting this property to null will disable this behaviour altogether but you can load manually at any time by invoking autoSave.Load()
seekExternalFormElements
For all Form elements specified at or under your scope elements, AutoSavePrime will seek input elements elsewhere in the document that are linked to this form. Setting this property to false will disable this behaviour.
saveNotification
When a save is kicked off, a notification briefly shows at the top indicating a save is in progress. By default, it's got a simple non-distracting look but see the demos for styling it :-
By specifying null, the notification is disabled
message:Setting this property overrides the message to display in the notification bar.
template:This must be a valid HTML fragment that replaces the entire notification container. The existing container can be styled with css but incase more drastic changes are required this allows you to do that.
Either message or template can be specified but not both.
minShowDuration:The save process normally happens instantly, especially when using local storage. To allow the user to see the notification that their work is being auto-saved, the notification has a minimal time for which it shows. By default this is 500ms (but it can show for longer if the save is taking longer - over a network, say). The minimum duration can be changed by setting this parameter (in milliseconds).
//Example usage #1 - simple message customise
var autoSave = new AutoSave( null, {
saveNotification: {
message: "Conservé...", //The same message in French
minShowDuration: 2000 //Override to show for at least 2 seconds
}
})
/* Use this CSS to customise the notification */
.autosave-saving .autosave-msg{
text-decoration: underline;
}
//Example usage #2 - custom HTML template
var autoSave = new AutoSave( null, {
saveNotification: {
template: "<div id='my_custom_notification'><span>My own message that autosave is saving</span></div>",
minShowDuration: 2000 //Override to show for at least 2 seconds
}
})
noStorageNotification
When AutoSavePrime detects that neither cookies nor local storage is available a notification briefly shows at the top stating auto-save is disabled. If the datastore however has been customised with load and save callbacks, the notification never shows. By default, it looks like the below but see the demos for styling it :-
message:Setting this property overrides the message to display in the notification bar.
template:This must be a valid HTML fragment that replaces the entire notification container. The existing container can be styled with css but incase more drastic changes are required this allows you to do that.
Either message or template can be specified but not both.
showDuration:The notification by default shows for 5 seconds but can be overriden by this setting. Set in milliseconds.
//Example usage #1 - simple message customise
var autoSave = new AutoSave( null, {
saveNotification: {
message: "AutoSave est éteint", //The same message in French
showDuration: 3500 //Show for exactly 3.5 seconds
}
})
/* Use this CSS to customise the notification */
.autosave-noStore .autosave-msg{
text-decoration: underline;
}
//Example usage #2 - custom HTML template
var autoSave = new AutoSave( null, {
saveNotification: {
template: "<div id='my_custom_notification'><span>My own message about autosave unavailability</span></div>",
showDuration: 3500 //Show for exactly 3.5 seconds
}
})
dataStore
AutoSavePrime by default will try and use the HTML5 local storage API for data storage. If this isn't detected, it'll fallback to using cookies. You can also customise the datastore with custom functions to, for example, save and load to/from a server instead.
By specifying null, saving and loading is disabled. You can instead use the hooks to drive saving and loading.
preferCookies: Even if local storage is available, you can switch to using cookies by setting this option to true.
clearEmptyValuesOnLoad: By default, on load AutoSavePrime will clear existing form entries if an entry value is specified in the payload. This is useful if you do a server-side reset of the user's controls and want to blank them out. e.g. If the loading payload has name=&age=, the inputs would be blanked out on a load regardless of their existing values. However, setting this property to false will cause the blank values to be ignored and the inputs to retain their existing values.
key: As you can have multiple AutoSavePrime instances on one page, this property is used to distinguish between them. The key is a string used to index into the datastore and is automatically generated by the formula
key = "AutoSaveJS_" + URL.path + Form.Name
If there isn't a Form with a Name property in the scope set, then of course the last term above isn't applied.
Sometimes you will need to set this key explicitly - namely when
1. You have multiple AutoSavePrime instances on one page and they don't have a Form element with a name property in the scope set (Example #1 below)
or
2. You have multiple pages using AutoSavePrime and the URL path is the same for all (Example #2 below).
<!-- Example Context -->
<div id="container_1">
...
</div>
<form id="container_2">
...
</form>
<form id="container_3" name="contact_details">
...
</form>
1. Multiple instances on one page
//1a) (URL: http://www.example.com/customer_entry)
new AutoSave( document.querySelector( "#container_1" ) );
//Key generated: AutoSaveJS_customer_entry
new AutoSave( document.querySelector( "#container_2" ) );
//Error: Key already in use
//1b) (URL: http://www.example.com/customer_entry)
new AutoSave( document.querySelector( "#container_1" ) );
//Key generated: AutoSaveJS_customer_entry
new AutoSave( document.querySelector( "#container_2" ),
{
dataStore: {
key: "extra_details"
}
});
//Key generated: AutoSaveJS_customer_entry_extra_details
//1c) (URL: http://www.example.com/customer_entry)
new AutoSave( document.querySelector( "#container_1" ) );
//Key generated: AutoSaveJS_customer_entry
new AutoSave( document.querySelector( "#container_3" ) ); //Uses the form name
//Key generated: AutoSaveJS_customer_entry_contact_details
2. Multiple Instances across pages
//2a. (URL: http://www.example.com/customer_entry?customer_id=10) //Query parameters are ignored
new AutoSave( document.querySelector( "#container_1" ) );
//Key generated: AutoSaveJS_customer_entry
// (URL: http://www.example.com/customer_entry?customer_id=11)
new AutoSave( document.querySelector( "#container_1" ) );
//Error: Key already in use
//2b. (URL: http://www.example.com/customer_entry?customer_id=10)
new AutoSave( document.querySelector( "#container_1" ) );
//Key generated: AutoSaveJS_customer_entry
new AutoSave( document.querySelector( "#container_1" ),
{
dataStore: {
key: "cust_10"
}
});
//Key generated: AutoSaveJS_customer_entry_cust_10
Finally, you can also customise the key handling entirely by the onPreLoad and onPreStore interceptors. These allow you to, for example, share a datastore across multiple AutoSavePrime instances on different pages.
load,
save: You can change the datastore to a completely custom one by specifying functions for the load and save. The key parameter supplied in both helps identify which instance is being saved. For example
var autoSave = new AutoSave( null, {
dataStore: {
save: function( key, data, saveCompleteCallback ){
mySvc.save( key, data ).then( function(){ //Assume mySvc.save() returns a Promise
saveCompleteCallback();
});
},
load:function( key, loadCompleteCallback ){
mySvc.load( key ).then( function( result ){ //Assume mySvc.load() returns a Promise
loadCompleteCallback( result );
});
}
}
})
The saveCompleteCallback and loadCompleteCallback must be invoked at completion, regardless of being an sync or async operation, else you may get unexpected behavior.
You must set both the save and load callbacks or neither of them - you cannot set just one.
The remaining options are interceptor-cum-inspector callbacks that conform to ...
@FUNC Semantics
@FUNC semantics in AutoSavePrime give a consistent experience among callbacks. Concretely, it means that when you register a function callback, what you return dictates what happens next. Your callback could
Return False. That particular operation will stop dead there (and clean up anything if necessary).
Simply not return (i.e. Undefined), in which case it'll act as just a passive inspector and the flow will continue as normal.
Return Null or a Custom data structure so the operation continues with your overriden/enhanced data.
The supported return values are indicated next to each callback below.
onInitialised (U)
Callback to listen to when AutoSave is fully initialised including the initial load of any existing data from the datastore.
//Example usage
var autoSave = new AutoSave( null, {
onInitialised: function(){
//Do post-initialisation work here
}
})
onPreLoad (FUNC)
Callback to listen to when AutoSave is about to load data from the datastore. By returning false, you can cancel the load. By returning a string, you can specify the payload to load. This must be encoded as x-www-form-urlencoded.
//Example usage
var autoSave = new AutoSave( null, {
onPreLoad: function(){
if ( some_condition )
return false; //prevent load from happening (you can call autoSave.load() afterwards too)
else
return AutoSave.serialize( "name=Mozart&type=Classical+Music" ); //x-www-form-urlencoded
}
})
onPostLoad (FUNC)
Callback to listen to after AutoSave has loaded the string from the data source but before deserialising it into the input elements. By returning false, you can cancel the subsequent deserialisation. By returning a string, you can override the payload to be deserialised.
//Example usage
var autoSave = new AutoSave( null, {
onPostLoad: function( serialisedData ){
if ( some_condition )
return false; //Cancel the load
else if ( other_condition )
return serialisedData + "&firstName=James" //Append an extra field to be loaded
//Otherwise, continue loading as normal
}
})
onPostDeserialize (U)
Callback to listen to after AutoSave has deserialised the string into the input elements.
//Example usage
var autoSave = new AutoSave( null, {
onPostDeserialize: function(){
//All inputs loaded - you could now, for example, initialise UI libraries like CKEditor
}
})
onPreSerialize (FUNC)
Callback to listen to before all the input elements are serialised into one long x-www-form-urlencoded string. By returning false, you can cancel the subsequent serialisation (and hence the save). The set of elements can be customised by returning any of the types shown above.
//Example usage
var autoSave = new AutoSave( null, {
onPreSerialize: function( controlsArray ){
if ( some_condition )
return false; //Cancel the serialisation - e.g. check if any inputs are invalid
else
return controlsArray.slice( 0, Math.min(3,controlsArray.length) ); //Only serialize the first 3 controls
}
})
onPreStore (FUNC)
Callback to listen to before the serialised string is stored to the datastore. By returning false, you can cancel the save. The serialised string can be modified and returned.
//Example usage
var autoSave = new AutoSave( null, {
onPreStore: function( serialisedString ){
if ( some_condition )
return false; //Cancel storing it
else
return serialisedString + "×tamp="+mySvc.getTimestamp() //Append an extra field to be saved down
}
})
For cookie-based storage, the string also contains the cookie parameters - like the expiry date - so this would be a good place to customise the final cookie string.
onPostStore (U)
Callback to listen to after the serialised string is stored to the datastore.
//Example usage
var autoSave = new AutoSave( null, {
onPostStore: function(){
//Save completed - you could now, for example, re-enable controls to continue working
}
})
onSaveNotification (FU)
Callback to listen to just before the saving notification visibility is toggled. The parameter is true if the notification is about to be shown and false just before its hidden.
Return false to cancel showing the notification.
//Example usage
var autoSave = new AutoSave( null, {
onSaveNotification: function( isToggleOn ){
if ( some_condition ) {
return false; //Don't show the notification
}
else {
//Disable save button whilst auto-saving
document.querySelector( "button[type='submit']" ).enabled = !isToggleOn;
}
}
})
onNoStorageNotification (FU)
Callback to listen to just before the notification that there is no storage available is toggled. The parameter is true if the notification is about to be shown and false just before its hidden.
Return false to cancel showing the notification.
//Example usage
var autoSave = new AutoSave( null, {
onNoStorageNotification: function( isToggleOn ){
if ( isToggleOn ) {
//If local storage isnt available, switch to using a server-side implementation
mySvc.initialiseAjaxService();
}
}
})
onLog (FUNC)
Callback for handling logging. If a function is supplied, it must be variadic with the signature
// (level: string, ...logArgs: any[]) => any
where level will be one of the following strings
- debug (AutoSave.LOG_DEBUG)
- info (AutoSave.LOG_INFO)
- warn (AutoSave.LOG_WARN)
- error (AutoSave.LOG_ERROR)
The argument returned from your callback is what gets sent to the log sink instead of the original arguments. If false is returned, this is a special case where the logging is aborted.
For convenience and easy integration with other libraries, you can also pipe messages at specific levels by specifying an object for this parameter. Both methods are shown in the following example
//Example usage - with 1 function
var autoSave = new AutoSave( null, {
onLog: function( level, _variadic_args_ ){
//Log errors to svc in production
if ( mySvc.isProduction() ) {
if ( level == AutoSave.LOG_ERROR )
mySvc.logError( arguments.slice( 1 ) ); //Skip the level parameter
}
return false; //Don't write any logs to the default output (console)
}
})
//Example usage - with level piping functions
var autoSave = new AutoSave( null, {
onLog: {
debug: function( _variadic_args_ ){
//Never pipe debug logging to downstream logger
return false;
}
info: mySvc.logger.info,
warn: mySvc.logger.warn,
error: mySvc.logger.error
}
})
All functions are optional and for any levels without a function, default logging will take place.
Returning false from any of these will prevent default logging (to console).
Anything else returned overwrites the existing log message. If an array is returned, it will become a variadic parameter list to the log sink.
See the demos for how to seamlessly wire these into any existing logging you have.