Script generico click-to-rename in JavaScript (testo da inserire / casella di testo)
-
06-07-2019 - |
Domanda
Scrivere un widget per poter rinominare i file facendo clic sul nome del testo e inserendo il nuovo nome. Non ho trovato soluzioni pronte per l'uso, forse puoi indicarmene una?
Ecco dove sono finito e non funziona: per qualche motivo, solo l'ultima casella di input sta cambiando e il primo e il secondo non sono referenziati:
<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>
Grazie.
Soluzione
Questo è un classico problema di associazione delle variabili loop. Vedi questa domanda per qualche discussione.
La tua chiusura è inefficace perché si chiude sulla copia di changer
in uso all'interno del loop, che cambierà il loop. Per vincolarlo, è necessaria un'altra chiusura per prendere una copia della versione corrente di 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);
(Potresti preferire abbandonare l'argomento node
e usare this
.)
In futuro (ECMAScript Fifth Edition), ci sarà un modo più rapido ed efficiente per dirlo:
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);
}
ma nel frattempo, poiché la maggior parte dei browser non supporta ancora function.bind
, puoi hackerarlo in questo modo:
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))
);
};
};
}
Altri suggerimenti
Se non ti dispiace della dipendenza jQuery, ho usato jquery-in-place-editor per modificare prima i campi.
Il problema è che quando le funzioni di ascolto aggiunte qui vengono attivate, contengono riferimenti alla variabile globale "cambia". Nel momento in cui sparano il loop è già stato completato, quindi "cambia" " punta all'ultimo elemento del ciclo.
Inoltre, aggiungere listener può essere disordinato su più browser, è più sicuro usare una libreria come jQuery o YUI per farlo. Ciò ti consentirà anche di passare un oggetto a ciascun listener di eventi (in modo cross-browser), quindi ad esempio potresti:
for (var i=0; i < 3; i++) {
var changer = new TextChanger(i);
YAHOO.util.Event.addListener(changer.textNode, "click", changer.change, changer);
...