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.

È stato utile?

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); 
                ...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top