sexta-feira, 13 de fevereiro de 2009

Chamando o callback do callback no jquery.

Me deparei com um problema ao precisar chamar o callback de vários nós de uma arvore para abrir um de cada vez no jquery. Ou seja, tem que abrir a raiz e passar o callback para abrir o filho, só que no callback de abrir o filho (callback do callback) chamar o callback de abrir o neto e assim por diante até onde for necessário.

Depois de fritar os miolos um poucos, resolvi da seguinte maneira:
Na "classe" TaskTreeC coloquei um método que inicializa algumas variáveis no escopo dela mesma e também define um lock:

  
this.openParents = function(id,callback) {
// para não dar conflito sendo chamada antes de terminar uma operação em andamento.
if(TaskTreeC.locked) return;
TaskTreeC.locked = true;
stack = [];
TaskTreeC.getParentStack(id,stack);
TaskTreeC.stack = stack;
TaskTreeC.recursiveIndex = 0;
TaskTreeC.openStackCallback = function() {
TaskTreeC.locked = false;
if(callback) callback();
}
TaskTreeC.openStack();
}


Primeiramente a função recebe um id de um item interno na arvore e chama getParentStack para poder pegar um array com os ids de todos os pais daquele item. Então armazena isso, cria um índice e um callback final que será chamado depois de todo o processo. Então ela chama o método openStack que faz o "serviço sujo".

No meu caso eu não preciso mostrar os elementos percorridos, mas sim abrir os filhos de cada um deles. Assim o método openStack ficou da seguinte maneira:


this.openStack = function() {
if(TaskTreeC.recursiveIndex < TaskTreeC.stack.length) {
id = TaskTreeC.stack[TaskTreeC.recursiveIndex];
TaskTreeC.recursiveIndex++;
if(TaskTreeC.getChildren(id).length) {
// pega o div que tem os filhos...
node = $('#node-content-'+id);
if(node.is(':visible')) {
// se já estiver aberto, segue em frente sem fazer nada.
TaskTreeC.openStack();
}
else {
// mostra com um tempo para o browser renderizar
var t=setTimeout(
"TaskTreeC.removeHiddenCache(id);"+
"node.show('blind',{},500,TaskTreeC.openStack);"+
"TaskTreeC.closeChildren(id);", // fecha os "netos"
200
);
}
}
else {
// chama o callback final
if(TaskTreeC.openStackCallback) {
var t=setTimeout("TaskTreeC.openStackCallback();",300);
}
}
}
else {
// chama o callback final
if(TaskTreeC.openStackCallback) {
var t=setTimeout("TaskTreeC.openStackCallback();",300);
}
}
}



Outros métodos usados:



this.getParentStack = function(id,stack) {
node = $('#node-'+id);
parentId = UtilC.getAttrUpTheTree( node.parent() , 'taskId' );
if(parentId) {
TaskTreeC.getParentStack(parentId,stack);
}
stack[stack.length] = id;
}

//UtilC
this.getAttrUpTheTree = function(item,attrName) {
//attrib = $(item).attr(attrName);
if(
$(item).attr(attrName) != undefined &&
( typeof $(item).attr(attrName) === 'string' )
) {
return $(item).attr(attrName);
}
else {
parentNode = $(item).parent()[0];
if(parentNode != undefined) {
return RouterC.getAttrUpTheTree($(item).parent()[0],attrName);
}
else return null;
}
}


OBS: acho que este código pode ser melhorado utilizando um module pattern, dê uma olhada no outro post.

Nenhum comentário:

Postar um comentário