javascript undefined

kongen

kongemedlem
i en php fil har jeg denne koden

PHP:
echo 'javascript';

denne blir hentet inn i en javascript fil

PHP:
function javaFunc() {
var javaRequest = new XMLHttpRequest();		
javaRequest.open('get', 'java.php', true);
javaRequest.onreadystatechange = function () {
    var DONE = 4;
    var OK = 200;
    if (javaRequest.readyState === DONE) {
        if (javaRequest.status === OK) {
			return javaRequest.responseText;		
		}
	}
}
javaRequest.send(null);
}
document.getElementById("java").innerHTML = javaFunc();

og javascriptet blir hentet inn i en html fil

PHP:
<div id="java"></div>
<script type="text/javascript" src="java.js"></script>

men dette gir resultatet 'undefined' istedet for 'javascript'. Hvordan får jeg resultatet 'javascript'?
 

adeneo

Medlem
I JavaScript returnerer alle funksjoner "undefined" med mindre noe annet er spesifisert.
Nå har du jo spesifisert dette med en "return" inni der, og antar selvfølgelig at den returnerer resultatet fra ajax forespørselen når du kjører funksjonen.

Ajax står for "Asynchronous Javascript And XML", ajax er med andre ord asynkront.

Når en funksjon er asynkron så betyr det at funksjonen kjøres med en gang, men gir resultat senere, mens resten av koden fortsetter å kjøre. Asynkrone ting må altså ha en callback hvor resultatet er tilgjengelig ettersom det ikke stanser tråden.

I JavaScript gjelder dette stort sett timere, ajax, websockets og en del andre ting.

Her er et eksempel som forhåpentligvis er enklere å forstå
PHP:
var test = 0;
setTimeout(function() {
    test = 1;
}, 1000);

console.log( test ); // fortsatt 0, variablen endres ikke før om et sekund ?

Timeouten venter 1 sekund, og så endres variablen, men resten av koden fortsetter likevel å kjøre. Det er det som er akynkron oppførsel.

Ajax er noe av det samme
PHP:
var request = new XMLHttpRequest(); 

request.open('get', 'java.php', true); 
   // den siste parameteren ovenfor, "true", angir om forespørselen er synkron eller asynkron
   // Denne skal alltid settes til true, synkron ajax er en uting, og er i utgangspunktet aldri tillatt.

request.onreadystatechange = function () { 
    // legg merke til at dette er callback'en, den trigger på alle endringer i forspørselen, og 4 betyr at resultatet er mottatt

    if  ( request.readyState === 4 && request.status === 200) {
           // du kan rett og slett ikke returnerer herfra, denne callback'en kjøres senere
        var response = request.responseText; 
    }
}
request.send(null);

og det er kanskje enda lettere å forstå med XMLHttpRequest i jQuery

PHP:
$.ajax({
    url : 'java.php'
}).done(function(response) { // callback
     // response er kun tilgjengelig her
});
    // ikke her

Så hva er løsningen, hvordan får man resultatet tilbake fra en funksjon?
Den eneste løsninger er callbacks, enten det er i form av promises eller vanlige funksjoner, og koden må skrives slik at den fungerer med callbacks, som kan være litt plundrete noen ganger, men man må vente på at XMLHttpRequest kontakter "java.php" i bakgrunnen og laster inn innholdet i den filen, man har ikke noe annet valg.

PHP:
function javaFunc(callback) {
    var javaRequest = new XMLHttpRequest();
   
    javaRequest.open('get', 'java.php', true);
   
    javaRequest.onreadystatechange = function () {
        if (javaRequest.readyState === 4 && javaRequest.status === 200) {
                callback( javaRequest.responseText );
            }
        }
    }
    javaRequest.send(null);
}

javaFunc(function(data) {
    document.getElementById("java").innerHTML = data;
});

Dette er noe alle som begynner med JavaScript treffer på før eller siden, og alle gjør stort sett samme feilen.
På Stack Overflow har Felix fra Facebook vært så hyggelig å lage en slags kanonisk guide til asynkrone funksjoner, hvordan de virker, og hvordan man jobber med de, nettopp fordi det samme spørsmålet kommer opp hundre ganger hver eneste dag fra nye utviklere som støter på det samme problemet i forskjellige former

http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call

.
 

kongen

kongemedlem
Det virker. Kan man hente javascript slik også?

Hvis jeg har denne javascripten

PHP:
var num1 = 0;
var num2 = 20;
var num3= 0;

function klikkNum(num1) {
	if (num1 == 0){
		document.getElementById("java").innerHTML = '<button onclick="klikkTot()">Klikk knappen</button>';
	} else if (num1 == 1){
		document.getElementById("java").innerHTML = 'Du har klikket ' + num1 + ' gang. <button onclick="klikkTot()">Klikk mere</button>';
	} else {
		document.getElementById("java").innerHTML = 'Du har klikket ' + num1 + ' ganger. <button onclick="klikkTot()">Klikk mere</button>';
	}
}

function klikkTot() {
if (num1 == num2) {
document.getElementById("java").innerHTML = 'Du har klikket 20 ganger';
} else {
num1++;
klikkNum(num1);
}
}

window.onload = function() {
klikkNum(num1);
}

som puttes i en php fil

PHP:
echo "
var num1 = 0;
var num2 = 20;
var num3= 0;

function klikkNum(num1) {
	if (num1 == 0){
		document.getElementById(\"java\").innerHTML = '<button onclick=\"klikkTot()\">Klikk knappen</button>';
	} else if (num1 == 1){
		document.getElementById(\"java\").innerHTML = 'Du har klikket ' + num1 + ' gang. <button onclick=\"klikkTot()\">Klikk mere</button>';
	} else {
		document.getElementById(\"java\").innerHTML = 'Du har klikket ' + num1 + ' ganger. <button onclick=\"klikkTot()\">Klikk mere</button>';
	}
}

function klikkTot() {
if (num1 == num2) {
document.getElementById(\"java\").innerHTML = 'Du har klikket 20 ganger';
} else {
num1++;
klikkNum(num1);
}
}

window.onload = function() {
klikkNum(num1);
}
";

og hentes inn i den kjørende javascript filen.

PHP:
function javaFunc(callback) {
    var javaRequest = new XMLHttpRequest();
   
    javaRequest.open('get', 'java.php', true);
   
    javaRequest.onreadystatechange = function () {
        if (javaRequest.readyState === 4 && javaRequest.status === 200) {
                callback( javaRequest.responseText );
            }
        
    }
    javaRequest.send(null);
}


javaFunc(function(data) {
// hvordan få importert javascript til å virke i denne filen
});

Hvordan kan man få de opprinnelige javascriptkodene til å virke i javascript filen som henter inn javascript fra ekstern fil?
 

adeneo

Medlem
Nå er jeg ikke helt sikker på hva du mener, men jeg tror det enkleste er å endre på settingene slik at javascript parses av PHP, noe sånt ( kun for å demonstrere ... les videre ) ...
PHP:
<FilesMatch"\.(js)$">
AddHandler application/x-httpd-php .js
</FilesMatch>

i .htaccess, og så bare bruke en include
PHP:
// inne i "ting.js" e.l. ?

javaFunc(function(data) {
    <?php include_once('klikk.js'); ?>
});

Men dette er dårlig praksis. For det første ønsker man ikke å parse mer enn nødvendig, for det andre ønsker man å cache javascript filene, som ikke blir mulig dersom de har dynamisk innhold, slik at alt i alt er det en elendig løsning som aldri bør brukes, fordi det tyder på feil design fra starten av.

Det samme gjelder for echo'ing av javascript, det bør generelt sett unngås, og er så å si aldri nødvendig.
Dersom du trenger data fra serveren kan du echo'et det ut i data-attributter i HTML'en og hente det derfra i stedet, for eksempel, det finnes mange løsninger på det problemet som er bedre.

JavaScript bør strengt tatt holdes i eksterne .js filer, og ikke i PHP eller i HTML dokumenter, med noen svært få unntak. Når du er i ferd med å gjøre
PHP:
<?php

echo '<script type="text/javascript"> ... '

så gjør du noe feil, det samme med echo'ing av CSS fra serveren, det er slikt man skriver i egne filer, eventuelt med LESS eller SASS dersom man trenger det.

For ditt tilfelle bør du bare klippe og lime den ene funksjonen inn i den andre funksjonen og ha alt i en ekstern JavaScript fil.
Dersom du trenger data fra serveren kan du gjøre
PHP:
<div id="java" data-ting="<?php echo $ting; ?>">Heisann Sveisann</div>

og henge dataene med
PHP:
var javaElem = document.getElementById('java'); // cacher elementet slik
                                               // at vi kun henter det en gang
var data = javaElem.getAttribute('data-ting');
// nyere nettlesere har "dataset" som er litt greiere å jobbe med

eller eventuelt også gjøre slik i .php filen som henter inn javascript filene
PHP:
<head>
    <script>
        var data = <?php echo json_encode($arr); ?>
    </script>
    <script src="ting.js"></script>

men det lager en global variabel, som vi heller ikke liker noe særlig, men det er mye bedre enn å echo ut store mengder javascript.
 
Topp