Skip to main content

It’s often best to use a checkbox for programming purposes for Yes/No type questions. It would slick to have the checkbox field get an additional Field Renderer called “Labelled Option Box”. I could then provide a label for both True and False of Yes and No respectively, or vice versa if the need arises.

Pat, I would love to collaborate on some sort of checkbox custom renderer. I would want it to look something like this: jQuery UI Switch Button Demo - Olivier Lance . This could also be made into a custom component with a custom on/off label. Maybe over the long weekend…


Here’s a little page I put together:


<skuidpage unsavedchangeswarning="yes" showsidebar="true" showheader="true" tabtooverride="Account">   <models>
<model id="Account" limit="1" query="true" createrowifnonefound="false" sobject="Account">
<fields>
<field id="Name"/>
<field id="CreatedDate"/>
<field id="IsPartner"/>
</fields>
<conditions>
<condition type="param" enclosevalueinquotes="true" operator="=" field="Id" value="id"/>
</conditions>
<actions/>
</model>
</models>
<components>
<pagetitle model="Account">
<maintitle>
<template>{{Name}}</template>
</maintitle>
<subtitle>
<template>{{Model.label}}</template>
</subtitle>
<actions>
<action type="savecancel" window="self"/>
</actions>
</pagetitle>
<basicfieldeditor showsavecancel="false" showheader="true" model="Account" mode="read" buttonposition="" layout="" uniqueid="fields">
<columns>
<column width="33.3%">
<sections>
<section title="Basics">
<fields>
<field id="Name"/>
<field id="IsPartner" valuehalign="" type="CUSTOM" snippet="renderer">
<renderconditions logictype="and" onhidedatabehavior="keep"/>
</field>
</fields>
</section>
</sections>
</column>
<column width="33.3%">
<sections>
<section title="New Section" collapsible="no" showheader="false">
<fields/>
</section>
</sections>
</column>
<column width="33.3%">
<sections>
<section title="New Section" collapsible="no" showheader="false">
<fields/>
</section>
</sections>
</column>
</columns>
</basicfieldeditor>
</components>
<resources>
<labels/>
<css>
<cssitem location="inline" name="slider" cachelocation="false">.switch-button-label {
float: left;

font-size: 10pt;
cursor: pointer;
}

.switch-button-label.off {
color: #adadad;
}

.switch-button-label.on {
color: #0088CC;
}

.switch-button-background {
float: left;
position: relative;

background: #ccc;
border: 1px solid #aaa;

margin: 1px 10px;

-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;

cursor: pointer;
}

.switch-button-button {
position: absolute;

left: -1px;
top : -1px;

background: #FAFAFA;
border: 1px solid #aaa;

-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}</cssitem>
</css>
<javascript>
<jsitem location="inline" name="jQuerySwitchButton" cachelocation="false" url="">(function(skuid){
var $ = skuid.$;
/**
* jquery.switchButton.js v1.0
* jQuery iPhone-like switch button
* @author Olivier Lance &amp;lt;olivier.lance@sylights.com&amp;gt;
*
* Copyright (c) Olivier Lance - released under MIT License {{{
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
* }}}
*/
/*
* Meant to be used on a &amp;lt;input type="checkbox"&amp;gt;, this widget will replace the receiver element with an iPhone-style
* switch button with two states: "on" and "off".
* Labels of the states are customizable, as are their presence and position. The receiver element's "checked" attribute
* is updated according to the state of the switch, so that it can be used in a &amp;lt;form&amp;gt;.
*
*/
(function($) {
$.widget("sylightsUI.switchButton", {
options: {
checked: undefined, // State of the switch
show_labels: true, // Should we show the on and off labels?
labels_placement: "both", // Position of the labels: "both", "left" or "right"
on_label: "ON", // Text to be displayed when checked
off_label: "OFF", // Text to be displayed when unchecked
width: 25, // Width of the button in pixels
height: 11, // Height of the button in pixels
button_width: 12, // Width of the sliding part in pixels
clear: true, // Should we insert a div with style="clear: both;" after the switch button?
clear_after: null, // Override the element after which the clearing div should be inserted (null &amp;gt; right after the button)
on_callback: undefined, //callback function that will be executed after going to on state
off_callback: undefined //callback function that will be executed after going to off state
},
_create: function() {
// Init the switch from the checkbox if no state was specified on creation
if (this.options.checked === undefined) {
this.options.checked = this.element.prop("checked");
}
this._initLayout();
this._initEvents();
},
_initLayout: function() {
// Hide the receiver element
this.element.hide();
// Create our objects: two labels and the button
this.off_label = $("&amp;lt;span&amp;gt;").addClass("switch-button-label");
this.on_label = $("&amp;lt;span&amp;gt;").addClass("switch-button-label");
this.button_bg = $("&amp;lt;div&amp;gt;").addClass("switch-button-background");
this.button = $("&amp;lt;div&amp;gt;").addClass("switch-button-button");
// Insert the objects into the DOM
this.off_label.insertAfter(this.element);
this.button_bg.insertAfter(this.off_label);
this.on_label.insertAfter(this.button_bg);
this.button_bg.append(this.button);
// Insert a clearing element after the specified element if needed
if(this.options.clear)
{
if (this.options.clear_after === null) {
this.options.clear_after = this.on_label;
}
$("&amp;lt;div&amp;gt;").css({
clear: "left"
}).insertAfter(this.options.clear_after);
}
// Call refresh to update labels text and visibility
this._refresh();
// Init labels and switch state
// This will animate all checked switches to the ON position when
// loading... this is intentional!
this.options.checked = !this.options.checked;
this._toggleSwitch();
},
_refresh: function() {
// Refresh labels display
if (this.options.show_labels) {
this.off_label.show();
this.on_label.show();
}
else {
this.off_label.hide();
this.on_label.hide();
}
// Move labels around depending on labels_placement option
switch(this.options.labels_placement) {
case "both":
{
// Don't move anything if labels are already in place
if(this.button_bg.prev() !== this.off_label || this.button_bg.next() !== this.on_label)
{
// Detach labels form DOM and place them correctly
this.off_label.detach();
this.on_label.detach();
this.off_label.insertBefore(this.button_bg);
this.on_label.insertAfter(this.button_bg);
// Update label classes
this.on_label.addClass(this.options.checked ? "on" : "off").removeClass(this.options.checked ? "off" : "on");
this.off_label.addClass(this.options.checked ? "off" : "on").removeClass(this.options.checked ? "on" : "off");
}
break;
}
case "left":
{
// Don't move anything if labels are already in place
if(this.button_bg.prev() !== this.on_label || this.on_label.prev() !== this.off_label)
{
// Detach labels form DOM and place them correctly
this.off_label.detach();
this.on_label.detach();
this.off_label.insertBefore(this.button_bg);
this.on_label.insertBefore(this.button_bg);
// update label classes
this.on_label.addClass("on").removeClass("off");
this.off_label.addClass("off").removeClass("on");
}
break;
}
case "right":
{
// Don't move anything if labels are already in place
if(this.button_bg.next() !== this.off_label || this.off_label.next() !== this.on_label)
{
// Detach labels form DOM and place them correctly
this.off_label.detach();
this.on_label.detach();
this.off_label.insertAfter(this.button_bg);
this.on_label.insertAfter(this.off_label);
// update label classes
this.on_label.addClass("on").removeClass("off");
this.off_label.addClass("off").removeClass("on");
}
break;
}
}
// Refresh labels texts
this.on_label.html(this.options.on_label);
this.off_label.html(this.options.off_label);
// Refresh button's dimensions
this.button_bg.width(this.options.width);
this.button_bg.height(this.options.height);
this.button.width(this.options.button_width);
this.button.height(this.options.height);
},
_initEvents: function() {
var self = this;
// Toggle switch when the switch is clicked
this.button_bg.click(function(e) {
e.preventDefault();
e.stopPropagation();
self._toggleSwitch();
return false;
});
this.button.click(function(e) {
e.preventDefault();
e.stopPropagation();
self._toggleSwitch();
return false;
});
// Set switch value when clicking labels
this.on_label.click(function(e) {
if (self.options.checked &amp;amp;&amp;amp; self.options.labels_placement === "both") {
return false;
}
self._toggleSwitch();
return false;
});
this.off_label.click(function(e) {
if (!self.options.checked &amp;amp;&amp;amp; self.options.labels_placement === "both") {
return false;
}
self._toggleSwitch();
return false;
});
},
_setOption: function(key, value) {
if (key === "checked") {
this._setChecked(value);
return;
}
this.optionsnkey] = value;
this._refresh();
},
_setChecked: function(value) {
if (value === this.options.checked) {
return;
}
this.options.checked = !value;
this._toggleSwitch();
},
_toggleSwitch: function() {
this.options.checked = !this.options.checked;
var newLeft = "";
if (this.options.checked) {
// Update the underlying checkbox state
this.element.prop("checked", true);
this.element.change();
var dLeft = this.options.width - this.options.button_width;
newLeft = "+=" + dLeft;
// Update labels states
if(this.options.labels_placement == "both")
{
this.off_label.removeClass("on").addClass("off");
this.on_label.removeClass("off").addClass("on");
}
else
{
this.off_label.hide();
this.on_label.show();
}
this.button_bg.addClass("checked");
//execute on state callback if its supplied
if(typeof this.options.on_callback === 'function') this.options.on_callback.call(this);
}
else {
// Update the underlying checkbox state
this.element.prop("checked", false);
this.element.change();
newLeft = "-1px";
// Update labels states
if(this.options.labels_placement == "both")
{
this.off_label.removeClass("off").addClass("on");
this.on_label.removeClass("on").addClass("off");
}
else
{
this.off_label.show();
this.on_label.hide();
}
this.button_bg.removeClass("checked");
//execute off state callback if its supplied
if(typeof this.options.off_callback === 'function') this.options.off_callback.call(this);
}
// Animate the switch
this.button.animate({ left: newLeft }, 250, "easeInOutCubic");
}
});
})(jQuery);
})(skuid);</jsitem>
<jsitem location="inlinesnippet" name="renderer" cachelocation="false">var field = argumentst0],
value = argumentst1],
$ = skuid.$;
console.log(field);
var ON_LABEL = "Is Partner";
var OFF_LABEL = "Isn't Partner";
//render the checkbox
skuid.ui.fieldRenderersrfield.metadata.displaytype]e'edit'](field,value);
//get the standard checkbox
var input = $(field.element).find('input');
input.switchButton({
on_label: ON_LABEL,
off_label: OFF_LABEL,
checked : (value) ? true : false
});
$(field.element).children().each(function(){
$(this).click(function(e){
field.model.updateRow(field.row, field.id, $(this).hasClass('checked'));
});
});
</jsitem>
</javascript>
</resources>
</skuidpage>

Thanks Moshe.  This is a great add. 


Has anyone made this into a component?

It would be great to have this as a stock rendering option for checkboxes in skuid.