Getting rid of the renderUI

  1. Defining the new JS binding.

Use the _ prefix to make the difference between the default input binding methods and the user-defined methods.

let boxBinding = new Shiny.InputBinding();

$.extend(boxBinding, {
  
  // we are using the same class
  find: function(scope) {
    return $(scope).find('.box');
  },
  
  // we still want to comunite to R
  // wheter the box is collapsed or not
  getValue: function(el) {
    let isCollapsed = $(el).hasClass('collapsed-box');
    return {collapsed: isCollapsed}; // this will be a list in R
  },
  
  // Just returns the config script:
  _getConfigScript: function(el) {
    return(
      // Starting from the box
      $(el)
        // We have to look one level up to be able to use the `find` method
        .parent()
        // Target the script tag for current id
        .find("script[data-for='" + el.id + "']")
    );
  },
  
  // Converts the script content to a JS object
  _processConfig: function(el) {
    return(
      JSON.parse(
        this
        ._getConfigScript(el)
        .html()
      )
    );
  },
  
  // user defined binding: update box width
  _updateWidth: function(el, o, n) {
  
    // removes old class
    $(el).parent().toggleClass("col-sm-" + o);
    $(el).parent().addClass("col-sm-" + n);
    
    // trigger resize so that output resize
    $(el).trigger('resize');
  },
  
  // Input binding default method
  setValue: function(el, value) {
    let config = this._processConfig(el);

    // Only apply change for action update
    if (value.action === "update") {
    
      // check whether value.options.width exists
      if (value.options.hasOwnProperty("width")) {
              
        // config.width returns the initial width
        // value.options.width contains the new width value
        //   provided in the updateBox2 message output
        if (value.options.width !== config.width) {
          this._updateWidth(
            el,
            config.width,
            value.options.width
          )
           
          // Updating the confing after changing the UI
          config.width = value.options.width;
        }
      }
      
      // other items to update
      if (value.options.hasOwnProperty("title")) {
        if (value.options.title !== config.title) {
          let newTitle;
          newTitle = `<h3 class="box-title">${value.options.title}</h3>`
          newTitle = $.parseHTML(newTitle);

          $(el)
            .find(".box-title")
            .replaceWith($(newTitle));

          config.title = value.options.title;
        }
      }

      // Don’t forget to update the config script attached
      // to the card tag at the end of the update condition
      // OTHERWISE THE INPUT VALUE WON’T BE MODIFIED
      this
        ._getConfigScript(el)
        .replaceWith(
          '<script type="application/json" data-for="' +
          el.id +
          '">' +
          JSON.stringify(config) +
          '</script>'
        );

    } else if (value.action === "toggle") {
      // if action is toggle
      $(el).toggleBox();
    }

  },
  receiveMessage: function(el, data) {
    this.setValue(el, data);
    $(el).trigger('change');
  },
  subscribe: function(el, callback) {
    $(el).on('click', '[data-widget="collapse"]', function(event) {
      setTimeout(function() {
        callback();
      }, 50);
    });

    $(el).on('change', function(event) {
      setTimeout(function() {
        callback();
      }, 50);
    });
  },
  unsubscribe: function(el) {
    $(el).off('.boxBinding');
  }
});

Shiny.inputBindings.register(boxBinding, 'box-input');


$(function() {
  // overwrite box animation speed. Putting 500 ms add unnecessary delay for Shiny.
  $.AdminLTE.boxWidget.animationSpeed = 10;
});