jQuery W tym wpisie wytłumaczę jak uzupełnić kontrolkę rozwijanej listy przy użyciu jQuery i Ajax. Użyje metody strony ASP.NET (WebMethods) do przekazywania asynchronicznego informacji pomiędzy klientem i serwerem.
Dzięki użyciu rozwiązania WebMethods nie muszę deklarować oddzielnej usługi sieciowej .Co doskonalone zaspokaja specyficzne potrzeby istniejące tylko dla jednej strony ASP.NET.
Na początku utworzyłem pusty projekt web w Visual Studio i za pomocą NuGet szybko pobrałem aktualne skrypty jQuery , które będą mi potrzebne do tego wpisu.
Layout strony zawiera na razie tylko tabelkę oraz dwie rozwijane listy
Są to na razie zwykłe kontrolki HTML, ponieważ użycie kontrolek ASP.NET wiąże pewne inne problemy, które opiszę później. Dla prostoty tego wpisu skoncentrujmy się na razie na wywołaniu tego mechanizmu w samym jQuery.
Rozwijana lista z imionami będzie zależna od wybranej wartości z rozwijanej listy z płciami.
Wybierz swoją ulubioną postać z OnePiece
<table>
<tr>
<th>
Płeć
</th>
<td>
<select id="ddlGender">
</select>
</td>
</tr>
<tr>
<th>
Imie
</th>
<td>
<select id="ddlName">
</select>
</td>
</tr>
</table>
Do przekazywania informacji pomiędzy C# a jQuery będzie nam potrzebna prosta klasa zawierająca wartość oraz tekst, który będzie wyświetlany w rozwijanej liście.
namespace jQueryDropDownList
{
public class DropDownItem
{
public DropDownItem(int value,string display)
{
Value = value;
Display = display;
}
public int Value { get; set; }
public string Display { get; set; }
}
}
Metoda strony [WebMethod] musi być statyczna. Oto metoda zwracające listę płci.
[WebMethod]
public static List<DropDownItem> GetGenders()
{
return new List<DropDownItem>()
{
new DropDownItem(1,"Mężczyzna"),
new DropDownItem(2,"Kobieta")
};
}
.NET serializuję obiekty klasy DropDownItem automatycznie do JSON-a który później będzie odczytany w jQuery. Nazwy wartości zostaną zachowane, czyli aby uzyskać tekst z poziomu jQuery muszę tylko napisać “Display”.
Oczywiście możesz dostosować ten kod do swoich własnych potrzeb. Dla prostoty tego wpisu nie ma tutaj żadnej bazy danych.
Druga metoda prześle listę imion .Jest ona zależna od wcześniej wybranej płci. Do metody zostanie tutaj przekazany ID płci.
[WebMethod]
public static List<DropDownItem> GetNames(int genderID)
{
if (genderID.Equals(1))
{
return new List<DropDownItem>
{
new DropDownItem(1,"Luffy"),
new DropDownItem(2,"Zorro"),
new DropDownItem(3,"Sanji"),
new DropDownItem(4,"Brook"),
new DropDownItem(5,"Usopp"),
new DropDownItem(6,"Franky"),
new DropDownItem(7,"Tony Tony Chopper")
};
}
if (genderID.Equals(2))
{
return new List<DropDownItem>
{
new DropDownItem(8,"Nami"),
new DropDownItem(2,"Robin")
};
}
throw new ApplicationException("Nie właściwe ID płci");
}
Teraz zaczyna się zabawa czas połączyć klocki w jQuery. Najpierw uzupełniamy listę rozwijaną o listę płci, gdy strona zostanie załadowana.
<head runat="server">
<title>Wybierz swoją ulubioną postać z OnePiece </title>
<script src="Scripts/jquery-1.8.0.js" type="text/javascript"></script>
<script type="text/javascript">
$().ready(function () {
$.ajax({
type: "POST",
url: "WebForm1.aspx/GetGenders",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
$("#ddlGender").get(0).options.length = 0;
$("#ddlGender").get(0).options[0] = new Option("Wybierz płeć", "-1");
$.each(msg.d, function (index, item) {
$("#ddlGender").get(0).options[$("#ddlGender").get(0).options.length] = new Option(item.Display, item.Value);
});
},
error: function () {
alert("Błąd wczytania płci");
}
});
});
</script>
</head>
Powyżej znajduję się metoda AJAX-owa jQuery, która wywoła metodę strony GetGenders. Jeśli wywołanie przebiegło z sukcesem wykonają się następujące operację:
Zostanie wyczyszczona obecna lista elementów znajdujących się w liście rozwijanej ddlGender.
$("#ddlGender").get(0).options.length = 0;
Do listy rozwijanej zostaje dodany pierwszy element zachęcający użytkownika do kliknięcia .Ma on wartość “-1”. Ta wartość będzie później sprawdzana przy pobieraniu imion.
$("#ddlGender").get(0).options[0] = new Option("Wybierz płeć", "-1");
Następnie wykonana się pętla, która będzie spacerować po zwróconej przez serwer liście płci . Każdy element z listy zostanie odpowiednio dodany do listy rozwijanej.
JavaScript$.each(msg.d, function (index, item) {
$("#ddlGender").get(0).options[$("#ddlGender").get(0).options.length] = new Option(item.Display, item.Value);
});
Teraz lista płci jest uzupełniona podczas wczytywania strony. Następnie musimy uzupełnić kolejny listę rozwijaną o listę imion, która jest zależna od wyboru płci. Aby to zrobić tworzymy funkcję JavaScript “GetNames”, która akceptuje parametr “genderID”
$().ready(function () {
function GetNames(genderID) {
if (genderID > 0) {
$("#ddlName").get(0).options.length = 0;
$("#ddlName").get(0).options[0] = new Option("Wczytywanie imion", "-1");
$.ajax({
type: "POST",
url: "WebForm1.aspx/GetNames",
data: "{genderID:" + genderID + "}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
$("#ddlName").get(0).options.length = 0;
$("#ddlName").get(0).options[0] = new Option("Wybierz imie", "-1");
$.each(msg.d, function (index, item) {
$("#ddlName").get(0).options[$("#ddlName").get(0).options.length] = new Option(item.Display, item.Value);
});
},
error: function () {
$("#ddlName").get(0).options.length = 0;
alert("Błąd wczytywania imion");
}
});
}
else {
$("#ddlName").get(0).options.length = 0;
}
}
$("#ddlGender").bind("change", function () {
GetNames($(this).val());
});
Najpierw sprawdzamy czy zmienna genderID jest mniejszy od zera .Jeśli tak jest znaczy to ,że element “Wybierz płeć” został zaznaczony. Wtedy czyścimy listę imion.
Jeśli genderID jest większy od zera wtedy czyścimy i dodajemy pierwszy element do listy rozwijanej z imionami. Ten element informuje użytkownika o tym ,że imiona są właśnie pobierane asynchronicznie przez przeglądarkę.
Następnie tak jak w poprzednim przykładzie wywołujemy metodę GetNames używając Ajax-owej funkcji z jQuery. Tym razem jednak przesyłamy parametr do metody. Parametr musi być określony w formacie JSON i musi on mieć taką samą nazwę jak parametr w metodzie po stronie C#.
Jeśli wywołanie przebiegło bez żadnych problemów lista rozwijana zostanie uzupełniona w podobny sposób jak wcześniej.
Na koniec musimy naszą funkcję JavaScript GetNames podpiąć pod listę rozwijaną z płciami i pod jego zdarzeniem “onChange”. Te zdarzenie zajdzie, gdy użytkownik zmieni wartość danej listy rozwijanej.
$("#ddlGender").bind("change", function () {
GetNames($(this).val());
});
Rezultat jest następujący.
Teraz czas na mały komentarz związany z jQuery i ASP.NET.
Problem z kontrolkami ASP.NET
Do kontrolki ASP.NET dodaj właściwości “ClientIDMode” i ustaw ją na static. Dzięki temu ID kontrolek, które widzisz obecnie pisząc stronę w Visua Studio będą identycznych do tych które zostaną ostatecznie wygenerowane przez serwer.
Teraz aby odwołać się do ASP.NET rozwijanych list w jQuery wystarczy zmienić nazwy elementów w kodzie JavaScript z “dllGender” na “dllGenderASNET” oraz “ddlName” na “ddlNameASPNET”.
Wybierz swoją ulubioną postać z OnePiece ASP.NET
<table>
<tr>
<th>
Płeć
</th>
<td>
<asp:DropDownList runat="server" ID="ddlGenderASPNET" ClientIDMode="Static">
</asp:DropDownList>
</td>
</tr>
<tr>
<th>
Imie
</th>
<td>
<asp:DropDownList runat="server" ID="ddlNameASPNET" ClientIDMode="Static">
</asp:DropDownList>
</td>
</tr>
</table>
<asp:Button ID="Button1" runat="server" Text="Button" />
Niestety zmienianie wartości ASP.NET-owych kontrolek po stronie klienta wywołuje pewien wyjątek serwerowy bezpieczeństwa. Oto komunikat o błędzie, który pojawia się po kliknięciu na przycisk.
ASP.NET uznaje to za hakowanie zawartości strony. Trudno mu się dziwić, ponieważ kod klienta jest widoczny w przeglądarce i łatwo go zmodyfikować n.p w FireBug.
Istnieje wiele sposobów rozwiązania tego problemu. Jednak te rozwiązania w żaden sposób nie są wygodne dla programisty. Dlatego poświęcę o tym oddzielny wpis.
Jest to jednak jeden z problemów związany z jQuery,JavaScript i ASP.NET-em.Istnieje jeszcze drugi problem.
Poniższy obrazek pokazuj moją próbę oszukania systemu ASP.NET. Dodałem do kontrolek HTML tag “runat=”server”. W ten sposób mogę odwołać się do nich po stronie serwera.
Teraz postback nie wywołuje wyjątku ,ale wciąż występuje problem numer 2. No tak nie powiedziałem czym jest problem numer 2.
Problem numer dwa polega na tym ,że po stronie serwera wszystkie zmiany wykonane po stronie klienta zostają utracone. Jak widać moje kontrolki HTML nie przechowują żadnej wartość jak i nie mają żadnych elementów.
Ten problem też można rozwiązać ,ale poświęcę o tym oddzielny wpis.
Teraz wiesz, dlaczego domyślnie w ASP.NET istnieje framework ASP.NET AJAX.