Miłosz Orzeł

.net, js, html, arduino, java... no rants or clickbaits.

Kod skryptu aktualizowany w UpdatePanelu

Załóżmy, że z jakiegoś powodu musisz umieścić w obszarze kontrolki UpdatePanel funkcję JavaScript, której kod będzie się zmieniał przy każdej aktualizacji panelu. Funkcja ta ma być wywoływana w odpowiedzi na zdarzenie onclick jakiegoś elementu, który znajduję się poza UpdatePanelem...

Pierwsza rzecz, która przychodzi na myśl to umieszczenie skryptu w kontrolce Literal znajdującej się w aktualizowanym fragmencie strony:

protected void Button1_Click(object  sender, EventArgs e)
{
   string s = "<script type='text/javascript'> function " +
      "test() { alert('" + DateTime.Now + "') };</script>";

   Literal1.Text = s;
}

Niestety, przy próbie wywołania funkcji test() pojawi się błąd (przeglądarka jej nie znajdzie). Dzieje się tak dlatego, że aktualizacja UpdatePanelu to tak naprawdę podmiana właściwości innerHTML warstwy (div), która reprezentuje ten panel po stronie klienta. Wnętrze tej warstwy będzie zawierać fragment skryptu jednak przeglądarka nie będzie sobie zdawać sprawy z jego obecności.

Oto fragment przechwyconej za pomocą narzędzia Fiddler, odpowiedzi serwera na postback pochodzący z UpdatePanelu:

HTTP/1.1 200 OK
Server: ASP.NET Development Server/9.0.0.0
Date: Mon, 29 Sep 2008 13:28:26 GMT
X-AspNet-Version: 2.0.50727
Transfer-Encoding: chunked
Cache-Control: private
Content-Type: text/plain; charset=utf-8
Connection: Close

10c
238|updatePanel|UpdatePanel1|
<input type="submit" name="Button1" value="upa1" id="Button1" />

<script type='text/javascript'> function test() { alert('2008-09-29 15:28:26') };</script> | 22a 216|hiddenField|__VIEWSTATE|/wEP...

Widać wyraźnie, że treść skryptu została wysłana do klienta...

Co zrobić by wywołanie funkcji test(), która pojawiła się po aktualizacji UpdatePanelu, zadziałało prawidłowo? Zamiast dosłownie wpisywać treść skryptu w aktualizowany obszar skorzystaj z metody ScriptManager.RegisterStartupScript:

protected void Button1_Click(object  sender, EventArgs e)
{
   string s = "<script type='text/javascript'> function " +
      "test() { alert('" + DateTime.Now + "') };</script>";

   ScriptManager.RegisterStartupScript(this, typeof(Page),
      "abc", s, false);
}

Tym razem wywołanie metody test() zakończy się powodzeniem (użytkownik zobaczy alert z datą ustawianą w chwili aktualizacji panelu).

O znaczeniu poszczególnych parametrów metody ScriptManager.RegisterStartupScript możesz poczytać tutaj.

Treść komunikatu o błędzie podczas asynchronicznego postbacka

Gdy kontrolka znajdująca się w UpdatePanelu wykonuje asynchroniczny postback skutkujący błędem po stronie serwera, użytkownik zostaje poinformowany o problemie przez komunikat JavaScript. Treść tego komunikatu jest taka sama jak właściwość Message wyjątku. Alert ukaże się jedynie wtedy, gdy witryna nie korzysta z przekierowania w przypadku błędu lub, gdy właściwość AllowCustomErrorsRedirect kontrolki ScriptManager jest ustawiona na false.

Co jeśli chciałbyś zmienić treść wiadomości wyświetlanej użytkownikowi?
Można to zrobić na dwa sposoby. Pierwszy to ustawienie odpowiedniego tekstu w propercie AsyncPostBackErrorMessage kontrolki ScriptManager. Drugi to obsługa zdarzenia AsyncPostBackError tejże kontrolki.

Druga technika daje większe możliwości, ponieważ pozwala na dostosowanie treści komunikatu do typu wyjątku. Dobrym pomysłem jest umieszczenie ogólnej informacji o błędzie we właściwości AsyncPostBackErrorMessage i modyfikowanie jej w razie potrzeby w zdarzeniu AsyncPostBackError.

Tak wygląda deklaracja ScriptManagera wyświetlającego domyślmy komunikat błędu o treści "Mamy problem!":

<asp:ScriptManager  ID="ScriptManager1" runat="server"
 AsyncPostBackErrorMessage="Mamy problem!"
 OnAsyncPostBackError="ScriptManager1_AsyncPostBackError" />

A oto przykładowy kod modyfikujący komunikat wyświetlany w alercie, jeśli błąd powstał na skutek operacji dzielenia przez zero:

protected void ScriptManager1_AsyncPostBackError(object sender,
    AsyncPostBackErrorEventArgs e)
{
    if (e.Exception is DivideByZeroException)
    {
        ScriptManager1.AsyncPostBackErrorMessage = "Nie można dzielić przez zero!";
    }
}

Zdradliwa parseInt()

Dzięki funkcji parseInt() języka JavaScript w łatwy sposób można dokonać konwersji łańcucha tekstowego na liczbę całkowitą. Niestety korzystanie z niej w celu pobrania wartości wpisanej przez użytkownika niesie za sobą pewne zagrożenie. Przeanalizuj poniższy fragment kodu:

function dodaj() {
    var txt = document.getElementById('TextBox1');
    var a = parseInt(txt.value);
    return a + 10;
}

Co stanie się gdy użytkownik wprowadzi do okienka 10? Oczywiście funkcja zwróci wartość 20. Co jednak wydarzy się gdy ktoś wpisze do okienka ciąg 010? Otóż w rezultacie otrzymamy 18! Stało się tak dlatego, że funkcja parseInt() wywoływana tylko z jednym parametrem zinterpretowała tekst wpisany przez usera aplikacji jako wartość podaną w systemie ósemkowym (napis postaci 0x10 został by odczytany jako szesnastkowy). Możesz być niemal pewien, iż użytkownik programu zakładał, że wprowadzenie zera przed liczbę nie powinno mieć wpływu na wynik. A jednak ma! Co zrobić by program działał bardziej intuicyjnie? Wystarczy dodać w wywołaniu funkcji parseInt() drugi parametr określający podstawę wykorzystywanego systemu liczbowego. Należy więc zastosować taki kod:

function dodaj2() {
    var txt = document.getElementById('TextBox1');
    var a = parseInt(txt.value, 10);
    return a + 10;
}