Expandable Text Box

  • 1
  • Question
  • Updated 3 years ago
  • Answered
I would like to add this expandable text box javascript into my skuid page, but when I tried to add it as an In-Line snippet javascript resource it did not display correctly. I added the code from this link https://bgrins.github.io/ExpandingTextareas/expanding.js into the snippet body and then rendered the field using the snippet but when I load the page the text in the text box is gone and I can not type in the text box. Any ideas?

I originally got the javascript reference from http://bgrins.github.io/ExpandingTextareas/
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb

Posted 4 years ago

  • 1
Photo of Emily Davis

Emily Davis, Employee

  • 3,502 Points 3k badge 2x thumb
Hi, Nate!

For rendering the field, I included this in the snippet after the code from expanding.js:

var $ = skuid.$, field = arguments[0], value = arguments[1];
var model = field.model, row = field.row;

var containerDiv = field.element;
var fieldText = $('<textarea class="expanding">' + value + '</textarea>');

//Update field value when text is changed
$(fieldText).bind('input propertychange', function() {
    var fieldsToUpdate = {};
    fieldsToUpdate[field.id] = $(this).val();
    
    model.updateRow(row, fieldsToUpdate);
});

$(containerDiv).append(fieldText);

You might have to update this to account for read mode vs. edit mode. (using field.mode property)

Emily
Photo of Tami Lust

Tami Lust

  • 5,280 Points 5k badge 2x thumb
Emily,

This is great! One question. I removed the '+ value +' section because it showed "null" in my text box instead of the text box being blank. The text box is now glitchy. You have to copy and paste things twice in order for it to show in the text box. Do you know how I can fix the glitches but keep the text box blank on page load?
Photo of Rob Hatch

Rob Hatch, Official Rep

  • 44,006 Points 20k badge 2x thumb
Tami - I think that's because you are in a new data entry scenario.  Right? In that case the Value is null.  I think you need to check whether Value is present and if not - define the value field with some hard coding,  maybe just a space,  maybe a prepopulated text.

This way the expanding text box can carry a value - regardless of whether or not there is anything in the data. 
Photo of Tami Lust

Tami Lust

  • 5,280 Points 5k badge 2x thumb
Hi Rob,

You are correct. I tried defining the value field with some hard coding but that is where the glitches came in. So if I defined value as a sting or spaces so it is blank, then when I go to enter new data into that field you have to click twice in order to type in the box.

For example I have a list of items I want to paste in the expandable box. I click in the box and click paste. Nothing happens. I have to put my cursor in the box again and paste. Then the data sticks.
Photo of Emily Davis

Emily Davis, Employee

  • 3,502 Points 3k badge 2x thumb
Something like this :)

if (field.mode == 'edit') {
    $(containerDiv).append(fieldText);
}
else {
    $(containerDiv).append($('<div class="nx-fieldtext">').html(value));
}
 
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
Thank you for the response. I will take a look at this and let you know how it goes.
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
That worked great. Thank you so much for your help!
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
So, I don't know if this is a coincidence with installing the new Skuid into my sandbox or if there is now something wrong with the javascript, but this code is no longer working. Here is the code that I have running in the javascript as an in-line snippet. Any ideas of what might have happened?

// Expanding Textareas v0.1.2// MIT License
// https://github.com/bgrins/ExpandingTextareas

(function(factory) {
  // Add jQuery via AMD registration or browser globals
  if (typeof define === 'function' && define.amd) {
    define([ 'jquery' ], factory);
  }
  else {
    factory(jQuery);
  }
}(function ($) {

  var Expanding = function($textarea, opts) {
    Expanding._registry.push(this);

    this.$textarea = $textarea;
    this.$textCopy = $("<span />");
    this.$clone = $("<pre class='expanding-clone'><br /></pre>").prepend(this.$textCopy);

    this._resetStyles();
    this._setCloneStyles();
    this._setTextareaStyles();

    $textarea
      .wrap($("<div class='expanding-wrapper' style='position:relative' />"))
      .after(this.$clone);

    this.attach();
    this.update();
    if (opts.update) $textarea.bind("update.expanding", opts.update);
  };

  // Stores (active) `Expanding` instances
  // Destroyed instances are removed
  Expanding._registry = [];

  // Returns the `Expanding` instance given a DOM node
  Expanding.getExpandingInstance = function(textarea) {
    var $textareas = $.map(Expanding._registry, function(instance) {
        return instance.$textarea[0];
      }),
      index = $.inArray(textarea, $textareas);
    return index > -1 ? Expanding._registry[index] : null;
  };

  // Returns the version of Internet Explorer or -1
  // (indicating the use of another browser).
  // From: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx#ParsingUA
  var ieVersion = (function() {
    var v = -1;
    if (navigator.appName === "Microsoft Internet Explorer") {
      var ua = navigator.userAgent;
      var re = new RegExp("MSIE ([0-9]{1,}[\\.0-9]{0,})");
      if (re.exec(ua) !== null) v = parseFloat(RegExp.$1);
    }
    return v;
  })();

  // Check for oninput support
  // IE9 supports oninput, but not when deleting text, so keyup is used.
  // onpropertychange _is_ supported by IE8/9, but may not be fired unless
  // attached with `attachEvent`
  // (see: http://stackoverflow.com/questions/18436424/ie-onpropertychange-event-doesnt-fire),
  // and so is avoided altogether.
  var inputSupported = "oninput" in document.createElement("input") && ieVersion !== 9;

  Expanding.prototype = {

    // Attaches input events
    // Only attaches `keyup` events if `input` is not fully suported
    attach: function() {
      var events = 'input.expanding change.expanding',
        _this = this;
      if(!inputSupported) events += ' keyup.expanding';
      this.$textarea.bind(events, function() { _this.update(); });
    },

    // Updates the clone with the textarea value
    update: function() {
      this.$textCopy.text(this.$textarea.val().replace(/\r\n/g, "\n"));

      // Use `triggerHandler` to prevent conflicts with `update` in Prototype.js
      this.$textarea.triggerHandler("update.expanding");
    },

    // Tears down the plugin: removes generated elements, applies styles
    // that were prevously present, removes instance from registry,
    // unbinds events
    destroy: function() {
      this.$clone.remove();
      this.$textarea
        .unwrap()
        .attr('style', this._oldTextareaStyles || '');
      delete this._oldTextareaStyles;
      var index = $.inArray(this, Expanding._registry);
      if (index > -1) Expanding._registry.splice(index, 1);
      this.$textarea.unbind(
        'input.expanding change.expanding keyup.expanding update.expanding');
    },

    // Applies reset styles to the textarea and clone
    // Stores the original textarea styles in case of destroying
    _resetStyles: function() {
      this._oldTextareaStyles = this.$textarea.attr('style');

      this.$textarea.add(this.$clone).css({
        margin: 0,
        webkitBoxSizing: "border-box",
        mozBoxSizing: "border-box",
        boxSizing: "border-box",
        width: "100%"
      });
    },

    // Sets the basic clone styles and copies styles over from the textarea
    _setCloneStyles: function() {
      var css = {
        display: 'block',
        border: '0 solid',
        visibility: 'hidden',
        minHeight: this.$textarea.outerHeight()
      };

      if(this.$textarea.attr("wrap") === "off") css.overflowX = "scroll";
      else css.whiteSpace = "pre-wrap";

      this.$clone.css(css);
      this._copyTextareaStylesToClone();
    },

    _copyTextareaStylesToClone: function() {
      var _this = this,
        properties = [
          'lineHeight', 'textDecoration', 'letterSpacing',
          'fontSize', 'fontFamily', 'fontStyle',
          'fontWeight', 'textTransform', 'textAlign',
          'direction', 'wordSpacing', 'fontSizeAdjust',
          'wordWrap', 'word-break',
          'borderLeftWidth', 'borderRightWidth',
          'borderTopWidth','borderBottomWidth',
          'paddingLeft', 'paddingRight',
          'paddingTop','paddingBottom', 'maxHeight'];

      $.each(properties, function(i, property) {
        var val = _this.$textarea.css(property);

        // Prevent overriding percentage css values.
        if(_this.$clone.css(property) !== val) {
          _this.$clone.css(property, val);
          if(property === 'maxHeight' && val !== 'none') {
            _this.$clone.css('overflow', 'hidden');
          }
        }
      });
    },

    _setTextareaStyles: function() {
      this.$textarea.css({
        position: "absolute",
        top: 0,
        left: 0,
        height: "100%",
        resize: "none",
        overflow: "auto"
      });
    }
  };

  $.expanding = $.extend({
    autoInitialize: true,
    initialSelector: "textarea.expanding",
    opts: {
      update: function() { }
    }
  }, $.expanding || {});

  $.fn.expanding = function(o) {

    if (o === "destroy") {
      this.each(function() {
        var instance = Expanding.getExpandingInstance(this);
        if (instance) instance.destroy();
      });
      return this;
    }

    // Checks to see if any of the given DOM nodes have the
    // expanding behaviour.
    if (o === "active") {
      return !!this.filter(function() {
        return !!Expanding.getExpandingInstance(this);
      }).length;
    }

    var opts = $.extend({ }, $.expanding.opts, o);

    this.filter("textarea").each(function() {
      var visible = this.offsetWidth > 0 || this.offsetHeight > 0,
          initialized = Expanding.getExpandingInstance(this);

      if(visible && !initialized) new Expanding($(this), opts);
      else {
        if(!visible) _warn("ExpandingTextareas: attempt to initialize an invisible textarea. Call expanding() again once it has been inserted into the page and/or is visible.");
        if(initialized) _warn("ExpandingTextareas: attempt to initialize a textarea that has already been initialized. Subsequent calls are ignored.");
      }
    });
    return this;
  };

  function _warn(text) {
    if(window.console && console.warn) console.warn(text);
  }

  $(function () {
    if ($.expanding.autoInitialize) {
      $($.expanding.initialSelector).expanding();
    }
  });

}));

var $ = skuid.$, field = arguments[0], value = arguments[1];
var model = field.model, row = field.row;

var containerDiv = field.element;
var fieldText = $('<textarea class="expanding">' + value + '</textarea>');

//Update field value when text is changed
$(fieldText).bind('input propertychange', function() {
    var fieldsToUpdate = {};
    fieldsToUpdate[field.id] = $(this).val();
    
    model.updateRow(row, fieldsToUpdate);
});

$(containerDiv).append(fieldText);

if (field.mode == 'edit') {
    $(containerDiv).append(fieldText);
}
else {
    $(containerDiv).append($('<div class="nx-fieldtext">').html(value));
}
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
What happens is when I try to type, it allows me to type one character and then the focus of the cursor goes somewhere else on the page. 
Photo of Rob Hatch

Rob Hatch, Official Rep

  • 44,006 Points 20k badge 2x thumb
One explanation for the symptom you are having is that you have another 'iFrame based include' somewhere else on the page that is using the same model as its source.  When the model detects changes (ie a new character typed in the textbox) it tells the iFrame to rerender - which grabs focus.   It is best to provide a model just for the iframe includes.   If this is a wild goose chase let me know. 
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
Thanks for your quick response Rob!

I tried just creating a new page all together with just a single text box, a single text field, and a single model to test out this javascript and I am getting the same result. I'm not sure if this is exactly what you are asking about, but let me know if there is another way to test this out.
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
I'm not exactly sure how the above code would have worked before, as the Expanding plugin has to be initialized using the jQuery expanding() plugin syntax in order for it to be used programmatically (see the "Manual" section in the Github docs for the plugin), but this approach should work:

1. Change the "Resource Location" of your existing JavaScript Resource from Inline (Snippet) to regular Inline --- this step is very very important. 
2. Change the "Resource Body" to be the following:
 


// Expanding Textareas v0.1.2
// MIT License
// https://github.com/bgrins/ExpandingTextareas
(function(factory) {
  // Add jQuery via AMD registration or browser globals
  if (typeof define === 'function' && define.amd) {
    define([ 'jquery' ], factory);
  }
  else {
    factory(skuid.$);
  }
}(function ($) {
  var Expanding = function($textarea, opts) {
    Expanding._registry.push(this);
    this.$textarea = $textarea;
    this.$textCopy = $("<span />");
    this.$clone = $("<pre class='expanding-clone'><br /></pre>").prepend(this.$textCopy);
    this._resetStyles();
    this._setCloneStyles();
    this._setTextareaStyles();
    $textarea
      .wrap($("<div class='expanding-wrapper' style='position:relative' />"))
      .after(this.$clone);
    this.attach();
    this.update();
    if (opts.update) $textarea.bind("update.expanding", opts.update);
  };
  // Stores (active) `Expanding` instances
  // Destroyed instances are removed
  Expanding._registry = [];
  // Returns the `Expanding` instance given a DOM node
  Expanding.getExpandingInstance = function(textarea) {
    var $textareas = $.map(Expanding._registry, function(instance) {
        return instance.$textarea[0];
      }),
      index = $.inArray(textarea, $textareas);
    return index > -1 ? Expanding._registry[index] : null;
  };
  // Returns the version of Internet Explorer or -1
  // (indicating the use of another browser).
  // From: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx#ParsingUA
  var ieVersion = (function() {
    var v = -1;
    if (navigator.appName === "Microsoft Internet Explorer") {
      var ua = navigator.userAgent;
      var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
      if (re.exec(ua) !== null) v = parseFloat(RegExp.$1);
    }
    return v;
  })();
  // Check for oninput support
  // IE9 supports oninput, but not when deleting text, so keyup is used.
  // onpropertychange _is_ supported by IE8/9, but may not be fired unless
  // attached with `attachEvent`
  // (see: http://stackoverflow.com/questions/18436424/ie-onpropertychange-event-doesnt-fire),
  // and so is avoided altogether.
  var inputSupported = "oninput" in document.createElement("input") && ieVersion !== 9;
  Expanding.prototype = {
    // Attaches input events
    // Only attaches `keyup` events if `input` is not fully suported
    attach: function() {
      var events = 'input.expanding change.expanding',
        _this = this;
      if(!inputSupported) events += ' keyup.expanding';
      this.$textarea.bind(events, function() { _this.update(); });
    },
    // Updates the clone with the textarea value
    update: function() {
      this.$textCopy.text(this.$textarea.val().replace(/\r\n/g, "\n"));
      // Use `triggerHandler` to prevent conflicts with `update` in Prototype.js
      this.$textarea.triggerHandler("update.expanding");
    },
    // Tears down the plugin: removes generated elements, applies styles
    // that were prevously present, removes instance from registry,
    // unbinds events
    destroy: function() {
      this.$clone.remove();
      this.$textarea
        .unwrap()
        .attr('style', this._oldTextareaStyles || '');
      delete this._oldTextareaStyles;
      var index = $.inArray(this, Expanding._registry);
      if (index > -1) Expanding._registry.splice(index, 1);
      this.$textarea.unbind(
        'input.expanding change.expanding keyup.expanding update.expanding');
    },
    // Applies reset styles to the textarea and clone
    // Stores the original textarea styles in case of destroying
    _resetStyles: function() {
      this._oldTextareaStyles = this.$textarea.attr('style');
      this.$textarea.add(this.$clone).css({
        margin: 0,
        webkitBoxSizing: "border-box",
        mozBoxSizing: "border-box",
        boxSizing: "border-box",
        width: "100%"
      });
    },
    // Sets the basic clone styles and copies styles over from the textarea
    _setCloneStyles: function() {
      var css = {
        display: 'block',
        border: '0 solid',
        visibility: 'hidden',
        minHeight: this.$textarea.outerHeight()
      };
      if(this.$textarea.attr("wrap") === "off") css.overflowX = "scroll";
      else css.whiteSpace = "pre-wrap";
      this.$clone.css(css);
      this._copyTextareaStylesToClone();
    },
    _copyTextareaStylesToClone: function() {
      var _this = this,
        properties = [
          'lineHeight', 'textDecoration', 'letterSpacing',
          'fontSize', 'fontFamily', 'fontStyle',
          'fontWeight', 'textTransform', 'textAlign',
          'direction', 'wordSpacing', 'fontSizeAdjust',
          'wordWrap', 'word-break',
          'borderLeftWidth', 'borderRightWidth',
          'borderTopWidth','borderBottomWidth',
          'paddingLeft', 'paddingRight',
          'paddingTop','paddingBottom', 'maxHeight'];
      $.each(properties, function(i, property) {
        var val = _this.$textarea.css(property);
        // Prevent overriding percentage css values.
        if(_this.$clone.css(property) !== val) {
          _this.$clone.css(property, val);
          if(property === 'maxHeight' && val !== 'none') {
            _this.$clone.css('overflow', 'hidden');
          }
        }
      });
    },
    _setTextareaStyles: function() {
      this.$textarea.css({
        position: "absolute",
        top: 0,
        left: 0,
        height: "100%",
        resize: "none",
        overflow: "auto"
      });
    }
  };
  $.expanding = $.extend({
    autoInitialize: true,
    initialSelector: "textarea.expanding",
    opts: {
      update: function() { }
    }
  }, $.expanding || {});
  $.fn.expanding = function(o) {
    if (o === "destroy") {
      this.each(function() {
        var instance = Expanding.getExpandingInstance(this);
        if (instance) instance.destroy();
      });
      return this;
    }
    // Checks to see if any of the given DOM nodes have the
    // expanding behaviour.
    if (o === "active") {
      return !!this.filter(function() {
        return !!Expanding.getExpandingInstance(this);
      }).length;
    }
    var opts = $.extend({ }, $.expanding.opts, o);
    this.filter("textarea").each(function() {
      var visible = this.offsetWidth > 0 || this.offsetHeight > 0,
          initialized = Expanding.getExpandingInstance(this);
      if(visible && !initialized) new Expanding($(this), opts);
      else {
        if(!visible) _warn("ExpandingTextareas: attempt to initialize an invisible textarea. Call expanding() again once it has been inserted into the page and/or is visible.");
        if(initialized) _warn("ExpandingTextareas: attempt to initialize a textarea that has already been initialized. Subsequent calls are ignored.");
      }
    });
    return this;
  };
  function _warn(text) {
    if(window.console && console.warn) console.warn(text);
  }
  $(function () {
    if ($.expanding.autoInitialize) {
      $($.expanding.initialSelector).expanding();
    }
  });
}));
// Register the TextExpander snippet
skuid.snippet.registerSnippet('TextExpander',function(){
    var $ = skuid.$;
    var field = arguments[0];
    var value = skuid.utils.decodeHTML(arguments[1]);
    
    skuid.ui.fieldRenderers[field.metadata.displaytype][field.mode](field,value);
   
    field.element.find('textarea').expanding();
});


3. Save, and preview.
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
Thank you very much for taking the time to respond.

Do I need to do anything with the Field Renderering? I changed the field rendering to standard on all of the text fields. I also have tried changed the javascript resource from in-line (Snippet) to in-line and then copied and pasted your code, but the text boxes are not expanding.

Any ideas?
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
You will need to change the Field Renderer on all of your Textarea fields to be "Custom", and for Render Snippet, enter "TextExpander".
(Edited)
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
I just tried that and it isn't working for me. Here is a screen shot of the how I have it set up. Any ideas of what I might be doing wrong?

Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
That all looks correct. 
Photo of Emily Davis

Emily Davis, Employee

  • 3,502 Points 3k badge 2x thumb
It works for field editors but not for tables. Nate, are you using a table?
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
I tested it out and I have my field editor default mode set to "edit", but when I change it to "read with inline-edit" it works correctly. Is there a way to change it to expand the text box when the view is in the default mode of "edit"?
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
Any ideas of how to get this to work with the default mode of "edit"?
Photo of Zach McElrath

Zach McElrath, Employee

  • 49,056 Points 20k badge 2x thumb
Use this code instead for the Inline Resource body, it should work with default mode of "Edit" or "Read with Inline-Edit".

(All I changed was a little bit at the bottom, changing the Custom Field Renderer Snippet, to wait for the element to be added to the DOM before applying the expanding() plugin. This is a common pitfall for initial edit-mode renderers.)


// Expanding Textareas v0.1.2// MIT License// https://github.com/bgrins/ExpandingTextareas
(function(factory) {
  // Add jQuery via AMD registration or browser globals
  if (typeof define === 'function' && define.amd) {
    define([ 'jquery' ], factory);
  }
  else {
    factory(skuid.$);
  }
}(function ($) {
  var Expanding = function($textarea, opts) {
    Expanding._registry.push(this);
    this.$textarea = $textarea;
    this.$textCopy = $("<span />");
    this.$clone = $("<pre class='expanding-clone'><br /></pre>").prepend(this.$textCopy);
    this._resetStyles();
    this._setCloneStyles();
    this._setTextareaStyles();
    $textarea
      .wrap($("<div class='expanding-wrapper' style='position:relative' />"))
      .after(this.$clone);
    this.attach();
    this.update();
    if (opts.update) $textarea.bind("update.expanding", opts.update);
  };
  // Stores (active) `Expanding` instances
  // Destroyed instances are removed
  Expanding._registry = [];
  // Returns the `Expanding` instance given a DOM node
  Expanding.getExpandingInstance = function(textarea) {
    var $textareas = $.map(Expanding._registry, function(instance) {
        return instance.$textarea[0];
      }),
      index = $.inArray(textarea, $textareas);
    return index > -1 ? Expanding._registry[index] : null;
  };
  // Returns the version of Internet Explorer or -1
  // (indicating the use of another browser).
  // From: http://msdn.microsoft.com/en-us/library/ms537509(v=vs.85).aspx#ParsingUA
  var ieVersion = (function() {
    var v = -1;
    if (navigator.appName === "Microsoft Internet Explorer") {
      var ua = navigator.userAgent;
      var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
      if (re.exec(ua) !== null) v = parseFloat(RegExp.$1);
    }
    return v;
  })();
  // Check for oninput support
  // IE9 supports oninput, but not when deleting text, so keyup is used.
  // onpropertychange _is_ supported by IE8/9, but may not be fired unless
  // attached with `attachEvent`
  // (see: http://stackoverflow.com/questions/18436424/ie-onpropertychange-event-doesnt-fire),
  // and so is avoided altogether.
  var inputSupported = "oninput" in document.createElement("input") && ieVersion !== 9;
  Expanding.prototype = {
    // Attaches input events
    // Only attaches `keyup` events if `input` is not fully suported
    attach: function() {
      var events = 'input.expanding change.expanding',
        _this = this;
      if(!inputSupported) events += ' keyup.expanding';
      this.$textarea.bind(events, function() { _this.update(); });
    },
    // Updates the clone with the textarea value
    update: function() {
      this.$textCopy.text(this.$textarea.val().replace(/\r\n/g, "\n"));
      // Use `triggerHandler` to prevent conflicts with `update` in Prototype.js
      this.$textarea.triggerHandler("update.expanding");
    },
    // Tears down the plugin: removes generated elements, applies styles
    // that were prevously present, removes instance from registry,
    // unbinds events
    destroy: function() {
      this.$clone.remove();
      this.$textarea
        .unwrap()
        .attr('style', this._oldTextareaStyles || '');
      delete this._oldTextareaStyles;
      var index = $.inArray(this, Expanding._registry);
      if (index > -1) Expanding._registry.splice(index, 1);
      this.$textarea.unbind(
        'input.expanding change.expanding keyup.expanding update.expanding');
    },
    // Applies reset styles to the textarea and clone
    // Stores the original textarea styles in case of destroying
    _resetStyles: function() {
      this._oldTextareaStyles = this.$textarea.attr('style');
      this.$textarea.add(this.$clone).css({
        margin: 0,
        webkitBoxSizing: "border-box",
        mozBoxSizing: "border-box",
        boxSizing: "border-box",
        width: "100%"
      });
    },
    // Sets the basic clone styles and copies styles over from the textarea
    _setCloneStyles: function() {
      var css = {
        display: 'block',
        border: '0 solid',
        visibility: 'hidden',
        minHeight: this.$textarea.outerHeight()
      };
      if(this.$textarea.attr("wrap") === "off") css.overflowX = "scroll";
      else css.whiteSpace = "pre-wrap";
      this.$clone.css(css);
      this._copyTextareaStylesToClone();
    },
    _copyTextareaStylesToClone: function() {
      var _this = this,
        properties = [
          'lineHeight', 'textDecoration', 'letterSpacing',
          'fontSize', 'fontFamily', 'fontStyle',
          'fontWeight', 'textTransform', 'textAlign',
          'direction', 'wordSpacing', 'fontSizeAdjust',
          'wordWrap', 'word-break',
          'borderLeftWidth', 'borderRightWidth',
          'borderTopWidth','borderBottomWidth',
          'paddingLeft', 'paddingRight',
          'paddingTop','paddingBottom', 'maxHeight'];
      $.each(properties, function(i, property) {
        var val = _this.$textarea.css(property);
        // Prevent overriding percentage css values.
        if(_this.$clone.css(property) !== val) {
          _this.$clone.css(property, val);
          if(property === 'maxHeight' && val !== 'none') {
            _this.$clone.css('overflow', 'hidden');
          }
        }
      });
    },
    _setTextareaStyles: function() {
      this.$textarea.css({
        position: "absolute",
        top: 0,
        left: 0,
        height: "100%",
        resize: "none",
        overflow: "auto"
      });
    }
  };
  $.expanding = $.extend({
    autoInitialize: true,
    initialSelector: "textarea.expanding",
    opts: {
      update: function() { }
    }
  }, $.expanding || {});
  $.fn.expanding = function(o) {
    if (o === "destroy") {
      this.each(function() {
        var instance = Expanding.getExpandingInstance(this);
        if (instance) instance.destroy();
      });
      return this;
    }
    // Checks to see if any of the given DOM nodes have the
    // expanding behaviour.
    if (o === "active") {
      return !!this.filter(function() {
        return !!Expanding.getExpandingInstance(this);
      }).length;
    }
    var opts = $.extend({ }, $.expanding.opts, o);
    this.filter("textarea").each(function() {
      var visible = this.offsetWidth > 0 || this.offsetHeight > 0,
          initialized = Expanding.getExpandingInstance(this);
      if(visible && !initialized) new Expanding($(this), opts);
      else {
        if(!visible) _warn("ExpandingTextareas: attempt to initialize an invisible textarea. Call expanding() again once it has been inserted into the page and/or is visible.");
        if(initialized) _warn("ExpandingTextareas: attempt to initialize a textarea that has already been initialized. Subsequent calls are ignored.");
      }
    });
    return this;
  };
  function _warn(text) {
    if(window.console && console.warn) console.warn(text);
  }
  $(function () {
    if ($.expanding.autoInitialize) {
      $($.expanding.initialSelector).expanding();
    }
  });
}));
(function(skuid){
    // Register the TextExpander snippet
    skuid.snippet.registerSnippet('TextExpander',function(){
    var $ = skuid.$;
    var field = arguments[0];
    var value = skuid.utils.decodeHTML(arguments[1]);
    
    skuid.ui.fieldRenderers[field.metadata.displaytype][field.mode](field,value);
   
   if (!field.element.parent().length) {
       setTimeout(function(){
          field.element.find('textarea').expanding(); 
       },1500);   
   } else {
       field.element.find('textarea').expanding(); 
   }
    
});
})(skuid);
(Edited)
Photo of Tami Lust

Tami Lust

  • 5,280 Points 5k badge 2x thumb
I experienced the same issue Nate did with it allowing me to type one character and then the focus of the cursor goes somewhere else on the page. I tried the above code but the text box does not expand. Will the above code work for a text box?

Originally I just used just the skuid portion of the code as an inline snippet. It expanded a text box but the pesky not being able to type thing became an issue:
var $ = skuid.$, field = arguments[0], value = arguments[1];
var model = field.model, row = field.row;

var containerDiv = field.element;
var fieldText = $('<textarea class="expanding">' + value + '</textarea>');

//Update field value when text is changed
$(fieldText).bind('input propertychange', function() {
    var fieldsToUpdate = {};
    fieldsToUpdate[field.id] = $(this).val();
    
    model.updateRow(row, fieldsToUpdate);
});

$(containerDiv).append(fieldText);
Photo of Rob Hatch

Rob Hatch, Official Rep

  • 44,006 Points 20k badge 2x thumb
Our experience with the scenario you describe is as follows. 
1. You have a template with an iFrame somewhere else on your page that is tied to this same model. 
2. When you type a character - the model detects changes, the template says "Ooh - I saw changes and need to let my iFrame know about it" and focus is grabbed by the template. 
3. Having lost focus on your text box, you do somthing like hit the back-space and your browser takes you back a page.   ACK!

So tie the template to another model (even if it sourcing exactly the same data from the same objects)... 

And yes - Text Fields should work with the code above. 
Photo of Tami Lust

Tami Lust

  • 5,280 Points 5k badge 2x thumb
Hi Rob,

I understand what you are saying about what is happening. However, I don't think I have anything else tied to this model. This model has one field "Invoice Number". That field is in a field editor (inside a panel set).

I use this field to filter data in another table. The other table is attached to a different model. 

Based on the set up do you see how this could be happening. 
Photo of Nate Gilbertson

Nate Gilbertson

  • 1,194 Points 1k badge 2x thumb
Thank you very much! That did the trick!