Genéricos roteiro click-to-renomeação em JavaScript (texto para entrada / caixa de texto)

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

Pergunta

Escrevendo um widget para ser capaz de renomear arquivos, clicando sobre o nome do texto e digitar o novo nome. I não encontrou quaisquer soluções ready-to-use, talvez você possa me apontar para um?

Aqui é onde eu acabei e ele não funciona: por alguma razão, apenas a última caixa de entrada está mudando, e o primeiro eo segundo não são 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>

Graças.

Foi útil?

Solução

Este é um problema de ligação ciclo-variável clássico. Consulte esta questão para alguma discussão.

Seu fechamento é ineficaz porque se fecha sobre a cópia do changer em uso dentro do loop, que o loop vai mudar. Para ligá-la, você precisa de outro encerramento, que terá uma cópia da versão atual do 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);

(Você pode preferir abandonar o argumento node e apenas this uso.)

No futuro (ECMAScript Fifth Edition), haverá uma maneira mais rápida e mais eficiente para dizer o seguinte:

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

mas, entretanto, uma vez que a maioria dos navegadores não suportam function.bind ainda, você pode cortar que em assim:

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

Outras dicas

Se você não se importa a dependência jQuery, eu usei jquery-in-place-editor para editar campos antes.

O problema é que, quando as funções de ouvinte adicionado aqui fogo, eles contêm referências à variável "trocador" global. No momento em que disparar o circuito já foi concluída, e assim "trocador" aponta para o último item do loop.

Além disso, a adição de ouvintes pode ser confuso cross-browser, é mais seguro usar uma biblioteca como jQuery ou YUI a fazê-lo. Isso também irá permitir que você passe um objeto para cada ouvinte de evento (de uma forma cross-browser), por isso, por exemplo, você poderia fazer:

for (var i=0; i < 3; i++) {
                var changer = new TextChanger(i);
                YAHOO.util.Event.addListener(changer.textNode, "click", changer.change, changer); 
                ...
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top