Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: AJAX: dwa zalezne do siebie selecty - zauwazylem problem
Forum PHP.pl > Forum > XML, AJAX
luckyluc
Cytat(TomASS @ 2.03.2006, 08:21:24 ) *
Witam ponownie wszystkich forumowiczów guitar.gif

Postanowiłem opisać jeszcze jeden przykład na wykorzystanie AJAXa oraz na rozwiązanie popularnego problemu od czasu do czasu poruszanego na tym forum.

Chodzi tutaj o dwa selecty <span style="font-style: italic;">"sprzężone"</span> ze sobą w ten sposób, że wybór odpowiedniej pozycji na <span style="font-weight: bold;">selekcie1</span> wpływa na zawartość <span style="font-weight: bold;">selecta2</span> - np. mamy wybrać ze spisu jedną wieś w Polsce. Przeszukując selectem cały spis wszystkich miejscowości moglibyśmy się zaszukać na śmierć tongue.gif . Wygodniej byłoby wybierać po kolei: Województwo -> Powiat -> Gmina -> Miejscowość.

Przedstawie tuta tylko pierwszy etap (Województwo -> Powiat) - dorobienie reszty jest już dziecinnie proste.

Noto zaczynamy.
Na początek podam definicję bazy danych abyście nie musieli się trudzić - oczywiście ktoś może ją wypełnić swoimi danymi:
  1. #
  2. # Struktura tabeli dla `powiaty`
  3. #
  4.  
  5. CREATE TABLE `powiaty` (
  6. `ID` int(10) NOT NULL AUTO_INCREMENT,
  7. `ID_wojewodztwo` int(10) DEFAULT NULL,
  8. `Powiat` varchar(20) DEFAULT NULL,
  9. UNIQUE KEY `ID` (`ID`)
  10. ) TYPE=MyISAM AUTO_INCREMENT=15 ;
  11.  
  12. #
  13. # Zrzut danych tabeli `powiaty`
  14. #
  15.  
  16. INSERT
  17. INTO `powiaty` VALUES (1, 1, 'Wroclawski');
  18. INSERT
  19. INTO `powiaty` VALUES (2, 1, 'Sroda Slaska');
  20. INSERT
  21. INTO `powiaty` VALUES (3, 1, 'Miekinia');
  22. INSERT
  23. INTO `powiaty` VALUES (4, 1, 'Legnica');
  24. INSERT
  25. INTO `powiaty` VALUES (5, 1, 'Lubin');
  26. INSERT
  27. INTO `powiaty` VALUES (6, 2, 'Opole');
  28. INSERT
  29. INTO `powiaty` VALUES (7, 2, 'Brzezie');
  30. INSERT
  31. INTO `powiaty` VALUES (8, 2, 'Grodkow');
  32. INSERT
  33. INTO `powiaty` VALUES (9, 2, 'Brzeg');
  34. INSERT
  35. INTO `powiaty` VALUES (10, 2, 'Nysa');
  36. INSERT
  37. INTO `powiaty` VALUES (11, 3, 'Szczecin');
  38. INSERT
  39. INTO `powiaty` VALUES (12, 3, 'Szczecinek');
  40. INSERT
  41. INTO `powiaty` VALUES (13, 3, 'Gryfow');
  42. INSERT
  43. INTO `powiaty` VALUES (14, 3, 'Miedzyzdroje');

Jak zwykle mamy 4 pliki. Pierwszy z nich to dobrze wszystkim znay plik <span style="font-weight: bold;">advajax.js</span>. Kolejnym plikiem jest <span style="font-weight: bold;">dzialaj.html</span> (plik który uruchamia użytkownik), plik <span style="font-weight: bold;">odpowiedz.php </span>- generujący odpowiedź z serwera w postaci XML oraz plik z funkcjami JS - <span style="font-weight: bold;">function.js</span>.

Plik uruchamiany przez użytkownika nie jest wielce skomplikowany:
  1. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  2. </head>
  3.  
  4. <select name="wojewodztwa" id="wojewodztwa" onchange="getRecords();">
  5. <option value="1">Dolnośląskie</option>
  6. <option value="2">Opolskie</option>
  7. <option value="3">Zachodnio Pomorskie</option>
  8.  
  9. <select name="gminy" id="gminy" style="width: 200px;">
  10.  
  11. <script type="text/javascript" src="advajax.js"></script>
  12. <script type="text/javascript" src="function.js"></script>
  13. </body>
  14. </html>

Składa się on z dwóch selectów (wojewodztwa - z wypełnioną listą) oraz gminy (będzie dopiero wypełniany)

Plik odpowiedz.php jest bardzo ładny smile.gif :
  1. <?
  2. header("Content-type: text/xml; charset=UTF-8"); 
  3. echo '<?xml version="1.0" encoding="UTF-8"?>';
  4.  
  5. $dbhost = localhost;
  6. $dblogin = root;
  7. $dbhaslo = '';
  8. $db = uop;
  9. mysql_connect (localhost,root,'') or die ("Nie masz uprawnien");
  10. $wojewodztwo = (int)$_GET['wojewodztwo'];
  11. if(!$wojewodztwo) $wojewodztwo = 1;
  12.  
  13. echo '<records>';
  14. $query = "SELECT ID, Powiat FROM powiaty WHERE ID_wojewodztwo='$wojewodztwo'";
  15. $result = mysql_query($query);
  16. while ($row = mysql_fetch_array($result)){
  17. echo '<record>';
  18. echo '<ID>'.$row['ID'].'</ID>';
  19. echo '<nazwa>'.$row['Powiat'].'</nazwa></record>';
  20. }
  21.  
  22. echo '</records>';
  23. ?>

Bardzo ważny jest nagłówek - aby był to plik XML:
  1. header("Content-type: text/xml; charset=UTF-8"); 
  2. echo '<?xml version="1.0" encoding="UTF-8"?>';

Potem zwykłe zapytanie do bazy danych wybierające odpowiednie rekordy - nic szczególnego.
Po zapytaniu następuje generacja XML - także nic co mogło by być bardzo szczególnym zajęciem. Nie zagłębiam się tutaj w puste znaczniki (aby zamiast <nazwa></nazwa> pisać </nazwa>) nie zajmuję się także polskimi znaczkami aby nie komplikować kodu - i muszę coś pozostawić jeszcze Wam smile.gif

Bardzo istotnym plikiem jest plik function.js:
  1. function $(id){
  2. return document.getElementById(id);
  3. }
  4. function parseRecords(xml) {
  5.  
  6. var opttypes = document.getElementById("gminy");
  7. record = xml.getElementsByTagName("record");
  8. ID = new Array();
  9. nazwa = new Array();
  10. for (i = 0; i < record.length; i++) {
  11. nazwa[i] = record[i].childNodes[1].childNodes[0].nodeValue;
  12. ID[i] = record[i].childNodes[0].childNodes[0].nodeValue;
  13.  
  14. }
  15.  
  16. for (i = opttypes.options.length-1; i >= 0; i--) {
  17. opttypes.remove(i);
  18. }
  19.  
  20. for(var i = 0; i < nazwa.length; i++) {
  21. opttypes.options[i] = new Option(nazwa[i],ID[i]);
  22. }
  23. }
  24. function getRecords() {
  25. var wojewodztwo = $("wojewodztwa").value;
  26.  
  27. advAJAX.get({
  28. url : "odpowiedz.php?wojewodztwo="+wojewodztwo,
  29. onInitialization : function(obj) {
  30. $("gminy").disabled="true";
  31. },
  32. onSuccess : function(obj) {
  33. parseRecords(obj.responseXML);
  34. $("gminy").disabled="";
  35. }
  36. });
  37. }

Trzy skromne funkcje, a właściwie tylko dwie: jedna parsująca wynik XML na kod HTML. Dzieje sie to za pomocą new Option(Nazwa,Value), a wartości są zczytywane z odpowiedzi XML za pomocą:
  1. record[i].childNodes[0].childNodes[0].nodeValue;
  2. record[i].childNodes[1].childNodes[0].nodeValue;

Jest jeszcze funkcja "uruchamiająca" AJAXa. Najpierw prosi go o to aby wyczytał odpowiedni URL z odpowiednia opcia (?wojewodztwo) a nastepnie podczas inicjalizacji blokuje selecta gminy. Po zakonczeniu wczytywania (onSuccess) XML jest parsowany a select gminy odblokowywany.

To tyle - it`s simply smile.gif
Nie powinno nastarczyć to kłopotu ludziom z podstawową znajomością JS, php, MySQL.

P.S Proszę nie zwracać na błedy w postaci że dany powiat nie jest powiatem albo nie leży w odpowiednim województwie tongue.gif




Skrypt jest dobry, ale ma pare mankamentow. Mianowicie przy przeladowaniu strony w celu weryfikacji formularza select wojewodztwo pozostaje na wybranym obiekcie, natomiast select gmina jest pusty. PRZYKLAD:

Dolnoslaskie
Lubuskie
Malopolskie
Wielkopolskie

Wybieram Lubuskie. Laduja mi sie gminy:

Nowa Sol
Zielona Gora
Zagan
Zary

Wybieram Zielona Gora. Klikam na wyslij. Przeladowuje mi sie strona. Ze wzgledu na blad musze uzupelnić niewypelnione pole. I teraz jest problem ze skryptem. Select wojewodztwa jest ustawione za pomoca selected na wybranym poprzednio lubuskim. Natomiast w select gminy nic nie ma i jest pusto. Klikam na wojewodztwa i na lubuskie i niestety nic to nie daje. Musze dopiero wybrac inne wojewodztwo, nastepnie kliknac ponownie na lubuskie i wtedy dopiero wyswietli sie lista gmin z lubuskiego. Strasznie to nieporeczne. Czy mozna to jakos poprawic. Chodzi mi o to, zeby zapamietywal po przeladowaniu liste gmin i za pomoca selected ustawial na wybranej wczesniej gmine.

Mysle, ze to poprawi funkcjonalnosc skryptu. Z gory dziekuje za odpowiedz.
kukix
oczywiście, ze mozna:
  1. <BODY onLoad="getRecords();">
luckyluc
Jest to rozwiazanie, ale polowiczne poniewaz po przeladowaniu wyswietla dane w gminach, ale nie ustawia select na pozycji, ktora zostala wybrana przed przeladowaniem. Gdyby to sie udalo rozwiazac skrypt bylby idealny smile.gif Prosze o podpowiedz.
astropanic
Też z tym długo walczyłem,
Ja mam zrobione to tak że mam tradycyjnie dwa pola select w szablonie (działam na opt, ale bez szablonów będzie podobnie, chodzi o samą ideę).
Jeżeli muszę ponownie zwrócić szablon na wskutek niepoprawnie wypełnionych pól, wyświetlam te tradycyjne selecty z ustawionymi polami option pobranymi z metody POST/GET(w zależności od metody formularza), lecz do obydwóch dołączam kod JS powodujący że przy zmianie stanu selecta AJAX dogrywa dalszą część. Proste i skuteczne roziwązanie. Nadmienię że do pola do wyboru miast na starcie nie wyświetlam wcale, dogrywam go dopiero w momencie wyboru województwa.

Zastanawiam się nad wykorzystaniem AJAX + zwykle pole typu text do wpisywania samego miasta, coś w stylu google suggest, a jeśli ktoś wpisze miasto którego nie ma, żeby lądowało w bazie jako sugerowane do moderatora. Być może to też będzie sensowne rozwiązanie eliminujące ogromną listę miast.

Pozdrawiam
luckyluc
Cytat(astropanic @ 17.02.2007, 23:41:25 ) *
Też z tym długo walczyłem,
Ja mam zrobione to tak że mam tradycyjnie dwa pola select w szablonie (działam na opt, ale bez szablonów będzie podobnie, chodzi o samą ideę).
Jeżeli muszę ponownie zwrócić szablon na wskutek niepoprawnie wypełnionych pól, wyświetlam te tradycyjne selecty z ustawionymi polami option pobranymi z metody POST/GET(w zależności od metody formularza), lecz do obydwóch dołączam kod JS powodujący że przy zmianie stanu selecta AJAX dogrywa dalszą część. Proste i skuteczne roziwązanie. Nadmienię że do pola do wyboru miast na starcie nie wyświetlam wcale, dogrywam go dopiero w momencie wyboru województwa.

Zastanawiam się nad wykorzystaniem AJAX + zwykle pole typu text do wpisywania samego miasta, coś w stylu google suggest, a jeśli ktoś wpisze miasto którego nie ma, żeby lądowało w bazie jako sugerowane do moderatora. Być może to też będzie sensowne rozwiązanie eliminujące ogromną listę miast.

Pozdrawiam



Do tej pory nie moge sobie z tym poradzic, chociaz probowalem wielokrotnie. Czy mozesz pokazac swoje rozwiazanie na jakims przykladzie, bo nie rozumiem jak sobie z tym problem poradziles. Bede wdzieczny.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.