lunes, 26 de abril de 2010

__doPostBack

ASP.Net 2.0. Me imagino que se habrán dado cuenta de que en las páginas de asp.net se implementa un curioso metodo llamado __doPostBack, de hecho nosotros lo podemos utilizar dentro de las funciones del lado del cliente de los controles de .Net como por ejemplo en el OnClientClick de un botón. Pero ¿que es lo que hace? y ¿cómo lo hace?

Básicamente realiza un submit de la página, ó sea, dispara el postback, como claramente indica su nombre. El método recibe dos parámetros: __EVENTTARGET y __EVENTARGUMENT El primero de los cuales recibe el nombre del control que dispara el postback y el segundo el método de dicho control.

Ahora, ¿cómo hace esta función para hacer el postback? El código que se genera automáticamente es mas o menos este:

< input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" / >
< input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" / >

function __doPostBack(eventTarget, eventArgument) 
{
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) 
    {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
Como se puede ver, son simplemente dos textbox ocultos y una función que los utiliza para el disparar el submit. Como lo dije antes, este código es generado automáticamente siempre y cuando haya al menos un control en la página que tenga al atributo “AutoPostBack” en True. Si lo queremos es usar la funcion sin que haya controles con el AutoPostBack en True, pues manualmente ponemos el código anterior en la página y listo.

Ahora bien, nosotros podemos hacen uso del método con los parámetros vacíos __doPostBack("",""); Esto dispara el submit y se hubiera algún método del lado del servidor que no se hayan ejecutado (por tener el AutoPostBack en False, por ejemplo) entonces ahora también se dispararán. Este método se usa en los treeview que no disponen de método de postback, cuando se utilizan con checkboxes, para que cuando hagan click en alguno de ellos se ejecute el método postback correspondiente.

Pero hay algo más. La realización de un simple Submit con controles ocultos significa que podemos capturar los valores de los parámetros(valores del los controles ocultos) del lado del servidor y por ende, ejecutar lo que nos parezca más conveniente en determinadas circunstancias. Así por ejemplo podemos hacer una función javascript como esta:
function MiPostBack ()
 {
     var o = window.event.srcElement;
     if ( o.tagName == "INPUT" && o.type == "checkbox")
     {                   
          __doPostBack("MiControl","MiEvento");
      } 
} 
La cual la podemos usar en el OnClick de un treeview para indicar de que si hace clic sobre un checkbox del treeview haga submit con estos parámetros. Y en el método Page_Load del lado del servidor tener algo similar a esto
string controlName = Request.Params.Get("__EVENTTARGET");
string controlEvent = Request.Params.Get("__EVENTARGUMENT");
if ((controlName=="MiControl")&&(controlEvent=="MiEvento"))
{
   UnMetodoCualquiera();
}
Así podemos ejecutar UnMetodoCualquiera(); cuando se produce un clic en alguno de los checkboxes del treeview (esto se realizó asi en un proyecto real para evitar que cuando se marcaba un checkbox padre se dispara el postback por cada hijo que también se marcaba automáticamente). Para mi esto abre más de una posibilidad para usar el __doPostBack cuando requiere ejecutar código del servidor.

2 comentarios:

Migda dijo...

Hola, gracias por el aporte, pero estoy haciendo lo que dices y no me funciona en el treeview. Tengo un treeview con checkboxes (propiedad ShowCheckBoxes=true) y puse el codigo javascript, siguiendo tu ejemplo y me quedó asi:
function MiPostBack() {
var o = window.event.srcElement;
if (o.tagName == "INPUT" && o.type == "checkbox") {
__doPostBack("AreasTree", "OnClick");
}
}
Y tambien puse el codigo como dices en el load de la pagina y me quedó asi:
string controlName = Request.Params.Get("__EVENTTARGET");
string controlEvent = Request.Params.Get("__EVENTARGUMENT");
if ((controlName == "AreasTree") && (controlEvent == "OnClick"))
{
RefreshBrands();
}

Pero no funciona, ni siquiera se hace el postback cuando doy click en el checkbox del treeview. Cual puede ser el problema? muchas gracias de antemano

Roy Barrantes dijo...

Adicional a lo que indica el post, en mi código javascript tengo lo siguiente:

function OnTreeClick(evt)
{
var src = window.event != window.undefined ? window.event.srcElement : evt.target;
var isChkBoxClick = (src.tagName.toLowerCase() == "input" && src.type == "checkbox");

if(isChkBoxClick)
{
var parentTable = GetParentByTagName("table", src);
var nxtSibling = parentTable.nextSibling;
if(nxtSibling != null && nxtSibling.nodeType == 1)//Verificar su el siguiente hermano es not null y si es un nodo
{
if(nxtSibling.tagName.toLowerCase() == "div") //si el nodo tiene hijos
{
//Chekear o deschekear todo los hijos
CheckUncheckChildren(parentTable.nextSibling, src.checked);
}
}
//Chekear o deschekear los padres
CheckUncheckParents(src, src.checked);
}
postBackByObject(); //Postback proviamente
}

Esa función maneja el evento clic en el treeview que esta el mismo indicado así:

OnClick="javascript:OnTreeClick(event);"

Las Funciones utilitarias indicadas en OnTreeClick son las siguientes:


function CheckUncheckParents(srcChild, check)
{
var parentDiv = GetParentByTagName("div", srcChild);
var parentNodeTable = parentDiv.previousSibling;
if(parentNodeTable)
{
var checkUncheckSwitch;
if(check) //si esta checkeado
{
var isAllSiblingsChecked = AreAllSiblingsChecked(srcChild);
if(isAllSiblingsChecked)
checkUncheckSwitch = true;
else
return; //No se necesita verificar si los hijos no estan chekeados
}
else //Si no esta cheakeado
{
checkUncheckSwitch = false;
}

var inpElemsInParentTable = parentNodeTable.getElementsByTagName("input");
if(inpElemsInParentTable.length > 0)
{
var parentNodeChkBox = inpElemsInParentTable[0];
parentNodeChkBox.checked = checkUncheckSwitch;
//Recuersivo
CheckUncheckParents(parentNodeChkBox, checkUncheckSwitch);
}
}
}

function AreAllSiblingsChecked(chkBox)
{
var parentDiv = GetParentByTagName("div", chkBox);
var childCount = parentDiv.childNodes.length;

for(var i=0; i<childCount; i++)
{
if(parentDiv.childNodes[i].nodeType == 1) //Verificar si el hijo es tipo nodo
{
if(parentDiv.childNodes[i].tagName.toLowerCase() =="table")
{
var prevChkBox = parentDiv.childNodes[i].getElementsByTagName("input")[0];
//Si algun hermano no esta chekaeado return false
if(!prevChkBox.checked)
{
return false;
}
}
}
}

return true;
}
//funcion que devuelve un contenedor de elementos por tagname
function GetParentByTagName(parentTagName, childElementObj)
{
var parent = childElementObj.parentNode;
while(parent.tagName.toLowerCase() != parentTagName.toLowerCase())
{
parent = parent.parentNode;
}
return parent;
}

Ojala te haya podido ayudar.