Script générique "Cliquer pour renommer" en JavaScript (texte à saisir / zone de texte)

StackOverflow https://stackoverflow.com/questions/1619884

Question

Ecrire un widget pour pouvoir renommer des fichiers en cliquant sur le nom du texte et en entrant le nouveau nom. Je n'ai trouvé aucune solution prête à l'emploi, vous pouvez peut-être m'en indiquer une?

Voici où je me suis retrouvé et cela ne fonctionne pas: pour une raison quelconque, seule la dernière zone de saisie est en train de changer, et la première et la seconde ne sont pas référencées:

<span id="text_name_0">Hello, world. Click me please.</span>
<input type="hidden" id="name_changer_0" />
<input type="hidden" id="done_changing_0" value="Done"/>
<br/>
<span id="text_name_1">Hello, world. Click me please.</span>
<input type="hidden" id="name_changer_1" />
<input type="hidden" id="done_changing_1" value="Done"/>
<br/>
<span id="text_name_2">Hello, world. Click me please.</span>
<input type="hidden" id="name_changer_2" />
<input type="hidden" id="done_changing_2" value="Done"/>

<script type="text/javascript">

function TextChanger(id) {
    this.textNode = document.getElementById('text_name_' + id);
    this.textValue = this.textNode.firstChild.nodeValue;
    this.textboxNode = document.getElementById('name_changer_' + id);
    this.doneButton = document.getElementById('done_changing_' + id);
}   

TextChanger.prototype.change = function(node) {
          node.textboxNode.setAttribute('value', node.textValue);
          node.textNode.style.display = 'none';
          node.textboxNode.setAttribute('type','text');
          node.doneButton.setAttribute('type','button');
}   

TextChanger.prototype.changeBack = function(node) {
          node.textNode.firstChild.nodeValue = node.textboxNode.value;
          node.textNode.style.display = 'block';
          node.textboxNode.setAttribute('type', 'hidden');
          node.doneButton.setAttribute('type','hidden');
}

for (var i=0; i < 3; i++) {
        changer = new TextChanger(i);
        changer.textNode.addEventListener("click", function() {
            changer.change(changer);
        }, false);

        changer.doneButton.addEventListener("click", function() {
            changer.changeBack(changer);
        }, false);
}
</script>

Merci.

Était-ce utile?

La solution

Il s'agit d'un problème classique de liaison variable-boucle. Voir cette question pour plus de détails.

Votre fermeture est inefficace car elle se referme sur la copie de changer utilisée dans la boucle, qui sera modifiée. Pour le lier, vous avez besoin d’une autre fermeture pour prendre une copie de la version actuelle de changer :

function changebind(c) {
    return function() {
        c.change(c);
    };
}

for (var i=0; i<3; i++) {
    var changer= new TextChanger(i);
    changer.textNode.addEventListener('click', changebind(changer), false);

(Vous préférerez peut-être abandonner l'argument noeud et utiliser simplement this .)

À l'avenir (ECMAScript Cinquième édition), il y aura un moyen plus rapide et plus efficace de dire ceci:

for (var i=0; i<3; i++) {
    var changer= new TextChanger(i);
    changer.textNode.addEventListener('click', changer.change.bind(changer), false);
    changer.doneButton.addEventListener('click', changer.changeBack.bind(changer), false);
}

mais dans l'intervalle, étant donné que la plupart des navigateurs ne prennent pas encore en charge function.bind , vous pouvez modifier cela de la manière suivante:

if (!Object.bind) {
    Function.prototype.bind= function(owner) {
        var that= this;
        var args= Array.prototype.slice.call(arguments, 1);
        return function() {
            return that.apply(owner,
                args.length===0? arguments : arguments.length===0? args :
                args.concat(Array.prototype.slice.call(arguments, 0))
            );
        };
    };
}

Autres conseils

Si la dépendance de jQuery ne vous dérange pas, j'ai utilisé jquery-in-place-editor pour modifier les champs avant.

Le problème est que, lorsque les fonctions d'écoute ajoutées ici sont activées, elles contiennent des références à la variable globale "changeur". Au moment où ils tirent, la boucle est déjà terminée et le "changeur" pointe sur le dernier élément de la boucle.

De plus, l’ajout d’auditeurs peut s’avérer désordonné, il est donc plus sage d’utiliser une bibliothèque telle que jQuery ou YUI. Cela vous permettra également de transmettre un objet à chaque écouteur d'événement (de manière inter-navigateur), ainsi vous pourriez par exemple:

for (var i=0; i < 3; i++) {
                var changer = new TextChanger(i);
                YAHOO.util.Event.addListener(changer.textNode, "click", changer.change, changer); 
                ...
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top