Autosizing textarea utilisant le Prototype

Je travaille actuellement sur une application de vente interne pour l'entreprise pour laquelle je travaille, et j'ai un formulaire qui permet à l'utilisateur de changer l'adresse de livraison.

Maintenant, je pense que cela serait beaucoup plus agréable, si la zone de texte que j'utilise pour les détails de l'adresse principale prenait simplement la zone du texte et se redimensionnait automatiquement si le texte était modifié.

Voici une capture d'écran actuellement.

Adresse ISO

Des idées?


@Chris

Un bon point, mais il y a des raisons pour lesquelles je veux redimensionner. Je veux que la zone qu'il prend soit la zone de l'information qu'il contient. Comme vous pouvez le voir dans la capture d'écran, si j'ai un textarea fixe, il prend un juste farfelu de l'espace vertical.

Je peux réduire la police, mais j'ai besoin d'une adresse pour être grande et lisible. Maintenant, je peux réduire la taille de la zone de texte, mais j'ai des problèmes avec les gens qui ont une ligne d'adresse qui prend 3 ou 4 (on prend 5) lignes. Avoir besoin que l'utilisateur utilise un scrollbar est un non-non majeur.

Je suppose que je devrais être un peu plus précis. Je suis après le redimensionnement vertical, et la largeur n'a pas autant d'importance. Le seul problème qui se produit avec cela, est le nombre ISO (Le Grand "1") est poussé sous l'adresse lorsque la largeur de la fenêtre est trop petite (comme vous pouvez le voir sur la capture d'écran).

Il ne s'agit pas d'avoir un gimick; il s'agit d'avoir un champ de texte que l'utilisateur peut modifier qui ne prendra pas de place inutile, mais affichera tout le texte il.

Bien que si quelqu'un trouve une autre façon d'aborder le problème, je suis ouvert à cela aussi.


J'ai un peu modifié le code parce qu'il agissait un peu bizarre. Je l'ai changé pour l'activer sur keyup, car il ne prendrait pas en considération le caractère qui vient d'être tapé.

resizeIt = function() {
  var str = $('iso_address').value;
  var cols = $('iso_address').cols;
  var linecount = 0;

  $A(str.split("n")).each(function(l) {
    linecount += 1 + Math.floor(l.length / cols); // Take into account long lines
  })

  $('iso_address').rows = linecount;
};
110
demandé sur Peter Mortensen 2008-08-11 05:43:13

18 réponses

Facebook le fait, quand vous écrivez sur les murs des gens, mais seulement redimensionne verticalement.

Le redimensionnement Horizontal me semble être un gâchis, en raison de l'enveloppement de mots, des longues lignes, etc., mais le redimensionnement vertical semble être assez sûr et agréable.

Aucun des débutants qui utilisent Facebook que je connais n'a jamais mentionné quoi que ce soit à ce sujet ou été confus. Je l'utiliserais comme une preuve anecdotique pour dire "Allez-y, mettez-le en œuvre".

Du code JavaScript pour le faire, en utilisant Prototype (parce que c'est ce que je suis familier avec):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <script src="http://www.google.com/jsapi"></script>
        <script language="javascript">
            google.load('prototype', '1.6.0.2');
        </script>
    </head>

    <body>
        <textarea id="text-area" rows="1" cols="50"></textarea>

        <script type="text/javascript" language="javascript">
            resizeIt = function() {
              var str = $('text-area').value;
              var cols = $('text-area').cols;

              var linecount = 0;
              $A(str.split("\n")).each( function(l) {
                  linecount += Math.ceil( l.length / cols ); // Take into account long lines
              })
              $('text-area').rows = linecount + 1;
            };

            // You could attach to keyUp, etc. if keydown doesn't work
            Event.observe('text-area', 'keydown', resizeIt );

            resizeIt(); //Initial on load
        </script>
    </body>
</html>

PS: évidemment, ce code JavaScript est très naïf et pas bien testé, et vous ne voulez probablement pas l'utiliser sur des zones de texte avec des romans, mais vous avez l'idée générale.

71
répondu Orion Edwards 2016-02-13 00:56:16

Un raffinement à certaines de ces réponses est de laisser CSS faire plus de travail.

L'itinéraire de base semble être:

  1. créer un élément conteneur pour contenir le textarea et un {[4 caché]}
  2. en utilisant Javascript, gardez le contenu du textarea synchronisé avec celui du div
  3. laissez le navigateur faire le travail de calculer la hauteur de cette div
  4. parce que le navigateur gère le rendu / dimensionnement du div caché, nous évitons définition explicite des textarea hauteur.

document.addEventListener('DOMContentLoaded', () => {
    textArea.addEventListener('change', autosize, false)
    textArea.addEventListener('keydown', autosize, false)
    textArea.addEventListener('keyup', autosize, false)
    autosize()
}, false)

function autosize() {
    // Copy textarea contents to div browser will calculate correct height
    // of copy, which will make overall container taller, which will make
    // textarea taller.
    textCopy.innerHTML = textArea.value.replace(/\n/g, '<br/>')
}
html, body, textarea {
    font-family: sans-serif;
    font-size: 14px;
}

.textarea-container {
    position: relative;
}

.textarea-container > div, .textarea-container > textarea {
    word-wrap: break-word; /* make sure the div and the textarea wrap words in the same way */
    box-sizing: border-box;
    padding: 2px;
    width: 100%;
}

.textarea-container > textarea {
    overflow: hidden;
    position: absolute;
    height: 100%;
}

.textarea-container > div {
    padding-bottom: 1.5em; /* A bit more than one additional line of text. */ 
    visibility: hidden;
    width: 100%;
}
<div class="textarea-container">
    <textarea id="textArea"></textarea>
    <div id="textCopy"></div>
</div>
57
répondu Jan Miksovsky 2018-05-17 18:31:51

Voici une autre technique pour autosizing un textarea.

  • utilise la hauteur de pixel au lieu de la hauteur de ligne: traitement plus précis de l'habillage de ligne si une police proportionnelle est utilisée.
  • Accepte L'ID ou l'élément en entrée
  • Accepte un paramètre facultatif de hauteur maximale-utile si vous préférez ne pas laisser la zone de texte dépasser une certaine taille (gardez tout à l'écran, évitez de casser la mise en page, etc.)
  • testé sur Firefox 3 et Internet Explorer 6

Code: (JavaScript vanille simple)

function FitToContent(id, maxHeight)
{
   var text = id && id.style ? id : document.getElementById(id);
   if (!text)
      return;

   /* Accounts for rows being deleted, pixel value may need adjusting */
   if (text.clientHeight == text.scrollHeight) {
      text.style.height = "30px";
   }

   var adjustedHeight = text.clientHeight;
   if (!maxHeight || maxHeight > adjustedHeight)
   {
      adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
      if (maxHeight)
         adjustedHeight = Math.min(maxHeight, adjustedHeight);
      if (adjustedHeight > text.clientHeight)
         text.style.height = adjustedHeight + "px";
   }
}

Démo: (utilise jQuery, cibles sur la zone de texte dans laquelle je tape en ce moment - si vous avezFirebug installé, collez les deux échantillons dans la console et testez sur cette page)

$("#post-text").keyup(function()
{
   FitToContent(this, document.documentElement.clientHeight)
});
38
répondu Shog9 2016-02-13 00:31:05

Probablement la solution la plus courte:

jQuery(document).ready(function(){
    jQuery("#textArea").on("keydown keyup", function(){
        this.style.height = "1px";
        this.style.height = (this.scrollHeight) + "px"; 
    });
});

De cette façon, vous n'avez pas besoin de divs cachés ou quelque chose comme ça.

Note: vous devrez peut-être jouer avec this.style.height = (this.scrollHeight) + "px"; en fonction de la façon dont vous stylisez la zone de texte (hauteur de ligne, remplissage et ce genre de choses).

12
répondu Eduard Luca 2016-02-13 00:49:35

Voici une version Prototype de redimensionnement d'une zone de texte qui ne dépend pas du nombre de colonnes dans la zone de texte. C'est une technique supérieure car elle vous permet de contrôler la zone de texte via CSS ainsi que d'avoir une zone de texte à largeur variable. De plus, cette version affiche le nombre de caractères restants. Bien que non demandé, il est une fonctionnalité très utile et est facilement retiré si indésirable.

//inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
if (window.Widget == undefined) window.Widget = {}; 

Widget.Textarea = Class.create({
  initialize: function(textarea, options)
  {
    this.textarea = $(textarea);
    this.options = $H({
      'min_height' : 30,
      'max_length' : 400
    }).update(options);

    this.textarea.observe('keyup', this.refresh.bind(this));

    this._shadow = new Element('div').setStyle({
      lineHeight : this.textarea.getStyle('lineHeight'),
      fontSize : this.textarea.getStyle('fontSize'),
      fontFamily : this.textarea.getStyle('fontFamily'),
      position : 'absolute',
      top: '-10000px',
      left: '-10000px',
      width: this.textarea.getWidth() + 'px'
    });
    this.textarea.insert({ after: this._shadow });

    this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
    this.textarea.insert({after: this._remainingCharacters});  
    this.refresh();  
  },

  refresh: function()
  { 
    this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
    this.textarea.setStyle({
      height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
    });

    var remaining = this.options.get('max_length') - $F(this.textarea).length;
    this._remainingCharacters.update(Math.abs(remaining)  + ' characters ' + (remaining > 0 ? 'remaining' : 'over the limit'));
  }
});

Créez le widget en appelant new Widget.Textarea('element_id'). Les options par défaut peuvent être remplacé en les passant en tant qu'objet, par exemple new Widget.Textarea('element_id', { max_length: 600, min_height: 50}). Si vous voulez le créer pour toutes les zones de texte de la page, faites quelque chose comme:

Event.observe(window, 'load', function() {
  $$('textarea').each(function(textarea) {
    new Widget.Textarea(textarea);
  });   
});
8
répondu Jeremy Kauffman 2016-02-07 18:08:34

Voici une solution avec JQuery:

$(document).ready(function() {
    var $abc = $("#abc");
    $abc.css("height", $abc.attr("scrollHeight"));
})

abc est un teaxtarea.

7
répondu memical 2017-02-23 10:29:31

Vérifier le lien ci-dessous: http://james.padolsey.com/javascript/jquery-plugin-autoresize/

$(document).ready(function () {
    $('.ExpandableTextCSS').autoResize({
        // On resize:
        onResize: function () {
            $(this).css({ opacity: 0.8 });
        },
        // After resize:
        animateCallback: function () {
            $(this).css({ opacity: 1 });
        },
        // Quite slow animation:
        animateDuration: 300,
        // More extra space:
        extraSpace:20,
        //Textarea height limit
        limit:10
    });
});
5
répondu Gyan 2016-02-07 18:09:04

Juste en revisitant cela, je l'ai rendu un peu plus net (bien que quelqu'un qui est plein bouteille sur Prototype/JavaScript pourrait suggérer des améliorations?).

var TextAreaResize = Class.create();
TextAreaResize.prototype = {
  initialize: function(element, options) {
    element = $(element);
    this.element = element;

    this.options = Object.extend(
      {},
      options || {});

    Event.observe(this.element, 'keyup',
      this.onKeyUp.bindAsEventListener(this));
    this.onKeyUp();
  },

  onKeyUp: function() {
    // We need this variable because "this" changes in the scope of the
    // function below.
    var cols = this.element.cols;

    var linecount = 0;
    $A(this.element.value.split("\n")).each(function(l) {
      // We take long lines into account via the cols divide.
      linecount += 1 + Math.floor(l.length / cols);
    })

    this.element.rows = linecount;
  }
}

Juste l'appel avec:

new TextAreaResize('textarea_id_name_here');
3
répondu Mike 2016-02-13 00:33:51

J'ai fait quelque chose de très facile. D'abord, je mets le TextArea dans un DIV. Deuxièmement, j'ai appelé la fonction ready à ce script.

<div id="divTable">
  <textarea ID="txt" Rows="1" TextMode="MultiLine" />
</div>

$(document).ready(function () {
  var heightTextArea = $('#txt').height();
  var divTable = document.getElementById('divTable');
  $('#txt').attr('rows', parseInt(parseInt(divTable .style.height) / parseInt(altoFila)));
});

Simple. C'est la hauteur maximale de la div une fois qu'elle est rendue, divisée par la hauteur d'une zone de texte d'une ligne.

3
répondu Eduardo Mass 2016-02-13 00:43:33

J'avais besoin de cette fonction pour moi-même, mais aucune de celles d'ici ne fonctionnait comme j'en avais besoin.

J'ai donc utilisé le code D'Orion et l'ai changé.

J'ai ajouté dans une hauteur minimale, de sorte que sur la destruction, il ne soit pas trop petit.

function resizeIt( id, maxHeight, minHeight ) {
    var text = id && id.style ? id : document.getElementById(id);
    var str = text.value;
    var cols = text.cols;
    var linecount = 0;
    var arStr = str.split( "\n" );
    $(arStr).each(function(s) {
        linecount = linecount + 1 + Math.floor(arStr[s].length / cols); // take into account long lines
    });
    linecount++;
    linecount = Math.max(minHeight, linecount);
    linecount = Math.min(maxHeight, linecount);
    text.rows = linecount;
};
2
répondu Peter Mortensen 2016-02-13 00:35:03

Comme la réponse de @ memical.

Cependant j'ai trouvé quelques améliorations. Vous pouvez utiliser la fonction jQuery height(). Mais soyez conscient des pixels padding-top et padding-bottom. Sinon, votre textarea grandira trop vite.

$(document).ready(function() {
  $textarea = $("#my-textarea");

  // There is some diff between scrollheight and height:
  //    padding-top and padding-bottom
  var diff = $textarea.prop("scrollHeight") - $textarea.height();
  $textarea.live("keyup", function() {
    var height = $textarea.prop("scrollHeight") - diff;
    $textarea.height(height);
  });
});
2
répondu Anatoly Mironov 2016-02-13 00:41:40

Voici une extension du widget Prototype que Jeremy a posté le 4 juin:

Cela empêche l'utilisateur d'entrer plus de caractères si vous utilisez des limites dans textareas. Il vérifie si il y a des caractères à gauche. Si l'utilisateur copie du texte dans la zone de texte, le texte est coupé au maximum. longueur:

/**
 * Prototype Widget: Textarea
 * Automatically resizes a textarea and displays the number of remaining chars
 * 
 * From: http://stackoverflow.com/questions/7477/autosizing-textarea
 * Inspired by: http://github.com/jaz303/jquery-grab-bag/blob/63d7e445b09698272b2923cb081878fd145b5e3d/javascripts/jquery.autogrow-textarea.js
 */
if (window.Widget == undefined) window.Widget = {}; 

Widget.Textarea = Class.create({
  initialize: function(textarea, options){
    this.textarea = $(textarea);
    this.options = $H({
      'min_height' : 30,
      'max_length' : 400
    }).update(options);

    this.textarea.observe('keyup', this.refresh.bind(this));

    this._shadow = new Element('div').setStyle({
      lineHeight : this.textarea.getStyle('lineHeight'),
      fontSize : this.textarea.getStyle('fontSize'),
      fontFamily : this.textarea.getStyle('fontFamily'),
      position : 'absolute',
      top: '-10000px',
      left: '-10000px',
      width: this.textarea.getWidth() + 'px'
    });
    this.textarea.insert({ after: this._shadow });

    this._remainingCharacters = new Element('p').addClassName('remainingCharacters');
    this.textarea.insert({after: this._remainingCharacters});  
    this.refresh();  
  },

  refresh: function(){ 
    this._shadow.update($F(this.textarea).replace(/\n/g, '<br/>'));
    this.textarea.setStyle({
      height: Math.max(parseInt(this._shadow.getHeight()) + parseInt(this.textarea.getStyle('lineHeight').replace('px', '')), this.options.get('min_height')) + 'px'
    });

    // Keep the text/character count inside the limits:
    if($F(this.textarea).length > this.options.get('max_length')){
      text = $F(this.textarea).substring(0, this.options.get('max_length'));
        this.textarea.value = text;
        return false;
    }

    var remaining = this.options.get('max_length') - $F(this.textarea).length;
    this._remainingCharacters.update(Math.abs(remaining)  + ' characters remaining'));
  }
});
1
répondu lorem monkey 2009-11-30 14:39:24

@memical avait une solution géniale pour définir la hauteur de la zone de texte sur pageload avec jQuery, mais pour mon application, je voulais pouvoir augmenter la hauteur de la zone de texte à mesure que l'utilisateur ajoutait plus de contenu. J'ai construit la solution de memical avec ce qui suit:

$(document).ready(function() {
    var $textarea = $("p.body textarea");
    $textarea.css("height", ($textarea.attr("scrollHeight") + 20));
    $textarea.keyup(function(){
        var current_height = $textarea.css("height").replace("px", "")*1;
        if (current_height + 5 <= $textarea.attr("scrollHeight")) {
            $textarea.css("height", ($textarea.attr("scrollHeight") + 20));
        }
    });
});

Ce n'est pas très lisse mais ce n'est pas non plus une application orientée client, donc la douceur n'a pas vraiment d'importance. (Si cela avait été face au client, je serais probablement juste utilisé un jQuery auto-redimensionné plugin.)

1
répondu Jazzerus 2017-05-23 12:34:18

Pour ceux qui codent pour IE et rencontrent ce problème. IE a un petit truc qui le rend 100% CSS.

<TEXTAREA style="overflow: visible;" cols="100" ....></TEXTAREA>

Vous pouvez même fournir une valeur pour rows = "n" que IE ignorera, mais d'autres navigateurs utiliseront. Je déteste vraiment le codage qui implémente IE hacks, mais celui-ci est très utile. Il est possible que cela ne fonctionne qu'en mode bizarreries.

1
répondu Einstein47 2013-06-13 22:26:22

Internet Explorer, Safari, Chrome et Opera les utilisateurs doivent se rappeler de définir explicitement la valeur de hauteur de ligne en CSS. Je fais une feuille de style qui définit les propriétés initiales pour toutes les zones de texte comme suit.

<style>
    TEXTAREA { line-height: 14px; font-size: 12px; font-family: arial }
</style>
1
répondu Larry 2016-02-13 00:37:44

Voici une fonction que je viens d'écrire dans jQuery pour le faire-vous pouvez le porter sur Prototype , mais ils ne supportent pas la" vivacité " de jQuery, donc les éléments ajoutés par les requêtes Ajax ne répondront pas.

Cette version se développe non seulement, mais elle se contracte également lorsque vous appuyez sur delete ou backspace.

Cette version repose sur jQuery 1.4.2.

Profitez ;)

Http://pastebin.com/SUKeBtnx

Utilisation:

$("#sometextarea").textareacontrol();

Ou (tout sélecteur jQuery pour exemple)

$("textarea").textareacontrol();

Il a été testé sur Internet Explorer 7/Internet Explorer 8, Firefox 3.5, et le Chrome. Tout fonctionne très bien.

1
répondu Alex 2016-02-13 00:40:11

Utilisation ASP.NET, faites simplement ceci:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Automatic Resize TextBox</title>
        <script type="text/javascript">
            function setHeight(txtarea) {
                txtarea.style.height = txtdesc.scrollHeight + "px";
            }
        </script>
    </head>

    <body>
        <form id="form1" runat="server">
            <asp:TextBox ID="txtarea" runat= "server" TextMode="MultiLine"  onkeyup="setHeight(this);" onkeydown="setHeight(this);" />
        </form>
    </body>
</html>
1
répondu Pat Murray 2016-02-13 00:45:29

Ma solution n'utilisant pas jQuery (parce que parfois ils ne doivent pas être la même chose) est ci-dessous. Bien qu'il n'ait été testé que dans Internet Explorer 7 , la communauté peut donc indiquer toutes les raisons pour lesquelles cela est faux:

textarea.onkeyup = function () { this.style.height = this.scrollHeight + 'px'; }

Jusqu'à présent, j'aime vraiment comment cela fonctionne, et je ne me soucie pas des autres navigateurs, donc je vais probablement l'appliquer à tous mes textareas:

// Make all textareas auto-resize vertically
var textareas = document.getElementsByTagName('textarea');

for (i = 0; i<textareas.length; i++)
{
    // Retain textarea's starting height as its minimum height
    textareas[i].minHeight = textareas[i].offsetHeight;

    textareas[i].onkeyup = function () {
        this.style.height = Math.max(this.scrollHeight, this.minHeight) + 'px';
    }
    textareas[i].onkeyup(); // Trigger once to set initial height
}
1
répondu user1566694 2016-02-13 00:48:10