AJAX Problem / XMLHttpRequest

th23

Mitglied
Hallo,

mein Problem ist leider etwas komplizierter... ich hatte es eigentlich schon am funktionieren, aber so richtig funktioniert es nicht. Hoffe irgendjemand kann mir helfen :(

Ich poste den Code mal möglichst vollständig, damit es zu keinen Missverständnissen kommt. Ich hoffe das ist in Ordnung.

Hier ist der HTML-Teil:
Code:
 <form method="post" action="<?php echo $filename.$SID ?>">
 <select name="perm_new[]" id="perm_new" size="10" multiple="multiple"><?php /* option Füllanweisungen per php */ ?></select>
 <div id="perm_new_manipulate"><a href="#" onClick="searchMember('perm_new');">Search single member...</a></div>
 <input type="submit" value="OK" />
 </form>

Hier der JavaScript Teil:
Code:
 <script language="javascript"  type="text/javascript">
 var url = "th23test_xmlhttp.php?user_name_search="; // The server-side script
 function handleHttpResponse(element) {
 	alert(http.readyState);
 	if (http.readyState == 4) {
 		if (http.responseText.indexOf('invalid') == -1) {
 			var manipulate_name = element + '_manipulate';
 			var manipulate_div = document.getElementById(manipulate_name);
 			manipulate_div.innerHTML = http.responseText;
 			isWorking = false;
 		}
   }
 }
 var isWorking = false;
 function searchMember_execute(element) {
 	if (!isWorking && http) {
 		var user_name_search_name = element + '_user_name_search';
 		var user_name_search = document.getElementById(user_name_search_name).value;
 		http.open("GET", url + "?element=" + escape(element) + "&user_name_search=" + escape(user_name_search), true);
 		var manipulate_name = element + '_manipulate';
 		var manipulate_div = document.getElementById(manipulate_name);
 		manipulate_div.innerHTML = "Search in progress...";
 		http.onreadystatechange = handleHttpResponse(element);
 		isWorking = true;
 		http.send(null);
 	}
 }
 function addMember(element) {
 	var add_user_id_select = document.getElementById("add_user_id");
 	var add_user_id = add_user_id_select.value;
 	var add_user_value = '+u' + add_user_id;
 	var add_user_name = '[User] ' + add_user_id_select.options[add_user_id_select.selectedIndex].text;
 	var perm_new_manipulate_div = document.getElementById("perm_new_manipulate");
   var addOption = new Option(add_user_name, add_user_value, false, true);
   document.getElementById("perm_new").options[document.getElementById("perm_new").length] = addOption;
 	perm_new_manipulate_div.innerHTML = "<a href=\"#\" onClick=\"searchMember();\">Search single member...</a>";
 }
 function searchMember(element) {
 	var manipulate_name = element + '_manipulate';
 	var manipulate_div = document.getElementById(manipulate_name);
 	manipulate_div.innerHTML = "<form onSubmit=\"searchMember_execute('" + element + "');\"><input type=\"text\" name=\"" + element + "_user_name_search\" id=\"" + element + "_user_name_search\" />&nbsp;<input type=\"button\" value=\"Suchen\" onClick=\"searchMember_execute('" + element + "');\" /></form>";
 }
 function getHTTPObject() {
   var xmlhttp;
   /*@cc_on
   @if (@_jscript_version >= 5)
     try {
       xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
     } catch (e) {
       try {
         xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
       } catch (E) {
         xmlhttp = false;
       }
     }
   @else
   xmlhttp = false;
   @end @*/
   if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
     try {
       xmlhttp = new XMLHttpRequest();
     } catch (e) {
       xmlhttp = false;
     }
   }
   return xmlhttp;
 }
 var http = getHTTPObject(); // We create the HTTP Object
 </script>

Und hier der Backend-Teil (PHP) bzw. das, was dieser (mit Parametern aufgerufen) produziert ... genau der erwartete Code:
Code:
 <form onSubmit="addMember('perm_new');">
 <select name="perm_new_add_user_id" id="perm_new_add_user_id">
 <option value="1">Anonymous</option>
 <option value="2">test</option>
 </select>
 <input type="button" value="Hinzuf&uuml;gen" onClick="addMember('perm_new');" />
 </form>
 <a href="#" onClick="searchMember('perm_new');">New search...</a>

Schon mal vorab: Vielen Dank für jeden Tip! :)

edit: Achso...der alert(readystate) gibt immer 1 als Wert aus... vielleicht gibt das einen Hinweis auf das Problem. Ich weiss es allerdings nicht...
 
Zuletzt bearbeitet:
Punkt#1(betrifft nur den IE )
perm_new_manipulate befindet sich in einem Formular, wenn du dort ein weiteres Formular einfügst, reagiert der IE mit einer Fehlermeldung. Platziere das Div ausserhalb des Formulares.


Punkt#2:
Code:
http.onreadystatechange = handleHttpResponse(element);
Wenn du die Anweisung so notierst, wird sie sofort ausgeführt, und nicht erst beim onreadystatechange->das erzeugt somit einen Fehler, da der Request noch nicht gesendet wurde, wenn die Anweisung ausgeführt wird.

Schreibs so:
Code:
http.onreadystatechange = new Function('l',"handleHttpResponse('"+element+"')");

...weiter hab ich noch nicht geschaut, aber das Formular aus responseText sollte jetzt schon mal auftauchen:)


Kleiner Tipp zum Request:
Du solltest der URL der Anfrage mit JS immer einen aktuellen Zeitstempel(oder sonst einen einzigartigen Wert) anhängen.
Sonst bekommst du in den überwiegenden Fällen eine Antwort aus dem Browsercache, und wunderst dich, dass das Resultat nicht wie gewünscht ausfällt;)
 
Danke! Hilft schon weiter...

@Punkt 1: Geht das generell überhaupt nicht? - Das wäre aber schwierig...wie könnte man das umgehen?

@Punkt 2: Versuche ich logisch gerade noch zu verstehen, habe ich aber - um ehrlich zu sein - noch nicht. Kannst Du mir da nochmal helfen?

@Punkt 3: Zeitstempel ist eine gute Idee...habe ich gleich eingebaut.

Thanks
th23
 
Zuletzt bearbeitet:
@Punkt 1: du müsstest eine neue Dokumentensprache entwickeln(weil lt. HTML dürfen <form>'s keine weiteren <form>'s enthalten) :-)

@Punkt2:
Füge mal folgendes in irgendeine Seite ein, dann siehst du, was ich meine
Code:
window.onunload=alert('Das ist doch kein onunload ;P');

Du musst die erste Zeile durch die zweite Zeile in meinem vorrangegangenen Post ersetzen.
 
Hi Sven,

nochmal vielen Dank für Deine schnelle Hilfe...Super Support :-)

Also Punkt 1 schiebe ich dann doch mal lieber noch ein bisschen hinaus... ;) und halte mich so lange an die Definition. - Ich habe einfach ein "großes" Form-Element um alles gelegt und die inneren Forms weggelassen, was ohne Probleme geht, denn das JavaScript holt sich ja die richtigen Werte...

Bei Punkt 2 will ich Dir nicht pauschal widersprechen - Dein Beispiel macht Sinn, oder eher halt nicht ;) - aber in meiner Applikation klappt es auch mit meiner Notierung... ;-) Vielleicht initialisiert meine Zeile so eine Art Tracker, der bei jedem Change anspringt, egal wo er aufgerufen wird...

Ich poste nachher nochmal mein Script, so es jetzt gleich den Test besteht, damit die User auch die Lösung finden (oder ist das hier nicht erwünscht weil zu viel für die DB?)

Grüße
Thorsten
 
Zuletzt bearbeitet:
th23 hat gesagt.:
Ich poste nachher nochmal mein Script, so es jetzt gleich den Test besteht, damit die User auch die Lösung finden (oder ist das hier nicht erwünscht weil zu viel für die DB?)

Nur zu.... die DB wirds schon aushalten:)
Falls es eng wird, können wir ja ein paar Rechtsklick-Sperre-Themen rauswerfen:-)
 
Na gut, auf die Gefahr hin, dass dafür ein paar "rechts-klick"-Themen weichen müssen ;)

Hier ist der - trotz problematisches Notation ("http.onreadystatechange = handleHttpResponse;") - in Firefox und IE funktionierende Code:

JavaScript in der HTML-Datei:

Code:
<script language="javascript"  type="text/javascript">
var url = "th23links_searchuser.php?user_name_search=";
function handleHttpResponse() {
	if (http.readyState == 4) {
		if (http.responseText.indexOf('invalid') == -1) {
			eval(http.responseText);
			var manipulate_name = element + '_manipulate';
			var manipulate_div = document.getElementById(manipulate_name);
			manipulate_div.innerHTML = output;
			isWorking = false;
		}
  }
}
var isWorking = false;
function searchMember_execute(element) {
	if (!isWorking && http) {
		var user_name_search_name = element + '_user_name_search';
		var user_name_search = document.getElementById(user_name_search_name).value;
		var actual = new Date();
		var msec = actual.getTime();
		var xth = url + escape(user_name_search) + "&element=" + element + "&time=" + msec;
		http.open("GET", xth, true);
		var manipulate_name = element + '_manipulate';
		var manipulate_div = document.getElementById(manipulate_name);
		manipulate_div.innerHTML = "Suche wird ausgef&uuml;hrt...";
		http.onreadystatechange = handleHttpResponse;
		isWorking = true;
		http.send(null);
	}
}
function addMember(element) {
	var add_user_id_select_name = element + '_add_user_id';
	var add_user_id_select = document.getElementById(add_user_id_select_name);
	var add_user_id = add_user_id_select.value;
	var add_user_value = 'u' + add_user_id;
	var add_user_name = '[User] ' + add_user_id_select.options[add_user_id_select.selectedIndex].text;
	var manipulate_name = element + '_manipulate';
	var manipulate_div = document.getElementById(manipulate_name);
  var addOption = new Option(add_user_name, add_user_value, false, true);
  document.getElementById(element).options[document.getElementById(element).length] = addOption;
	manipulate_div.innerHTML = "<input type=\"button\" value=\"Add single user...\" onClick=\"searchMember('" + element + "');\" />";
}
function searchMember(element) {
	var manipulate_name = element + '_manipulate';
	var manipulate_div = document.getElementById(manipulate_name);
	manipulate_div.innerHTML = "<input type=\"text\" name=\"" + element + "_user_name_search\" id=\"" + element + "_user_name_search\" />&nbsp;<input type=\"button\" value=\"Search\" onClick=\"searchMember_execute('" + element + "');\" />";
}
function getHTTPObject() {
  var xmlhttp;
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
        xmlhttp = false;
      }
    }
  @else
  xmlhttp = false;
  @end @*/
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
      xmlhttp = new XMLHttpRequest();
    } catch (e) {
      xmlhttp = false;
    }
  }
  return xmlhttp;
}
var http = getHTTPObject();
</script>

Formular in der HTML-Datei:

(Kein Form-Tag in Form-Tag mehr ... Danke Sven für den Hinweis ... das hätte mich sonst wahrscheinlich bei der Fehlersuche im IE sehr lange beschäftigt ;) )

HTML:
<form method="post" name="edit" action="irgendwas.php"><table width="100%" cellspacing="2" cellpadding="2" border="0" align="center">
<tr>
<td class="row1"><b>See category: </b><br /><span class="gensmall"></span></td>
<td class="row2">
<table width="100%"><tr>
<td align="center" width="50%">
<select name="perm_cat_see_yes[]" id="perm_cat_see_yes" size="10" multiple="multiple">
  <option value="+g1" selected="selected">[Group] Guests</option>
  <option value="+g2">[Group] Unapproved Users</option>
  <option value="+g3" selected="selected">[Group] Unapproved COPPA Users</option>
  <option value="+g4">[Group] Registered Users</option>
  <option value="+g5" selected="selected">[Group] Registered COPPA Users</option>
  <option value="+g6">[Group] Super Moderators</option>
  <option value="+g7" selected="selected">[Group] Administrators</option>
  <option value="+g8">[Group] Bots</option>
  <option value="+g9">[Group] Test Gruppe</option>
  <option value="u2" selected="selected">[User] thorsten</option>
</select>
<div id="perm_cat_see_yes_manipulate"><input type="button" value="Add single user..." onClick="searchMember('perm_cat_see_yes');" /></div>
</td>
<td align="center" width="50%">
...
</td>
</tr></table>
</td>
</tr>
...
</form>

Hinweis: Es gibt natürlich mehrere solche Select-Tags in der ganzen Seite! Das ist auch der Grund, warum das JavaScript Update dynamisch gestaltet werden musste hinsichtlich der Feldanpassung!

Und - last but not least - das php-Skript welches das Return für das AJAX Update liefert (als Auszug) mit dem wichtigsten Teil:

PHP:
<?php

/** 
*
* th23test_xmlhttp.php
* (c) 2005 by Thorsten Hartmann (www.th23.net) released under GNU Public License
*     (see http://opensource.org/licenses/gpl-license.php for details)
*
*/

...

// --- ACTION ---
$user_name_search = request_var('user_name_search', '');
$element = request_var('element', '');

... execute search ...

if($row = $db->sql_fetchrow($result))
{
  $output = '<select name=\"'.$element.'_add_user_id\" id=\"'.$element.'_add_user_id\">';
  $output .= '<option value=\"'.$row['user_id'].'\">'.$row['user_name'].'</option>';
  while ($row = $db->sql_fetchrow($result))
  {
    $output .= '<option value=\"'.$row['user_id'].'\">'.$row['user_name'].'</option>';
  }
  $output .= '</select>&nbsp;<input type=\"button\" value=\"'.$user->lang['TH23LINKS_ADD'].'\" onClick=\"addMember(\''.$element.'\');\" /><br><input type=\"button\" value=\"'.$user->lang['TH23LINKS_NEW_SEARCH'].'\" onClick=\"searchMember(\''.$element.'\');\" />';
}
else
{
  $output = $user->lang['TH23LINKS_NO_USER_FOUND'].'<br><input type=\"text\" name=\"'.$element.'_user_name_search\" id=\"'.$element.'_user_name_search\" />&nbsp;<input type=\"button\" value=\"'.$user->lang['TH23LINKS_SEARCH'].'\" onClick=\"searchMember_execute(\''.$element.'\');\" />';
}

$return_value = "var element = \"".$element."\"; var output = \"".$output."\";";

echo $return_value;

?>

So, das ist das aktuelle Werk :-)

Raum für Verbesserungen (vielleicht hat ja jemand noch einen Tip): Aktuell wird nach der Rückübergabe der Werte (2 Stück) der String mit "eval" ausgeführt um die Variablen zur Verfügung zu haben. Das ist aus Sicherheitsgründen natürlich "bedenklich", aber ich habe (noch) keinen anderen Weg gefunden!

Grüße
Thorsten

P.S.: Daumen hoch für den Service und die Qualität hier...ist (bisher) das einzige (deutsche) Forum, bei dem ich zu dem doch etwas komplizierteren Problem überhaupt was gefunden habe!

P.P.S.: Die fertige Application gibts dann irgendwann auch zum freien Download (GPL, siehe oben im Code) auf meiner Homepage zum Download. Handelt sich dann um eine Erweiterung zu dem kommenden phpBB 3.
 
Zuletzt bearbeitet:
th23 hat gesagt.:
Hier ist der - trotz problematisches Notation ("http.onreadystatechange = handleHttpResponse;") - in Firefox und IE funktionierende Code:

Das ist nicht problematisch.... erkennst du den Unterschied?:
Code:
//zuerst-> das war nicht so gut, und hat einen Fehler erzeugt
http.onreadystatechange = handleHttpResponse(element);

//Jetzt->eine völlig korrekte Eventüberwachung
http.onreadystatechange = handleHttpResponse;

//mein Vorschlag: ebenfalls korrekte Eventüberwachung, 
//allerdings wird dabei noch ein Parameter übergeben
http.onreadystatechange = new Function('l',"handleHttpResponse('"+element+"')");
 
Ok, ich glaube jetzt habe ich (endlich) verstanden, wo das Problem ist...mit der Änderung lässt sich dann auch das eval(...) beseitigen!

Spitze! :D

Danke,
Thorsten
 
Kleine Anmerkung:
Dein Skript hat einen entscheidenden Nachteil-> es ist nicht flexibel.

Du kannst nur jeweils 1 Request absetzen, hast nur 1. URL , und verzichtest komplett auf die Vorzüge von Objekten: Man kann ihnen beliebige Eigenschaften zuweisen.

Denk mal drüber nach... es wäre doch Schade, wenn du fertig bist, und erst dann auf dieses Manko stösst.:)
 

Neue Beiträge

Zurück