utils.editable.js

In-place editing for various form elements such as input, select, textarea, radios, checkboxes, etc...

Dropdown

Code

Action

new UTILS.Editable({ target: $('#simple-select1'), type: 'select', items: [ { label: 'United States', value: 1 }, { label: 'Germany', value: 49 }, { label: 'United Kingdom', value: 44 } ], value: 49, //Germany field: 'country_id' }).enable();
Dropdown with field
  1. No ajax (value is updated on the screen only)
  2. field defines how to return the value
  3. { country_id: value }
new UTILS.Editable({ target: $('#simple-select2'), type: 'select', items: [ { label: 'United States', value: 1 }, { label: 'Germany', value: 49 }, { label: 'United Kingdom', value: 44 } ], value: 1, //US params: function(value,Editable){ return { cid: value }; } }).enable();
Dropdown with params
  1. No ajax (value is updated on the screen only)
  2. params defines how to return the values
  3. { cid: value }
  4. (no need to specify field)
new UTILS.Editable({ target: $('#simple-select3'), type: 'select', items: [ { label: 'Dogs', value: 1 }, { label: 'Cats', value: 2 }, { label: 'Unicorns', value: 3 } ], value: 3, //Unicorns field: 'animal_id', ajax: { url: '/api/update', params: {} //any extra params needed to be passed } }).enable();
Dropdown with ajax
  1. ajax defines where to send the value, once updated
  2. return value as { animal_id: value }
new UTILS.Editable({ target: $('#simple-select4'), type: 'select-selectize', items: [ { label: 'Dogs', value: 1 }, { label: 'Cats', value: 2 }, { label: 'Unicorns', value: 3 } ], value: 2, //cats params: function(value,Editable){ return { animal_id: value }; } }).enable();
Dropdown with selectize.js integration
  1. selectize.js is a 3rd party hybrid library of a textbox and select box. It's jQuery-based and it's useful for tagging, contact lists, country selectors, and so on.
  2. However, we only use the select feature
new UTILS.Editable({ target: $('#simple-select5'), type: 'select-multiselect', items: [ { label:'Dogs', value:1 }, { label:'Cats', value:2 }, { label:'Unicorns', value:3 } ], value: [2,3], //cats & unicorns params: function (value, Editable){ return { animal_ids: JSON.stringify(value) //[1,2] }; } }).enable();
Multi-Select Dropdown (uses selectize.js)
  1. selectize.js with tagging option is used as a multi-select
  2. values are pre-defined
new UTILS.Editable({ target: $('#simple-select6'), type: 'select-multiselect', items: [ { label:'United States', value:1 }, { label:'Germany', value:86 } ], value: [1,86], //US & Germany options: { search_url: '/api/countries', content_type: '', //optional - default //used to format how the search query will be send to the server //==> api/countries?q={query} onBeforeSearch: query => { return { q: query }; }, //used to re-format the values that come back from the server into //a more friendly format that is accepted onAfterSearch: response => { let items = _.map(response.coutries, country => { return { label: country.country, value: country.id } }); return items; }, limit: 3 //limit selection to 3 items }, ajax: { url: '/api/update', params: {} //any extra params needed to be passed in the server call }, params: (value, Editable) => { return { country_ids: JSON.stringify(value) }; } }).enable();
Multi-Select Dropdown (required selectize.js)
  1. items pre-defined dropdown options
    required when value exists
  2. options options that will determine how/where to make the server calls and how to handle the response
    1. search_url URL used to call the server
    2. content_type (optional) specifies the content type header set during the server call
    3. onBeforeSearch (optional) defines how to pass the search query to the server /api/countries?q={query}
    4. onAfterSearch (optional) defines how to response needs to be processed in order to comply with the correct format. Each value must be in the following format: [{ label:'some label', value:'some value' },...]
    5. limit (optional) restricts the selection to the number specified. ( default: unrestricted )
  3. ajax defines where to send the selection to
  4. params defines how to format the values that will be passed to the server during the ajax call

Input

Code

Action

var name = new UTILS.Editable({ target: $('#simple-input1a1'), type: 'input', value: 'Jack Bauer', placeholder: '**' }).enable();
Input with placeholder option
  1. By default when the field is empty it will use the -- chars to make sure there is something that is clickable.
  2. In this case we are overwriting it with **
new UTILS.Editable({ target: $('#simple-input1b1'), type: 'input', value: 'John Rambo', placeholder: '...', contenteditable: true }).enable();
Input with contenteditable option
  1. By default the target field is replaced with an input field. However, contenteditable option allows for us to edit the content of the HTML element directly
  2. only applies to input and textarea

new UTILS.Editable({ target: $('#simple-input1c1'), type: 'input-autocomplete', value: 'Germany', placeholder: '---', contenteditable: true, options: { search_url: '/api/countries', onBeforeSearch: query => { return { q: query }; }, onAfterSearch: response => { let items = _.map(response.coutries, country => { return { label: country.country, value: country.country } }); return items; } }, ajax: { url: '/api/update', params: {} //any extra params needed to be passed }, params: (value, Editable) => { return { country: value }; } }).enable();
Auto-Complete with contenteditable option where the suggestions are obtained through an ajax call to the server
  1. Works like any regular auto-complete widget except this one is for contenteditable fields
  2. only applies to input fields

new UTILS.Editable({ target: $('#simple-input1d1'), type: 'input-autocomplete', value: 'Mickey Mouse', placeholder: '---', contenteditable: true, items: [ 'Mickey Mouse','Donald Duck', 'Oswald the Lucky Rabbit', 'Genie','Goofy','Snow White', 'Minnie Mouse','Scar','Tinker Bell', 'Dory' ], params: (value, Editable) => { return { disney_name: value }; } }).enable();
Contenteditable Auto-complete with pre-defined suggestions
let phone_imask; let phone = new UTILS.Editable({ target: $('#simple-input2'), type: 'input', value: '2345678906', params: (value, Editable) => { return { phone: value.replace(/[\(\)\s\-\+]/g, '') //need to remove any non-digit char }; }, onInputCreate: (Editable) => { //getting the input field created by UTILS.Editable var $input = Editable.getInputField(); //assigning phone_imask object (found in utils.js) phone_imask = UTILS.inputMask.phone($input); //setting the editable display value Editable.setDisplayValue(phone_imask.value); }, onShow: () => { if (phone_imask) phone_imask._onChange(); //undocumented method to trigger the formatting manually }, custom_methods_override: { name: 'filterValueForDisplay', method: function(phone){ //if phone_imask is defined lets use that, otherwise whatever was passed in return (phone_imask) ? phone_imask.value : phone; } } }).enable();
Input with imask.js integration
  1. imask.js is a 3rd party library to apply a mask to the user input.
  2. custom_methods_override ==> filterValueForDisplay is a method used to format the value before it gets displayed. In other words the value might be an id but we would want to display the name instead.
  3. In this particular case the phone number consists of digits only but we want to display it in a more readable format
  4. Additionally we want to apply an input mask to restrict user input UTILS.inputMask.phone
let phone_imask; new UTILS.Editable({ target: $('#simple-input2a'), type: 'input', placeholder: '---', contenteditable: true, value: '234-567-8906', params: (value, Editable) => { return { phone: value.replace(/[\(\)\s\-\+]/g, '') //need to remove any non-digit char }; }, onActionTriggered: Editable => { //getting the input field created by UTILS.Editable let $target = Editable.getTarget(); if (!$target.data('imask')){ //need to set contenteditable here b/c imask when instantiated needs to know about it $target.prop('contenteditable',true); //assigning phone_imask object (found in utils.js) phone_imask = UTILS.inputMask.phone($target); //setting the editable display value Editable.setDisplayValue(phone_imask.value); } }, onShow: () => { if (phone_imask) phone_imask._onChange(); //undocumented method to trigger the formatting manually }, custom_methods_override: { name: 'filterValueForDisplay', method: function(value){ if (phone_imask) value = phone_imask.value; if (!value.length) value = this.getPlaceholder(); return value; } } }).enable();
Input with contenteditable option and imask.js validation
  1. imask.js is a 3rd party library to apply a mask to the user input.
  2. In this example we want to validate the input of a phone number to match a certain format

Textarea

Code

Action

var name = new UTILS.Editable({ target: $('#simple-textarea1a'), type: 'textarea', value: 'Some text that goes here...' }).enable();
Textarea
  1. By default when the field is empty it will use the -- chars to make sure there is something that is clickable.
  2. In this case we are overwriting it with **
new UTILS.Editable({ target: $('#simple-textarea1b'), type: 'textarea', value: `Lorem ipsum dolor sit amet, qui ex appetere invidunt insolens, ad numquam vocibus sed. Et iisque assueverit nam. Choro referrentur definitiones quo et. Et labore audiam legimus nec. Tollit habemus maluisset et eum, ea usu nusquam mentitum. `, contenteditable: true }).enable();
Textarea contenteditable
new UTILS.Editable({ target: $('#simple-textarea2'), type: 'textarea-wysiwyg', value: 'Some text that goes here...' }).enable();
Textarea with summernote.js integration
  1. summernote.js is a 3rd party library to create a super simple WYSIWYG Editor.

Date

Code

Action

var date = new UTILS.Editable({ target: $('#simple-input3'), type: 'date', value: '', field: 'start_date', options: { //options passed down to bootstrap-datepicker.js } }).enable();
Input with bootstrap-datepicker.js integration
  1. bootstrap-datepicker.js is a 3rd party library to display a calendar for date selection.
  2. Another dependency is moment.js for date/time manipulation
  3. date selection is restricted to only future dates ( tomorrow+ )
new UTILS.Editable({ target: $('#simple-input4a'), type: 'date', value: '', options: { startDate: null //open to any date selection }, ajax: { url: '/api/update' }, params: function(date,Editable){ return { start_date: date }; } }).enable();
Input without date restrictions
new UTILS.Editable({ target: $('#simple-input4b'), type: 'date-range', value: '06/09/2023 - 06/23/2023', options: { date_format: 'MM/DD/YYYY', separator: ' - ' } }).enable();

Originally inspired by daterangepicker.js by Chunlong Liu, but unfortunately some needed features such as months-only/years-only selection were not available. That prompted the development of utils.daterange.js utility.

A few examples below
  • show top bar

    new UTILS.Editable({ target: $('#simple-input4c'), type: 'date-range', value: '06/09/2023 - 06/23/2023', options: { date_format: 'MM/DD/YYYY', separator: ' - ', show_topbar: true } }).enable();
  • sticky calendars

    new UTILS.Editable({ target: $('#simple-input4ca'), type: 'date-range', value: '06/09/2023 - 06/23/2023', options: { date_format: 'MM/DD/YYYY', separator: ' - ', sticky: true } }).enable();
  • months only

    new UTILS.Editable({ target: $('#simple-input4e'), type: 'date-range', value: 'Jun 2023 - Jun 2025', options: { date_format: 'MMM YYYY', start_date: null, //allow passed dates separator: ' - ', min_view_mode: 'months' } }).enable();
  • years only

    new UTILS.Editable({ target: $('#simple-input4g'), type: 'date-range', value: '2023 - 2038', options: { date_format: 'YYYY', start_date: null, //allow passed dates separator: ' - ', min_view_mode: 'years' } }).enable();

Checkbox

Code

Action

var checkbox = new UTILS.Editable({ target: $('#simple-input5'), type: 'checkbox', params: (value) => { return { setting: 'isAutosave', //name of the DB column is_checked: value //==> true/false }; }, value: true, //initial value (checked) options: { desc: 'Auto-Save' } }).enable();
Checkbox
  1. Standard checkbox functionality
  2. Value is saved upon checking/unchecking the box
//using shards to style the checkboxes var checkbox1a = new UTILS.Editable({ target: $('#simple-input6a'), type: 'checkbox-switch', params: (value) => { return { setting: 'isPopulate', is_checked: value }; }, value: false, //initial value (unchecked) options: { desc: 'Auto-Populate' //@desc is the label text next to the checkbox } }).enable(); var checkbox1b = new UTILS.Editable({ target: $('#simple-input6b'), type: 'checkbox-switch', params: (value) => { return { setting: 'isAutoUpdate', is_checked: value }; }, value: true, //initial value (checked) options: { desc: 'Auto-Update' //@desc is the label text next to the checkbox } }).enable();
Checkbox with shards integration
  1. shards is a 3rd party css framework built on top of bootstrap 4
  2. By changing the type to checkbox-switch we successfully changed the regular checkbox for an iOS-looking one

Radio

Code

Action

var radio = new UTILS.Editable({ target: $('#simple-input7'), type: 'radio', field: 'button_color', value: '#fff', items: [ { label: 'Red', value: '#f00' }, { label: 'White', value: '#fff' }, { label: 'Black', value: '#000' } ], //if no ajax specified we can also pass the value into a custom function onAfterSave: (Editable, response) => { console.log(response); //=> {errors: [], button_color: "#000", direction: "top"} } }).enable();
Radio
  1. Standard radio button functionality
  2. Value is saved upon selecting an option

API

Option

Required

Default

Description

target required $('body') DOM that will be replaced by the Editable element
params optional null

Params that will be passed in the ajax call along side the value of the editable parameter.

field: 'animal_id', params: { code_id:123, cat_id:9 } //passed to server --> { code_id:123, cat_id:9, animal_id:25 } //animal_id is appended

Another way is to assign it a function

field: 'animal_id', params: (value) => { return { code_id: 123, cat_id: 9, lion_id: value //holds the updated value }; } //passed to server --> { code_id:123, cat_id:9, lion_id:25 } //@field is ignored in this case
type required input
options optional {}

Native options that are passed down to the underlying libs used by the process, such as bootstrap-datepicker.js

{ container: $('body'), orientation: 'bottom', autoclose: false, format: 'MM/DD/YYYY', startDate: moment().add(1,'day').toDate(), todayHighlight: true }
css optional ''

Extra css classes that will be added to the editable elements for further styling

tabbing optional false

If enabled, by hitting the TAB will make the next-in-line element editable

lazyload optional false

If enabled, the element will be activated on user click and the _onActionTriggered will have to be triggered manually

Note, this is mainly used for performance enhencement when you have 100+ editable elements and you want to enable them through direct user action

var $span = $(''); //editable options that will be used when activated var editable_options = { target: $span, type: 'input', tabbing: true, lazyload: true, field: 'animal_id', value: 123 }; $span.addClass('xedit editable-target').data('editable-options',editable_options).on('click',function(event){ event.preventDefault(); //getting options var options = $(event.target).data('editable-options')); //activating new UTILS.Editable(options).enable()._onActionTriggered(); });
toggle optional click

Events that trigger the editable activation ( click, dblclick, etc... )

items optional []

Even though this is marked as optional it is required for certain types such as select and radio

container optional $('body')

Specifies the DOM where editable HTML will be appended to

value optional ''

The value of the editable.

Note, the value and display value are two different things

placeholder optional --

Specifies the character that will be displayed in case the value is empty

placeholder: '**' //if empty, ** will be shown
contenteditable optional false

Makes an HTML element be editable from within the HTML

Methods

Method

Default

Repeat

Description

onInputCreate null ONE-TIME Triggered when the editable input element is created
onShow null REPEAT Triggered every time when the editable is activated
onHide null REPEAT Triggered every time when the editable is de-activated
onCancel null REPEAT Triggered when the user decides not to make any changes by either clicking off or hitting the ESC key
onActionTriggered null REPEAT Triggered every time when the editable is activated, but before it is shown
onBeforeSave null REPEAT Triggered every time before the value is saved/ajax call made
onAfterSave null REPEAT Triggered every time after the value is saved/ajax call made
onSaveError null REPEAT Triggered every time if an error occurs while saving the value
Loading resources, please wait...