¿Diferencia entre RegisterStartupScript y RegisterClientScriptBlock?

139

¿Es la única diferencia entre el RegisterStartupScripty el RegisterClientScriptBlockes que RegisterStartupScript coloca el javascript antes de la </form>etiqueta de cierre de la página y RegisterClientScriptBlock lo coloca justo después de la <form>etiqueta de inicio de la página?

Además, ¿cuándo elegirías uno sobre el otro? Escribí una página de muestra rápida donde tuve un problema y no estoy seguro de la razón exacta de por qué está sucediendo.

Aquí está el marcado aspx:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Label ID="lblDisplayDate" runat="server"
                           Text="Label" /><br />
                <asp:Button ID="btnPostback" runat="server" 
                            Text="Register Startup Script"
                            onclick="btnPostback_Click" /><br />
                <asp:Button ID="btnPostBack2" runat="server" 
                            Text="Register"
                            onclick="btnPostBack2_Click" />
            </div>
        </form>
    </body>
</html>

Aquí está el código detrás:

protected void Page_Load(object sender, EventArgs e)
{
    lblDisplayDate.Text = DateTime.Now.ToString("T");
}

protected void btnPostback_Click(object sender, EventArgs e)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    sb.Append(@"<script language='javascript'>");
    sb.Append(@"var lbl = document.getElementById('lblDisplayDate');");
    sb.Append(@"lbl.style.color='red';");
    sb.Append(@"</script>");

    if(!ClientScript.IsStartupScriptRegistered("JSScript"))
    {
        ClientScript.RegisterStartupScript(this.GetType(),"JSScript",
        sb.ToString());
    }
}

protected void btnPostBack2_Click(object sender, EventArgs e)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    sb.Append(@"<script language='javascript'>");
    sb.Append(@"var lbl = document.getElementById('lblDisplayDate');");
    sb.Append(@"lbl.style.color='red';");
    sb.Append(@"</script>");

    if (!ClientScript.IsClientScriptBlockRegistered("JSScriptBlock"))
    {
        ClientScript.RegisterClientScriptBlock(this.GetType(), "JSScriptBlock",  
        sb.ToString());
    } 
 }

El problema es cuando hago clic en el btnPostBackbotón, hace una devolución de datos y cambia la etiqueta a rojo, pero cuando hago clic en el btnPostBack2, hace una devolución de datos, pero el color de la etiqueta no cambia a rojo. ¿Por qué es esto? ¿Es porque la etiqueta no está inicializada?

También leí que si está usando un UpdatePanel, debe usarlo ScriptManager.RegisterStartupScript, pero si tengo un MasterPage, ¿lo usaría ScriptManagerProxy?

Xaisoft
fuente

Respuestas:

162

Aquí hay un viejo hilo de discusión donde enumeré las principales diferencias y las condiciones en las que debe usar cada uno de estos métodos. Creo que puede resultarle útil analizar la discusión.

Para explicar las diferencias como relevantes para su ejemplo publicado:

a. Cuando lo use RegisterStartupScript, representará su secuencia de comandos después de todos los elementos de la página (justo antes de la etiqueta final del formulario). Esto permite que el script llame o haga referencia a elementos de la página sin la posibilidad de que no los encuentre en el DOM de la página.

Aquí está la fuente representada de la página cuando invocas el RegisterStartupScriptmétodo:

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1"><title></title></head>
<body>
    <form name="form1" method="post" action="StartupScript.aspx" id="form1">
        <div>
            <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="someViewstategibberish" />
        </div>
        <div> <span id="lblDisplayDate">Label</span>
            <br />
            <input type="submit" name="btnPostback" value="Register Startup Script" id="btnPostback" />
            <br />
            <input type="submit" name="btnPostBack2" value="Register" id="btnPostBack2" />
        </div>
        <div>
            <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="someViewstategibberish" />
        </div>
        <!-- Note this part -->
        <script language='javascript'>
            var lbl = document.getElementById('lblDisplayDate');
            lbl.style.color = 'red';
        </script>
    </form>
    <!-- Note this part -->
</body>
</html>

si. Cuando lo usa RegisterClientScriptBlock, el script se representa justo después de la etiqueta Viewstate, pero antes de cualquiera de los elementos de la página. Como se trata de una secuencia de comandos directa (no una función que se puede invocar , el navegador la ejecutará de inmediato. Pero en esta etapa, el navegador no encuentra la etiqueta en el DOM de la página y, por lo tanto, debería recibir un "Objeto no encontrado" error.

Aquí está la fuente representada de la página cuando invocas el RegisterClientScriptBlockmétodo:

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1"><title></title></head>
<body>
    <form name="form1" method="post" action="StartupScript.aspx" id="form1">
        <div>
            <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="someViewstategibberish" />
        </div>
        <script language='javascript'>
            var lbl = document.getElementById('lblDisplayDate');
            // Error is thrown in the next line because lbl is null.
            lbl.style.color = 'green';

Por lo tanto, para resumir, debe llamar al último método si tiene la intención de representar una definición de función. Luego puede procesar la llamada a esa función utilizando el método anterior (o agregar un atributo del lado del cliente).

Editar después de los comentarios:


Por ejemplo, la siguiente función funcionaría:

protected void btnPostBack2_Click(object sender, EventArgs e) 
{ 
  System.Text.StringBuilder sb = new System.Text.StringBuilder(); 
  sb.Append("<script language='javascript'>function ChangeColor() {"); 
  sb.Append("var lbl = document.getElementById('lblDisplayDate');"); 
  sb.Append("lbl.style.color='green';"); 
  sb.Append("}</script>"); 

  //Render the function definition. 
  if (!ClientScript.IsClientScriptBlockRegistered("JSScriptBlock")) 
  {
    ClientScript.RegisterClientScriptBlock(this.GetType(), "JSScriptBlock", sb.ToString()); 
  }

  //Render the function invocation. 
  string funcCall = "<script language='javascript'>ChangeColor();</script>"; 

  if (!ClientScript.IsStartupScriptRegistered("JSScript"))
  { 
    ClientScript.RegisterStartupScript(this.GetType(), "JSScript", funcCall); 
  } 
} 
Cerebro
fuente
1
¿Puedes explicar un poco más sobre las funciones en línea?
Xaisoft
2
Editando mi publicación para ilustrarla mejor con su ejemplo.
Cerebrus
1
En realidad no recibo un error, el tiempo se actualiza, pero el color no cambia. ¿Qué pasa con la parte de mi pregunta donde pregunto si tengo que usar ScriptManagerProxy si ya tengo un ScriptManager definido en una página maestra?
Xaisoft
1
Edición realizada. No estoy seguro sobre el error con el ScriptManagerProxy. Creo que deberías evaluar si esa no es realmente una pregunta separada. ;-)
Cerebrus
1
¡Excelente! Gracias hasta ahora No recibo un error con ScriptManagerProxy. Solo sé que solo puede declarar una instancia de ScriptManager, por lo que si ya tengo un ScriptManager definido en una página maestra, por ejemplo, asumiría que usaría ScriptManagerProxy en su lugar.
Xaisoft
6

Aquí hay un ejemplo más simple de la comunidad ASP.NET, esto me dio una comprensión clara del concepto ...

¿Qué diferencia hace esto?

Para un ejemplo de esto, aquí hay una manera de enfocar un cuadro de texto en una página cuando la página se carga en el navegador, con Visual Basic utilizando el RegisterStartupScriptmétodo:

Page.ClientScript.RegisterStartupScript(Me.GetType(), "Testing", _ 
"document.forms[0]['TextBox1'].focus();", True)

Esto funciona bien porque el cuadro de texto en la página se genera y se coloca en la página cuando el navegador llega al final de la página y llega a este pequeño fragmento de JavaScript.

Pero, si en cambio se escribió así (usando el RegisterClientScriptBlockmétodo):

Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "Testing", _
"document.forms[0]['TextBox1'].focus();", True)

El foco no llegará al control del cuadro de texto y se generará un error de JavaScript en la página

La razón de esto es que el navegador encontrará el JavaScript antes de que el cuadro de texto esté en la página. Por lo tanto, el JavaScript no podrá encontrar un TextBox1.

usuario c-sharp
fuente