Je souhaite exécuter une fonction lorsqu'un utilisateur modifie le contenu d'un attribut div
avec contenteditable
. Quel est l'équivalent d'un événement onchange
?
J'utilise jQuery, donc toutes les solutions utilisant jQuery sont préférées. Merci!
Je suggérerais d'attacher des écouteurs aux événements clés déclenchés par l'élément éditable, bien que vous sachiez bien que les événements keydown
et keypress
sont déclenchés avant que le contenu lui-même ne soit modifié. Cela ne couvrira pas tous les moyens possibles de changer le contenu: l'utilisateur peut également utiliser couper, copier et coller à partir des menus de modification ou du navigateur contextuel, de sorte que vous souhaiterez peut-être également gérer les événements cut
copy
et paste
. En outre, l'utilisateur peut supprimer du texte ou un autre contenu, de sorte qu'il y ait plus d'événements à cet endroit (mouseup
, par exemple). Vous souhaiterez peut-être interroger le contenu de l'élément comme solution de secours.
UPDATE 29 octobre 2014
L'événement HTML5 input
est la réponse à long terme. Au moment de la rédaction de ce document, il est pris en charge pour les éléments contenteditable
des navigateurs Mozilla (à partir de Firefox 14) et WebKit/Blink actuels, mais pas pour IE.
Démo:
document.getElementById("editor").addEventListener("input", function() {
console.log("input event fired");
}, false);
<div contenteditable="true" id="editor">Please type something in here</div>
Voici une version plus efficace qui utilise on
pour tous les contenteditables. C'est basé sur les meilleures réponses ici.
$('body').on('focus', '[contenteditable]', function() {
const $this = $(this);
$this.data('before', $this.html());
}).on('blur keyup paste input', '[contenteditable]', function() {
const $this = $(this);
if ($this.data('before') !== $this.html()) {
$this.data('before', $this.html());
$this.trigger('change');
}
});
Le projet est ici: https://github.com/balupton/html5edit
Pensez à utiliser MutationObserver . Ces observateurs sont conçus pour réagir aux modifications apportées au DOM et constituer un remplacement performant de événements de mutation .
Avantages:
Les inconvénients:
Apprendre encore plus:
non jQuery rapide et sale réponse:
function setChangeListener (div, listener) {
div.addEventListener("blur", listener);
div.addEventListener("keyup", listener);
div.addEventListener("paste", listener);
div.addEventListener("copy", listener);
div.addEventListener("cut", listener);
div.addEventListener("delete", listener);
div.addEventListener("mouseup", listener);
}
var div = document.querySelector("someDiv");
setChangeListener(div, function(event){
console.log(event);
});
J'ai modifié la réponse de lawwantsin comme suit et cela fonctionne pour moi. J'utilise l'événement keyup au lieu de la frappe qui fonctionne très bien.
$('#editor').on('focus', function() {
before = $(this).html();
}).on('blur keyup paste', function() {
if (before != $(this).html()) { $(this).trigger('change'); }
});
$('#editor').on('change', function() {alert('changed')});
Ce fil de discussion m'a été très utile lors de mes recherches sur le sujet.
J'ai modifié une partie du code disponible ici dans un plugin jQuery afin qu'il soit réutilisé, principalement pour répondre à mes besoins, mais d'autres peuvent apprécier une interface plus simple pour démarrer avec des balises contenteditable.
https://Gist.github.com/3410122
En raison de sa popularité croissante, le plugin a été adopté par Makesites.org
Le développement continuera d'ici:
Voici ce qui a fonctionné pour moi:
var clicked = {}
$("[contenteditable='true']").each(function(){
var id = $(this).attr("id");
$(this).bind('focus', function() {
// store the original value of element first time it gets focus
if(!(id in clicked)){
clicked[id] = $(this).html()
}
});
});
// then once the user clicks on save
$("#save").click(function(){
for(var id in clicked){
var original = clicked[id];
var current = $("#"+id).html();
// check if value changed
if(original != current) save(id,current);
}
});
Deux options:
1) Pour les navigateurs modernes (à feuilles persistantes): L'événement "input" agirait comme un événement "change" alternatif.
https://developer.mozilla.org/en-US/docs/Web/Events/input
document.querySelector('div').addEventListener('input', (e) => {
// Do something with the "change"-like event
});
ou
<div oninput="someFunc(event)"></div>
ou (avec jQuery)
$('div').on('click', function(e) {
// Do something with the "change"-like event
});
2) Pour tenir compte des navigateurs IE11 et modernes (à feuilles persistantes): Ceci surveille les changements d'éléments et leur contenu à l'intérieur du div.
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
var div = document.querySelector('div');
var divMO = new window.MutationObserver(function(e) {
// Do something on change
});
divMO.observe(div, { childList: true, subtree: true, characterData: true });
Voici la solution que j'ai finalement utilisée et qui fonctionne à merveille. J'utilise plutôt $ (this) .text () parce que j'utilise simplement un div d'une ligne dont le contenu est éditable. Mais vous pouvez également utiliser .html () de cette façon, vous n'avez pas à vous soucier de la portée d'une variable globale/non globale et l'avant est en fait attaché à l'éditeur div.
$('body').delegate('#editor', 'focus', function(){
$(this).data('before', $(this).html());
});
$('#client_tasks').delegate('.task_text', 'blur', function(){
if($(this).data('before') != $(this).html()){
/* do your stuff here - like ajax save */
alert('I promise, I have changed!');
}
});
const p = document.querySelector('p')
const result = document.querySelector('div')
const observer = new MutationObserver((mutationRecords) => {
result.textContent = mutationRecords[0].target.data
// result.textContent = p.textContent
})
observer.observe(p, {
characterData: true,
subtree: true,
})
<p contenteditable>abc</p>
<div />
Pour éviter les temporisations et les boutons "Enregistrer", vous pouvez utiliser un événement de flou qui se déclenche lorsque l'élément perd le focus. mais pour être sûr que l'élément a réellement été modifié (pas seulement focalisé et défocalisé), son contenu doit être comparé à sa dernière version. ou utilisez l'événement keydown pour définir un indicateur "sale" sur cet élément.
L'utilisation de DOMCharacterDataModified sous MutationEvents conduira à la même chose. La temporisation est configurée pour empêcher l'envoi de valeurs incorrectes (par exemple, dans Chrome, je rencontrais des problèmes avec la touche espace).
var timeoutID;
$('[contenteditable]').bind('DOMCharacterDataModified', function() {
clearTimeout(timeoutID);
$that = $(this);
timeoutID = setTimeout(function() {
$that.trigger('change')
}, 50)
});
$('[contentEditable]').bind('change', function() {
console.log($(this).text());
})
Une réponse simple dans JQuery, je viens de créer ce code et j'ai pensé qu'il serait utile pour les autres aussi
var cont;
$("div [contenteditable=true]").focus(function() {
cont=$(this).html();
});
$("div [contenteditable=true]").blur(function() {
if ($(this).html()!=cont) {
//Here you can write the code to run when the content change
}
});
Réponse non JQuery ...
function makeEditable(elem){
elem.setAttribute('contenteditable', 'true');
elem.addEventListener('blur', function (evt) {
elem.removeAttribute('contenteditable');
elem.removeEventListener('blur', evt.target);
});
elem.focus();
}
Pour l'utiliser, appelez (par exemple) un élément d'en-tête avec id = "myHeader"
makeEditable(document.getElementById('myHeader'))
Cet élément sera désormais modifiable par l'utilisateur jusqu'à ce qu'il perde le focus.
J'ai construit un plugin jQuery pour le faire.
(function ($) {
$.fn.wysiwygEvt = function () {
return this.each(function () {
var $this = $(this);
var htmlold = $this.html();
$this.bind('blur keyup paste copy cut mouseup', function () {
var htmlnew = $this.html();
if (htmlold !== htmlnew) {
$this.trigger('change')
}
})
})
}
})(jQuery);
Vous pouvez simplement appeler $('.wysiwyg').wysiwygEvt();
Vous pouvez également supprimer/ajouter des événements si vous le souhaitez
L'événement onchange ne se déclenche pas lorsqu'un élément doté de l'attribut contentEditable est modifié. Une approche suggérée pourrait être d'ajouter un bouton à l'édition "save".
Vérifiez ce plugin qui gère le problème de cette façon: