Script genérico de clic para cambiar de nombre en JavaScript (texto para ingresar / cuadro de texto)

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

Pregunta

Escribiendo un widget para poder renombrar archivos haciendo clic en el nombre del texto e ingresando el nuevo nombre. No encontré ninguna solución lista para usar, tal vez me pueda indicar una.

Aquí es donde terminé y no funciona: por alguna razón, solo el último cuadro de entrada está cambiando, y el primero y el segundo no están referenciados:

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

Gracias.

¿Fue útil?

Solución

Este es un problema clásico de vinculación de bucle-variable. Consulte esta pregunta para obtener más información.

Su cierre no es efectivo porque se cierra sobre la copia del changer en uso dentro del bucle, que cambiará el bucle. Para enlazarlo, necesita otro cierre para obtener una copia de la versión actual 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);

(Es posible que prefiera deshacerse del argumento node y simplemente use this .)

En el futuro (ECMAScript Quinta edición), habrá una manera más rápida y eficiente de decir esto:

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

pero mientras tanto, dado que la mayoría de los navegadores no admiten function.bind , puedes hackear eso de esta manera:

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

Otros consejos

Si no te importa la dependencia de jQuery, he usado jquery-in-place-editor para editar campos antes.

El problema es que cuando las funciones de escucha agregadas aquí se activan, contienen referencias a la variable global " changer " En el momento en que se disparan, el bucle ya se ha completado, por lo que " changer " apunta al último elemento del bucle.

Además, agregar oyentes puede ser un navegador cruzado desordenado, es más seguro usar una biblioteca como jQuery o YUI para hacerlo. Esto también le permitirá pasar un objeto a cada detector de eventos (en forma de navegador cruzado), por lo que, por ejemplo, podría hacerlo:

for (var i=0; i < 3; i++) {
                var changer = new TextChanger(i);
                YAHOO.util.Event.addListener(changer.textNode, "click", changer.change, changer); 
                ...
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top