Door
Liefhebber Laravel
op 19-01-2018 12:00
gewijzigd op 19-01-2018 12:35
3.955 views
Hoi,
Ik heb een vraag mbt de return van een ajax waarde uit een functie.
Dit is mijn functie:
function getPrice(productcode, quantity, specifications){
var url = "api-url-with-security-token";
var call = $.ajax({
type: "POST",
url: url,
data: {
productcode: productcode,
quantity: quantity,
specifications: specifications
}
});
call.done(function(data){
var result = JSON.parse(data);
if ('status' in result) {
console.log(result.prices.total);
price = result.prices.total;
return price;
}else{
console.log("ERROR price request");
return 0;
}
});
}
Als ik deze functie aanroep zoals dit:
var price = getPrice('CODE1', 5, '');
console.log(price);
Dan wordt in mijn console de variabele price 'undefined', terwijl de console.log functie IN mijn functie wel degelijk de correcte waarde teruggeeft.
Dit is waarschijnlijk omdat de functie al een return doet, nog VOOR de ajax-request een antwoord heeft gegeven. Maar hoe zorg ik ervoor dat de functie pas een return mag doen wanneer de ajax correct is uitgevoerd en een antwoord heeft gegeven?
De functie getPrice() retourneert niks, die maakt alleen een asynchrone call. Pas in de done heb je je antwoord, maar dan is de getPrice call allang verleden tijd. Wat je dus met de price van regel 16/17 wilt doen zul je daar moeten doen (of een callback functie meegeven aan getPrice().
@ Rob Doemaarwat: Maar ik roep deze functie aan vanuit een ander script, en moet dan met die prijs verder om nog andere berekeningen te doen. Is een callback functie dan de beste oplossing?
En hoe pas ik dit dan toe in mijn voorbeeld?
function getPrice(a,b,c,callback){
//...
call.done(function(data){
//...
callback(price);
});
}
//vanuit ander script
getPrice(1,2,3,function(price){
//doe ding met price
});
Je kunt ook je "call" object retourneren, en dan in je "andere script" de done() d'r aan knutselen. Maar in beide gevallen zul je niet "synchroon" (= direct) een antwoord krijgen. De asynchrone call heeft even tijd nodig, en de code waarin je getPrice() hebt aangeroepen loopt gewoon door.
Dat zogenaamd on-hold zetten kan wel, maar bereik je in JS niet door het 'een regeltje lager' te zetten. Kenmerk van JS is namelijk dat het non-blocking is, dus het wacht niet tot de asynchrone AJAX-call ( :-) dat was eventjes dubbelop) klaar is.
Via callback, promises, etc. bereik je wat je wilt bereiken, nl verschil tussen 'nu' en 'later'.
PS er bestaat ook iets als blocking AJAX, maar dat terzijde
Ik wil eigenlijk gewoon een functie (die in de scripts.js staat) die ergens via een API een prijs ophaalt, en die prijs teruggeeft. Daarna wil ik in mijn algemene pagina een script onderaan toevoegen die gewoon dit doet in deze stappen:
- een 'on-hold' div zichtbaar maken (met een zandlopertje en tekst "prijs wordt opgehaald")
- de functie van hierboven aanroepen om de prijs aan te vragen
- als de prijs binnen is, DAN PAS de on-hold div onzichtbaar maken
- de binnengekomen prijswaarde met jQuery in het veld plaatsen (iets zoals $('#price').val(price);)
Dit moet toch op een relatief eenvoudige manier te bouwen zijn?
Je geeft zelf de oplossing al - bouw gewoon de AJAX-call in in het gedeelte waar je je prijs-animaties regelt. Dit kan best in een hardcoded snippet JavaScript, omdat dit toch heel erg specifiek is - dit lijkt mij ook te speficiek om die in een "scripts.js" op te nemen, tenzij je dit op een heleboel plaatsen gaat gebruiken? En dan zou je misschien aan een generiekere oplossingen moeten gaan denken die je in een price.js stopt ofzo.
Maak anders eens een simpele proof of concept, in principe heb je alle bestanddelen al.
In aansluiting op opmerking Thomas... deze vraag kun je geheel zelf oplossen door in etappes te werken. Ik heb wel wat suggesties:
1. loader kan met puur css,
2. in html kun je een div maken met een class="loader" en id="response" (voorbeeldnamen),
3. in één simpele AJAX-snippet (in JS) kun je het PHP-script aanroepen en zodra de response er is:
A. de class="loader" verwijderen;
B. de HTML-response van de server in de div met id="response" plaatsen;
Voorbeeldje in JS:
$.ajax({url: "<url>script.php", success: function(result){
$("#response").removeClass();
$("#response").html(result);
}});
That's it.
PS In vbd even een method: "GET", maar met method: "POST" is het voorbeeld niet wezenlijk anders