2009-10-25 4 views
1

Écrire 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, peut-être pourriez-vous m'en désigner une?Script générique de clic-renommer en JavaScript (texte à saisir/zone de texte)

Voici où j'ai fini et il 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.

+0

Il est poli d'accepter une réponse (cliquez sur le chèque) Vous pouvez également voter pour d'autres réponses qui ont été utiles ou qui vous ont appris quelque chose. –

Répondre

1

Ceci est un problème de liaison de boucle variable classique. Voir this question pour une discussion.

Votre fermeture est inefficace car elle se referme sur la copie de changer utilisée dans la boucle, que la boucle va changer. Pour lier, vous avez besoin d'une autre fermeture de prendre une copie de la version actuelle de changer: (. Vous pouvez préférer abandonner l'argument node et il suffit d'utiliser this)

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

Dans l'avenir (ECMAScript cinquième édition), il y aura une plus rapide et plus moyen 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 en attendant, puisque la plupart des navigateurs ne supportent pas encore function.bind, vous pouvez pirater que comme ceci:

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)) 
      ); 
     }; 
    }; 
} 
+0

Ca a du sens, merci beaucoup! –

0

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

+0

Merci - ajouté, fonctionne parfaitement –

0

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

De plus, l'ajout d'écouteurs peut être désordonné pour plusieurs navigateurs, il est plus sûr d'utiliser une bibliothèque comme jQuery ou YUI pour le faire. Cela vous permettra également de passer d'un objet à chaque écouteur d'événement (d'une manière multi-navigateur), par exemple, vous pourriez faire:

for (var i=0; i < 3; i++) { 
       var changer = new TextChanger(i); 
       YAHOO.util.Event.addListener(changer.textNode, "click", changer.change, changer); 
       ... 
+0

merci - maintenant je vois la raison. javascript utilise 'by-ref', pas 'by-value'. –

Questions connexes