Comment détecter «Maj + Entrée» et générer une nouvelle ligne dans Textarea?

145

Actuellement, si la personne appuie enterdans la zone de texte, le formulaire sera soumis.
Bien, je veux ça.

Mais quand ils tapent shift + enter, je veux que la zone de texte passe à la ligne suivante:\n

Comment puis-je faire ça en JQuery ou en JavaScript le plus simple possible?

TIMEX
la source
3
Oh, comme je déteste un tel changement de comportement ... ^^ Pourquoi feriez-vous ça? Si vous écrivez une lettre en mot, vous attendez-vous à ce qu'il enregistre le texte dans un fichier lorsque vous appuyez sur Entrée ou doit-il commencer une nouvelle ligne?
Andreas
18
Je construis une salle de chat. C'est ainsi que Skype doe est assis.
TIMEX
10
Vérifiez e.shiftKey.
Thai
6
Tout ce que vous avez à faire est de trouver le code qui empêche Enter de soumettre le formulaire et de vérifier la shiftKeypropriété de l'événement .
Tim Down
3
Shift ENTER pour une nouvelle ligne dans un champ de texte n'est pas un comportement "modifié". C'est un comportement attendu depuis des années d'âne, pour toutes sortes de choses. Je l'ai utilisé il y a des décennies lors de la saisie de texte dans des feuilles de calcul.
Détente à Chypre

Réponses:

81

Mieux utiliser une solution plus simple:

La solution de Tim ci-dessous est meilleure, je suggère d'utiliser cela: https://stackoverflow.com/a/6015906/4031815


Ma solution

Je pense que vous pouvez faire quelque chose comme ça ...

EDIT: a changé le code pour qu'il fonctionne indépendamment de la position du curseur

La première partie du code consiste à obtenir la position du curseur.

Réf: Comment obtenir la position de la colonne caret (pas des pixels) dans une zone de texte, en caractères, dès le début?

function getCaret(el) { 
    if (el.selectionStart) { 
        return el.selectionStart; 
    } else if (document.selection) { 
        el.focus();
        var r = document.selection.createRange(); 
        if (r == null) { 
            return 0;
        }
        var re = el.createTextRange(), rc = re.duplicate();
        re.moveToBookmark(r.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
    }  
    return 0; 
}

Et puis en remplaçant la valeur textarea en conséquence lorsque Shift+ Enterensemble, soumettez le formulaire si Enterest appuyé seul.

$('textarea').keyup(function (event) {
    if (event.keyCode == 13) {
        var content = this.value;  
        var caret = getCaret(this);          
        if(event.shiftKey){
            this.value = content.substring(0, caret - 1) + "\n" + content.substring(caret, content.length);
            event.stopPropagation();
        } else {
            this.value = content.substring(0, caret - 1) + content.substring(caret, content.length);
            $('form').submit();
        }
    }
});

Voici une démo

Jishnu AP
la source
Cela ne fonctionnera pas si le curseur n'est pas à la fin du contenu de la zone de texte.
Tim Down
En outre, il y a une faute de frappe (vous voulez dire event.keyCode == 13) et je pense que vous vouliez probablement aussi event.preventDefault()plutôt que event.stopPropagation().
Tim Down
Je l'ai changé. Maintenant, cela fonctionnera indépendamment de la position du curseur. Et par event.stopPropagation()je voulais arrêter un autre code qu'il a peut-être écrit pour soumettre le formulaire.
Jishnu AP
7
Cette fonction de position du curseur est imparfaite (voir mon commentaire et ma réponse à la question de la position du curseur liée), et vous n'avez pas besoin de la position du curseur pour le faire de toute façon. Voir ma réponse ici. Re event.stopPropagation(), cela empêchera l'événement de remonter plus haut dans le DOM mais n'empêchera pas la pression de touche de faire son action par défaut d'insérer un saut de ligne (bien qu'en fait, dans keyupma suggestion event.preventDefault(), ne le fera pas non plus).
Tim Down
2
Bien que cela ait fonctionné bien, mais cela a donné une erreur qui carentn'est pas définie, si je le change en caret, cela ajoute 2 nouvelles lignes
Aamir Mahmood
164

Solution simple et élégante:

Tout d'abord, appuyer sur Enterune zone de texte ne soumet pas le formulaire à moins que vous n'ayez un script pour le faire. C'est le comportement attendu par l'utilisateur et je recommande de ne pas le changer. Cependant, si vous devez faire cela, l'approche la plus simple serait de trouver le script qui Entersoumet le formulaire et de le modifier. Le code aura quelque chose comme

if (evt.keyCode == 13) {
    form.submit();
}

... et vous pouvez simplement le changer en

if (evt.keyCode == 13 && !evt.shiftKey) {
    form.submit();
}

D'un autre côté, si vous n'avez pas accès à ce code pour une raison quelconque, vous devez procéder comme suit pour le faire fonctionner dans tous les principaux navigateurs, même si le signe d'insertion n'est pas à la fin du texte:

jsFiddle: http://jsfiddle.net/zd3gA/1/

Code:

function pasteIntoInput(el, text) {
    el.focus();
    if (typeof el.selectionStart == "number"
            && typeof el.selectionEnd == "number") {
        var val = el.value;
        var selStart = el.selectionStart;
        el.value = val.slice(0, selStart) + text + val.slice(el.selectionEnd);
        el.selectionEnd = el.selectionStart = selStart + text.length;
    } else if (typeof document.selection != "undefined") {
        var textRange = document.selection.createRange();
        textRange.text = text;
        textRange.collapse(false);
        textRange.select();
    }
}

function handleEnter(evt) {
    if (evt.keyCode == 13 && evt.shiftKey) {
        if (evt.type == "keypress") {
            pasteIntoInput(this, "\n");
        }
        evt.preventDefault();
    }
}

// Handle both keydown and keypress for Opera, which only allows default
// key action to be suppressed in keypress
$("#your_textarea_id").keydown(handleEnter).keypress(handleEnter);
Tim Down
la source
42

La plupart de ces réponses compliquent trop la situation. Pourquoi ne pas l'essayer de cette façon?

$("textarea").keypress(function(event) {
        if (event.keyCode == 13 && !event.shiftKey) {
         submitForm(); //Submit your form here
         return false;
         }
});

Pas de déranger avec la position du curseur ou de pousser les sauts de ligne dans JS. Fondamentalement, la fonction ne fonctionnera pas si la touche Majuscule est enfoncée, permettant ainsi à la touche Entrée / Retour de remplir sa fonction normale.

Matt Goodwin
la source
C'est exactement ce que je voulais. Merci.
Taku Yoshi le
18

Pourquoi pas juste

$(".commentArea").keypress(function(e) {
    var textVal = $(this).val();
    if(e.which == 13 && e.shiftKey) {

    }
    else if (e.which == 13) {
       e.preventDefault(); //Stops enter from creating a new line
       this.form.submit(); //or ajax submit
    }
});
Salle Liam
la source
2
Vous ne pouvez utiliser qu'une seule condition comme (event.keyCode == 13 &&! Event.shiftKey). Juste un conseil: si vous utilisez knockoutjs, vous devez déconcentrer le poing textarea pour mettre à jour la valeur: jQuery (this) .blur ();
Justin
4

Utilisez le plugin jQuery hotkeys et ce code

jQuery(document).bind('keydown', 'shift+enter', 
         function (evt){ 
             $('textarea').val($('#textarea').val() + "\n");// use the right id here
             return true;
         }
);
Thariama
la source
3

Voici une solution AngularJS utilisant ng-keyup si quelqu'un a le même problème avec AngularJS.

ng-keyup="$event.keyCode == 13 && !$event.shiftKey && myFunc()"
Tombery
la source
3

En utilisant ReactJS ES6, voici le moyen le plus simple

shift + enter Nouvelle ligne à n'importe quelle position

enter Bloqué

class App extends React.Component {

 constructor(){
    super();
    this.state = {
      message: 'Enter is blocked'
    }
  }
  onKeyPress = (e) => {
     if (e.keyCode === 13 && e.shiftKey) {
        e.preventDefault();
        let start = e.target.selectionStart,
            end = e.target.selectionEnd;
        this.setState(prevState => ({ message:
            prevState.message.substring(0, start)
            + '\n' +
            prevState.message.substring(end)
        }),()=>{
            this.input.selectionStart = this.input.selectionEnd = start + 1;
        })
    }else if (e.keyCode === 13) { // block enter
      e.preventDefault();
    }
    
  };

  render(){
    return(
      <div>
      New line with shift enter at any position<br />
       <textarea 
       value={this.state.message}
       ref={(input)=> this.input = input}
       onChange={(e)=>this.setState({ message: e.target.value })}
       onKeyDown={this.onKeyPress}/>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id='root'></div>

Shrroy
la source
2

J'ai trouvé ce fil à la recherche d'un moyen de contrôler Shift + n'importe quelle touche. J'ai collé ensemble d'autres solutions pour que cette fonction combinée accomplisse ce dont j'avais besoin. J'espère que cela aide quelqu'un d'autre.

function () {
    return this.each(function () {
    $(this).keydown(function (e) {
        var key = e.charCode || e.keyCode || 0;
        // Shift + anything is not desired
        if (e.shiftKey) {
            return false;
        }
        // allow backspace, tab, delete, enter, arrows, numbers 
        //and keypad numbers ONLY
        // home, end, period, and numpad decimal
        return (
            key == 8 ||
            key == 9 ||
            key == 13 ||
            key == 46 ||
            key == 110 ||
            key == 190 ||
            (key >= 35 && key <= 40) ||
            (key >= 48 && key <= 57) ||
            (key >= 96 && key <= 105));
    });
});
Spencer Sullivan
la source
1

Au cas où quelqu'un se demanderait encore comment faire cela sans jQuery.

HTML

<textarea id="description"></textarea>

Javascript

const textarea = document.getElementById('description');

textarea.addEventListener('keypress', (e) => {
    e.keyCode === 13 && !e.shiftKey && e.preventDefault(); 
})

Vanille JS

var textarea = document.getElementById('description');

textarea.addEventListener('keypress', function(e) {
    if(e.keyCode === 13 && !e.shiftKey) {
      e.preventDefault();
    }
})
Jaco Ahmad
la source
1

J'utilise div en ajoutant contenteditable true au lieu d'utiliser textarea.

L'espoir peut vous aider.

$("#your_textarea").on('keydown', function(e){//textarea keydown events
  if(e.key == "Enter")
  {
    if(e.shiftKey)//jump new line
    {
     // do nothing
    }
    else  // do sth,like send message or else
    {
       e.preventDefault();//cancell the deafult events
    }
  }
})
Hsinhsin Hung
la source
1

Cela fonctionne pour moi!

$("#your_textarea").on('keydown', function(e){
    if(e.keyCode === 13 && !e.shiftKey) 
    {

          $('form').submit();

    }
});
Mȍhǟmmǟd Șamȋm
la source
0

en utilisant la ng-keyupdirective dans angularJS, n'envoyez un message qu'en appuyant sur la Entertouche et Shift+Enterprendra juste une nouvelle ligne.

ng-keyup="($event.keyCode == 13&&!$event.shiftKey) ? sendMessage() : null"
Abdallah Okasha
la source