Bonjour,

Je voudrais faire un textarea qui s'adapte au contenu au chargement de la page, mon script fonctionne avec un textarea classique (en HTML pur). Je voudrais intégrer mon script à l'administration de mon site.

Par exemple pour administrer un article ma page contient un formulaire avec différents champs dont un textarea.
Le problème c'est que le formulaire est généré en PHP et les différentes valeurs des champs proviennent de la base de données.
Du coup mon script n'arrive pas à calculer la largeur de mon textarea

Voici mon code actuel :

jQuery(function($) {

    $.each($("textarea[data-autoresize]"), function() {
        var offset = this.offsetHeight - this.clientHeight;

        var resizeTextarea = function(e) {
            $(e).css("height", "auto").css("height", e.scrollHeight + offset);
        };

        $(this).on("keydown input", function() { resizeTextarea(this); });

        console.log("Height : " + $(this).height());
        console.log("scrollHeight : " + this.scrollHeight);

        if ($(this).height() < this.scrollHeight + offset) {
            resizeTextarea(this);
        }
    });

});

console.log me donne le résultat suivant :

Height : 0
scrollHeight : 0

Comment puis-je faire pour qu'il calcule correctement la taille de mes textarea ?

14 réponses


reuno92
Réponse acceptée

Avec jQuery, le mieux c'est de commencer et finir avec

$('document').ready(function() {

});

Ce que l'on ne voit pas dans le code que tu propose. Comme ça, on s'assure que le script javascript passe après tout le reste.
J'ai testé dernièrement un script pour détecter la largeur d'un élément avec width(). J'ai pas pu parce qu'il n'était pas afficher directement... il fallait attendre que le modal bootstrap et que s'affiche l'élément pour pouvoir le calculer (logique oui :p).
la résolution du problème à été de mettre un setTimeout( function(/ ton code /), 1000);

N'hésite pas à nous faire un retour sur ton expérience.

Si quelqu'un peut répondre à ma question, je suis preneur ^^

Hello,

Ton script fonctionne, tu as juste fait une erreur dans ton console.log (tu as oublié le t de height)

console.log("scrollHeight : " + this.scrollHeight);

Oui j'ai fait une faute de frappe mais cela ne règle pas le problème il me donne 0 au lieu de undefined (J'ai corrigé mon post)
En HTML pur il marche mais quand le formulaire est générer en PHP avec le contenu provenant de la base de données il ne marche plus

Peux-tu me montrer ton code d'un textarea avec ton php?

C'est une classe mais je peux te montrer le code

La fonction textarea de la classe CustomForm

public function textarea($name, $label, $options = []) {
        // Parametres
        $pattern = isset($options["pattern"]) ? 'pattern="'.$options["pattern"].'"' : null;
        $required = isset($options["required"]) ? "required" : null;
        $placeholder = isset($options["placeholder"]) ? 'placeholder="'.$options["placeholder"].'"' : null;
        $rows = isset($options["rows"]) ? $options["rows"] : 2;

        $label = '<label>'.$label.'</label>';
        $field = '<textarea name="'.$name.'" '.$placeholder.' '.$pattern.' class="form-control" rows="'.$rows.'" '.$required.' data-autoresize>'.$this->getValue($name).'</textarea>';

        return $this->surround($label.$field);
}

protected function surround($html) {
        return "<div class='form-group'>$html</div>";
}

La vue

<form method="post">
    <?= $form->input("title", "Titre de l'article"); ?>
    <?= $form->input("slug", "URL"); ?>
    <?= $form->select("category_id", "Catégorie", $categories); ?>
    <?= $form->textarea("content", "Contenu"); ?>
    <?= $form->submit(); ?>
</form>

Hum je ne vois pas d'érreur de code la comme ça, peux tu me montrer le HTML généré ?

À mon avis tu dois avoir des espaces en trop ou manquant lors de la génration de l'input, tu devrais plutôt utiliser la fonction implode pour concaténer les attributs du textarea, exemple :



public function textarea($name, $label, $options = []) {

    $attributes = [];
    $attributes[] = 'name="' . $name . '"';
    if (isset($options["pattern"])): $attributes[] = 'pattern="' . $options["pattern"] . '"'; endif;
    if (isset($options["placeholder"])): $attributes[] = 'placeholder="' . $options["placeholder"] . '"'; endif;
    $attributes[] = 'rows="' . (isset($options["rows"]) ? $options["rows"] : 2) . '"';
    $attributes[] = 'class="form-control"';
    $attributes[] = 'data-autoresize';
    if (isset($options["required"])): $attributes[] = 'required'; endif;
    $label = '<label>' . $label . '</label>';
    $field = "<textarea " . implode(' ', $attributes) . ">' . $this->getValue($name) . '</textarea>";

    return $this->surround($label . $field);
}

Mon textarea en lui-même marche très bien, c'est que le code PHP doit venir après le code HTML et CSS et du coup le JavaScript est perdu, enfin je pense
De plus le texte pour le remplir provient de la base de données donc je suppose qu'il y a un petit temps pour qu'il récupère les infos et remplit le textarea

Le code HTML généré pour un article est le suivant :

<textarea name="content" class="form-control" rows="2" data-autoresize="">Mon contenu</textarea>

Hello,

Non car tu ne fait pas d'ajax, le php est executé bien avant tout ça (beh oui, c'est lui qui génère ton code HTML).
Essaye de mettre tout ton code dans un setTimeout

setTimeout(function() {
    $.each($("textarea[data-autoresize]"), function() {
        var offset = this.offsetHeight - this.clientHeight;

        var resizeTextarea = function(e) {
            $(e).css("height", "auto").css("height", e.scrollHeight + offset);
        };

        $(this).on("keydown input", function() { resizeTextarea(this); });

        console.log("Height : " + $(this).height());
        console.log("scrollHeight : " + this.scrollHeight);

        if ($(this).height() < this.scrollHeight + offset) {
            resizeTextarea(this);
        }
    });
}, 0);

Essaye aussi de faire un console.log de $('[data-autoresize]').length

Cela ne marche pas plus
Pour ce qui est du console.log :

console.log("length : " + $("[data-autoresize]").length);

Résultat :

length : 1

Si quelqu'un peut me dire d'où peut venir le problème ?

Je croyais que jQuery(function($) {}); fesait la même chose en isolant jQuery pour éviter les erreurs de variables.
Et tout mes scripts sont en bas de page (avant la fermeture du body)

Après test $("document").ready(function() {}); ne donne rien de plus mais la fonction setTimeout(function() {}, 1000); agrandit bien le textarea à la bonne taille.

Le problème c'est qu'il s'agrandit au bout de 1 s (d'où le 1000ms)

Mon script donne ceci :

$("document").ready(function() {
    jQuery(function($) {

        setTimeout(function() {
            $.each($("textarea[data-autoresize]"), function() {
                var offset = this.offsetHeight - this.clientHeight;

                var resizeTextarea = function(e) {
                    $(e).css("height", "auto").css("height", e.scrollHeight + offset);
                };

                $(this).on("keydown input", function() {
                    resizeTextarea(this);
                });

                if ($(this).height() < this.scrollHeight + offset) {
                    resizeTextarea(this);
                }
            });
        }, 1000);

    });
});

En mettant un délai de 50ms cela marche en local après il faut faire des tests en ligne sur un serveur distant.
Du coup pourquoi il faut un délai supplémentaire ?

Après un test sur un serveur mutualisé mon textarea s'adapte bien au contenu au bout de 50 ms, après la base de données est toute petite mais bon s'il y a une base de données plus conséquentes je pense qu'il faudra augmenter le délai de quelque ms