Problem mit undefiniertem return in function

cyberian90

Grünschnabel
Hallo,

habe folgendes Problem, an dem ich schon seit Stunden sitze und einfach keine Lösung finde. In JS bin ich noch nicht ganz so erfahren, sodass es gerne sein kann, dass ich einfach was übersehen habe. Ich kenne mich da mehr in PHP aus und irgendwie ist mir die Sprache auch lieber :p

So, hier dann erst einmal der Code, der mir Probleme bereitet. Das ganze liegt innerhalb einer neuen jQuery-Funktion / eines neuen jQuery-Plugins, die / das ich gerade schreibe.

Code:
function getXMLGallery(){
	var pictures = new Array();
	var i = 0;
	$.ajax({
		type: "GET",
		url: "/inc/public/test.xml",
		dataType: "xml",
		success: function(xml) {
			$(xml).find('picture').each(function(){
				// Werte ermitteln
				p_dbid		= $(this).find('dbid').text();
				p_file		= $(this).find('file').text();
				p_name		= $(this).find('name').text();
				p_width		= $(this).find('width').text();
				p_height	= $(this).find('height').text();
				// Array füllen
				pictures[i] = new Array();
				pictures[i][0] = p_dbid;
				pictures[i][1] = p_file;
				pictures[i][2] = p_name;
				pictures[i][3] = p_width;
				pictures[i][4] = p_height;
				// Zähler
				i++;
			});
			return (pictrues);
			// an dieser Stelle funktioniert z.B. alert(pictures[1][2]); und liefert z.B. "Testname" aus
		}
	});
	// hier funktioniert z.B. alert(pictures[1][2]); nicht mehr. JS meldet, dass die Variable Pictures[1] undefined sei, versucht man es mit alert(Pictures);, ist die Ausgabe NULL, also leer
}


x = getXMLGallery();
alert(x[1][2]);			// Funktioniert nicht und produziert Fehler, da nichts von der Funktion zurückgegeben wird

jQuery ist natürlich zuvor eingebunden. Der AJAX-Aufruf klappt auch soweit, dass die Daten aus der XML ausgelesen werden. Leider gibt die Funktion aber nichts zurück, sodass ich mit meinem Array nicht weiterarbeiten kann.

Habe es auch schon mit objects erfolglos versucht. Da genau das selbe Problem.

Ich weiß echt nicht mehr weiter und woran es noch liegen könnte. Vielleicht hat ja einer einen Tipp für mich und ich seh den Code vor lauter Zeilen nicht...

Die XML (Anhang anzeigen xml.zip) habe ich mal beispielhaft angehangen.


Danke!
 
Zuletzt bearbeitet:
"// hier funktioniert z.B. alert(pictures[1][2]); nicht mehr."

Es gibt einen Unterschied zwischen zeitlichem und räumlichem "jetzt". Dein return steht zwar optisch "vor" der Stelle wo es nicht mehr funktioniert, wird aber zeitlich danach ausgeführt. Denn die Anfrage zum Server ist asynchron und die Antwort kommt irgendwann. Der Code läuft aber weiter als ob nichts wäre.
 
"// hier funktioniert z.B. alert(pictures[1][2]); nicht mehr."

Es gibt einen Unterschied zwischen zeitlichem und räumlichem "jetzt". Dein return steht zwar optisch "vor" der Stelle wo es nicht mehr funktioniert, wird aber zeitlich danach ausgeführt. Denn die Anfrage zum Server ist asynchron und die Antwort kommt irgendwann. Der Code läuft aber weiter als ob nichts wäre.


Ok, das verstehe ich soweit. Was muss ich nun aber ändern, dass ich den Array durch den Funktionsaufruf in die Variable x bekomme

Code:
x = getXMLGallery();
alert(x[1][2]);

und diese dann auch ausgeben kann. Ich benötige den Array später noch und will ihn daher hier per function erstellen lassen.
 
Javascript:
function getXMLGallery(callback) {
     // in success (wo jetzt return (pictrues); steht)
     callback(x);
}


//.....


getXMLGallery(function(x) {
    alert(x[1][2]);
});
 
Javascript:
function getXMLGallery(callback) {
     // in success (wo jetzt return (pictrues); steht)
    callback(pictures);
}
 
 
//.....
 
 
getXMLGallery(function(x) {
    alert(x[1][2]);
});


Habe die kleine Änderung oben in Zeile 3 vorgenommen (von callback(x); zu callback(pictures);) und jetzt funktioniert es super. Vielen Dank!
 
Zuletzt bearbeitet von einem Moderator:
Jetzt hat sich doch noch ein Problem ergeben. Wenn ich jetzt den Code so benutze, dann steht mir x ja nur innerhalb der Funktion zur Verfügung. Ich brauche ihn danach aber auch noch. Den Rest nach innerhalb der Funktion zu verlegen, ist keine Alternative, da ich noch mehrere andere Funktionen habe, die ebenfalls auf x zugreifen sollen. x müsste als global gelten und nicht nur lokal innerhalb der Funktion.

Javascript:
getXMLGallery(function(x) {
    alert(x[1][2]);
    // hier steht mir x zur Verfügung
});


Den derzeitigen Aufbau habe ich hier mal schematisch dargestellt:

Javascript:
(function($){
	$.fn.gallery = function(options){
		options = $.extend({
			// ... hier steht dann noch mehr
		}, options);
				
		function getXMLGallery(callback){
			// ... (wie bekannt geändert mit callback)
		}
		
		
		function newGallery(options){
			// Hier soll die XML eingelesen werden
			getXMLGallery(function(pics) {
				alert(pics[1][2]);
				// Hier muss noch irgendwas passieren, damit 'pics' auch danach definiert ist 
			});
			
			// Hier folgt dann auch noch ganz viel...
			// unter anderem werden hier die nachfolgenden Funktionen aufgerufen
			
		}
		
		function gotoGallery(firstlast, init){
			// Funktion braucht auch 'pics'-Array
		}
		
		function startstopGallery(){
			// Funktion braucht auch 'pics'-Array
		}
		
		
		
		function fillfitGallery(){
			// Funktion braucht auch 'pics'-Array
		}
		
		
		function showOverlayGallery(id){
			// Funktion braucht auch 'pics'-Array
		}
		
		
		// Neue Gallerie initalisieren
		newGallery(options);
	}
})(jQuery);


// Plugin-Aufruf wenn Seite geladen wurde
$(document).ready(function(e) {
   $("#gallery").gallery({
		// Hier steht dann noch was
	});
});


Die Funktion dann an mehreren Stellen aufzurufen wäre ja performance-technisch schlecht und außerdem problematisch, da sich die XML in der Zwischenzeit ja ändern könnte (die wird später dynamisch per php aus der Datenbank erzeugt).

Wie schaffe ich es also das Ergebnis der XML-Abfrage als Array 'pics' ab dem Abruf verfügbar zu machen für alle Funktionen?
Dajnke nochmal bis hierhin!
 
Zuletzt bearbeitet von einem Moderator:
Das ist nun mal so. Hier zwei mögliche Herangehensweisen:

1. Du packst alles in die Funktion rein. Oder anders gesagt: Erstell eine Funktion "init", die du an getXMLGallery übergibst. Der gesamte Inhalt deines Plugins geht dann von diesem Punkt aus. Oder noch sauberer: Pack deine ganze Logik in einer Klasse und instanzier sie, sobald du den Wert vom Server hast.

2. Du erweiterst die Funktion getXMLGallery dahingehend, dass Sie X mal aufgerufen werden kann, allerdings nur ein einziges Mal tatsächlich die Anfrage abschickt. Für denjenigen, der die Funktion aufruft, ist nicht ersichtlich ob
-die Funktionen einen Request absendet
-die Funktion direkt die callback Funktion aufruft (weil der Wert schon verfügbar ist)
-die Funktion dich in eine Warteschlange steckt und später callback aufruft

D.h. dort wo du jetzt "callback(pictures)" aufrufst, musst du eine Liste aller Leute abarbeiten, die den Wert gerne hätten. Sobald der Wert da ist, kommen weitere Anfragen nicht mehr in die Warteschlange sondern werden sofort beantwortet.
 
Nach deinem Beitrag habe ich mir noch einmal Gedanken zu dem Thema gemacht und folgende Lösung gefunden:

Javascript:
(function($){
    $.fn.gallery = function(options){
        options = $.extend({
            // ... hier steht dann noch mehr
        }, options);
        
        // XML einlesen und als JSON-String in DOM-Element ablegen
        getXMLGallery(function(pics) {
                $("<input>", {
                        id: "galleryPictures",
                        type: 'hidden',
                        value: '0'
                })
                .appendTo(element);
                $('#galleryPictures').val(JSON.stringify(pics));
        });

        function getXMLGallery(callback){
                var pictures = new Array();
                var i = 0;
                $.ajax({
                        type: "GET",
                        url: "/url/zur/test.xml",
                        dataType: "xml",
                        success: function(xml) {
                                $(xml).find('picture').each(function(){
                                        // Werte ermitteln
                                        p_dbid		= $(this).find('dbid').text();
                                        p_file		= $(this).find('file').text();
                                        p_name		= $(this).find('name').text();
                                        p_width		= $(this).find('width').text();
                                        p_height	= $(this).find('height').text();
                                        // Array füllen
                                        pictures[i] = new Array();
                                        pictures[i][0] = p_dbid;
                                        pictures[i][1] = p_file;
                                        pictures[i][2] = p_name;
                                        pictures[i][3] = p_width;
                                        pictures[i][4] = p_height;
                                        // Zähler
                                        i++;
                                });
                                callback(pictures);
                        }
                }).done(function(){
                        // Neue Gallerie initalisieren
                        newGallery(options);
                });
        }
        
        
        function newGallery(options){
            // 'pics'-Array aus Zwischenspeicher laden (DOM-Element)
            pics = $.parseJSON($('#galleryPictures').val());
            
            // Jetzt kann pics ständig verwendet werden
            // Hier folgt dann auch noch ganz viel...
            // unter anderem werden hier die nachfolgenden Funktionen aufgerufen
            
        }
        
        function gotoGallery(firstlast, init){
            // Funktion braucht auch 'pics'-Array
        }
        
        function startstopGallery(){
            // Funktion braucht auch 'pics'-Array
        }
        
        
        
        function fillfitGallery(){
            // Funktion braucht auch 'pics'-Array
        }
        
        
        function showOverlayGallery(id){
            // Funktion braucht auch 'pics'-Array
        }
    }
})(jQuery);
 
 
// Plugin-Aufruf wenn Seite geladen wurde
$(document).ready(function(e) {
   $("#gallery").gallery({
        // Hier steht dann noch was
    });
});

Damit geht es ganz gut. So kann jede Funktion auf den 'pics'-Array zugreifen und damit arbeiten.
 
Zuletzt bearbeitet von einem Moderator:
Zurück