132 votes

Comment redimensionner automatiquement un textarea avec Prototype ?

Je travaille actuellement sur une application de vente interne pour la société pour laquelle je travaille, et j'ai un formulaire qui permet à l'utilisateur de modifier l'adresse de livraison.

Maintenant, je pense que ce serait beaucoup plus joli si la zone de texte que j'utilise pour les détails de l'adresse principale prenait juste la zone de texte qu'elle contient, et se redimensionnait automatiquement si le texte était modifié.

Voici une capture d'écran de la situation actuelle.

ISO Address

Des idées ?


@Chris

Un bon point, mais il y a des raisons pour lesquelles je veux qu'il soit redimensionné. Je veux que la surface qu'il occupe corresponde à la surface des informations qu'il contient. Comme vous pouvez le voir dans la capture d'écran, si j'ai un textarea fixe, il occupe une bonne partie de l'espace vertical.

Je peux réduire la police, mais j'ai besoin que l'adresse soit grande et lisible. Je peux maintenant réduire la taille de la zone de texte, mais j'ai alors des problèmes avec les personnes qui ont une ligne d'adresse qui prend 3 ou 4 (une prend 5) lignes. La nécessité de demander à l'utilisateur d'utiliser une barre de défilement est un gros problème.

Je suppose que je devrais être un peu plus précis. Je cherche un redimensionnement vertical, et la largeur n'est pas aussi importante. Le seul problème qui se pose est que le numéro ISO (le grand "1") est repoussé sous l'adresse lorsque la largeur de la fenêtre est trop faible (comme vous pouvez le voir sur la capture d'écran).

Il ne s'agit pas d'avoir un gadget, mais d'avoir un champ de texte que l'utilisateur peut modifier, qui ne prend pas d'espace inutile, mais qui affiche tout le texte qu'il contient.

Mais si quelqu'un trouve une autre façon d'aborder le problème, je suis également ouvert à cette idée.


J'ai modifié un peu le code car il se comportait un peu bizarrement. Je l'ai changé pour qu'il s'active sur le keyup, car il ne prenait pas en compte le caractère qui venait 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;
};

0 votes

Pouvez-vous créer un site de démonstration où nous pourrions voir cela à l'œuvre ?

3 votes

Ce plugin semble bon jacklmoore.com/autosize

0 votes

Existe-t-il une version de JQuery ? Comment accéder aux colonnes et aux lignes d'un TextArea en JQuery ?

80voto

Orion Edwards Points 54939

Facebook le fait, lorsque vous écrivez sur les murs des gens, mais ne le redimensionne que verticalement.

Le redimensionnement horizontal me semble être un véritable gâchis, en raison du retournement des mots, des longues lignes, etc., mais le redimensionnement vertical semble être assez sûr et agréable.

Aucun des nouveaux utilisateurs de Facebook que je connais n'a jamais mentionné quoi que ce soit à ce sujet ou n'a été confus. J'utiliserais cela comme une preuve anecdotique pour dire "allez-y, mettez-le en place".

Un peu de code JavaScript pour le faire, en utilisant Prototype (parce que c'est ce que je connais) :

<!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 : Il est évident que ce code JavaScript est très naïf et n'a pas été testé, et vous ne voudrez probablement pas l'utiliser sur des zones de texte contenant des romans, mais vous avez compris l'idée générale.

2 votes

Cela suppose que le navigateur s'interrompt à n'importe quel caractère, ce qui est incorrect. Essayez-le sur <textarea cols='5'>0 12345 12345 0</textarea> . (J'ai écrit une implémentation presque identique et je n'ai remarqué cela qu'après un mois d'utilisation). Il échoue également pour les lignes vides.

0 votes

Existe-t-il une version JQuery pour cela ?

0 votes

La barre oblique inversée dans $A(str.split(" \n ")) en nécessite une autre. (Mon édition de la réponse ci-dessus n'a pas survécu pour une raison quelconque).

71voto

Jan Miksovsky Points 660

Un raffinement de certaines de ces réponses consiste à laisser les CSS faire une plus grande partie du travail.

L'itinéraire de base semble être :

  1. Créez un élément conteneur pour contenir le textarea et un caché div
  2. En utilisant Javascript, gardez le textarea synchronisé avec le contenu de la div 's
  3. Laissez le navigateur faire le travail de calcul de la hauteur de cette div.
  4. Parce que le navigateur se charge du rendu et du dimensionnement de l'image cachée. div nous évitons de fixer explicitement la textarea la hauteur de l'homme.

    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; }

    <div class="textarea-container"> <textarea id="textArea"></textarea> <div id="textCopy"></div> </div>

5 votes

C'est une solution géniale ! Le seul problème est que les navigateurs qui ne prennent pas en charge le box-sizing (IE<7) ne calculeront pas correctement la largeur et vous perdrez donc un peu de précision, mais si vous laissez une ligne d'espace à la fin, ça devrait aller. Je l'aime vraiment pour sa simplicité.

0 votes

Fonctionne encore mieux avec resize:none; dans le style de la zone de texte !

4 votes

J'ai pris la liberté de mettre en œuvre cette solution sous la forme d'un plugin jQuery autonome et simple à utiliser, sans qu'il soit nécessaire d'y ajouter des balises ou du style. xion.io/jQuery.xarea au cas où quelqu'un pourrait l'utiliser :)

39voto

Shog9 Points 82052

Voici une autre technique d'autodimensionnement d'un textarea.

  • Utilise la hauteur des pixels au lieu de la hauteur des lignes : gestion plus précise du retour à la ligne si une police proportionnelle est utilisée.
  • Accepte l'ID ou l'élément comme entrée
  • Accepte un paramètre facultatif de hauteur maximale - utile si vous préférez que la zone de texte ne dépasse pas une certaine taille (pour que tout reste à l'écran, pour éviter de casser la mise en page, etc.)
  • Testé sur Firefox 3 et Internet Explorer 6

Code : (simple vanille JavaScript)

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émonstration : (utilise jQuery, cible la zone de texte dans laquelle je tape en ce moment même - si vous avez Firebug installé, collez les deux échantillons dans la console et testez sur cette page)

$("#post-text").keyup(function()
{
   FitToContent(this, document.documentElement.clientHeight)
});

0 votes

@SMB - cela ne serait probablement pas trop difficile à mettre en œuvre, il suffit d'ajouter une autre conditionnelle

0 votes

@Jason : Quand le texte dans la boîte ne la remplit pas, clientHeight et scrollHeight sont égales, vous ne pouvez donc pas utiliser cette méthode si vous voulez que votre zone de texte rétrécisse et s'agrandisse.

0 votes

Pour le faire rétrécir, il suffit d'ajouter ce code avant la ligne 6 : if (text.clientHeight == text.scrollHeight) text.style.height = "20px";

17voto

Eduard Luca Points 1968

C'est 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 d'autres choses du genre.

Note : vous devrez peut-être jouer avec this.style.height = (this.scrollHeight) + "px"; en fonction du style de la zone de texte (hauteur de ligne, remplissage, etc.).

0 votes

La meilleure solution si le clignotement de la barre de défilement ne vous dérange pas.

0 votes

Il serait suffisant d'attraper seulement l'événement keyup. Vous ne pensez pas ?

3 votes

Définissez la propriété de débordement de la zone de texte sur "hidden" pour éviter le clignotement de la barre de défilement.

8voto

jeremy Points 6308

Voici un Prototype version du redimensionnement d'une zone de texte qui ne dépend pas du nombre de colonnes de la zone de texte. Il s'agit d'une technique supérieure car elle vous permet de contrôler la zone de texte via le CSS et d'avoir une zone de texte de largeur variable. En outre, cette version affiche le nombre de caractères restants. Bien qu'elle ne soit pas obligatoire, cette fonctionnalité est très utile et peut être facilement supprimée si elle n'est pas souhaitée.

//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 surchargées en les passant comme un objet, par ex. 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);
  });   
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X