Boolean on/off Switch option

edited September 21, 2018 in Ideas
I would like to do one of those cool switches for a Booleen field instead of a check box. On would be true and off would be false (Obviously). Thanks for all the hard work Skuids!
2
2 votes

Awaiting Review · Last Updated

Comments

  • Matt SonesMatt Sones 💎💎💎
    edited April 23, 2018
    I use jQuery switchButton and add a skuid rendering snippet of my own, packaged in a single static resource, like so:
    /**
     * jquery.switchButton.js v1.0
     * jQuery iPhone-like switch button
     * @author Olivier Lance <[email protected]>
     *
     * 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 <input type="checkbox">, 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 <form>.
     *
     */
    (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 > 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 = $("<span>").addClass("switch-button-label");
                this.on_label = $("<span>").addClass("switch-button-label");
                this.button_bg = $("<div>").addClass("switch-button-background");
                this.button = $("<div>").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;
                    }
                    $("<div>").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(true);
            },
            _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(false);
                    return false;
                });
                this.button.click(function(e) {
                    e.preventDefault();
                    e.stopPropagation();
                    self._toggleSwitch(false);
                    return false;
                });
                // Set switch value when clicking labels
                this.on_label.click(function(e) {
                    if (self.options.checked && self.options.labels_placement === "both") {
                        return false;
                    }
                    self._toggleSwitch(false);
                    return false;
                });
                this.off_label.click(function(e) {
                    if (!self.options.checked && self.options.labels_placement === "both") {
                        return false;
                    }
                    self._toggleSwitch(false);
                    return false;
                });
            },
            _setOption: function(key, value) {
                if (key === "checked") {
                    this._setChecked(value);
                    return;
                }
                this.options[key] = value;
                this._refresh();
            },
            _setChecked: function(value) {
                if (value === this.options.checked) {
                    return;
                }
                this.options.checked = !value;
                this._toggleSwitch(false);
            },
            _toggleSwitch: function(isInitializing) {
            // Don't toggle the switch if it is set to readonly or disabled, unless it is initializing and animating itself
            if( !isInitializing && (this.element.attr('readonly') == 'readonly' || this.element.prop('disabled')) )
            return;
                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);

    //switchButton snippets
    (function (skuid){
    //////////////////////////////////////////////
    // Shortcuts & Global Variables //
    //////////////////////////////////////////////
    var $ = skuid.$,
        $s = skuid.snippet.getSnippet;
    //////////////////////////////////////////////
    // Snippets //
    //////////////////////////////////////////////
    var snippets = {
    'renderSwitch': function(field,value){
    //Use these values to configure...
    var ON_LABEL = "Yes";
    var OFF_LABEL = "No";
    var LABEL_PLACEMENT = "right";
    //render the checkbox
    skuid.ui.fieldRenderers[field.metadata.displaytype].edit(field,value);
    //Add CSS Class
    $(field.element).addClass('switch-button');
    //get the standard checkbox
    var input = $(field.element).find('input');
    input.switchButton({
        on_label: ON_LABEL,
        off_label: OFF_LABEL,
        labels_placement: LABEL_PLACEMENT,
        checked : !!value
    });
    $(field.element).children().each(function(){
        $(this).click(function(e){
            field.model.updateRow(field.row, field.id, $(this).hasClass('checked'), {initiatorId:field._GUID});
        });
    });
    };
    //////////////////////////////////////////////
    // Register Snippets //
    //////////////////////////////////////////////
    $.each(snippets,function(name,func){ skuid.snippet.registerSnippet(name,func); });

    })(skuid);
  • Matt SonesMatt Sones 💎💎💎
    edited November 6, 2017
    Oh, and here's the CSS I use:
    .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;
    }
    /*Custom implementation for skuid field editors*/
    .switch-button.nx-field {
        padding: 6px 0 2px 0;
    }
  • Conlan O'RourkeConlan O'Rourke ✭✭✭✭
    edited September 21, 2018
    It would be great to see this built in as a native field rendering option :)
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!