# Externe gegevens ophalen via JSONP

We hebben het al enkele malen aangehaald: het is perfect mogelijk een JSON-bestand van een ander domein in te lezen. De externe server moet deze cross-domain-data echter wel toestaan. U kan dus niet zomaar eender welk JSON-bestand vanaf een externe server inlezen.

Even zoeken op Google en u vindt voldoende JSONP aanbieders.

Om een JSONP request uit te voeren, hoeft u meestal aan het einde van de URL enkel de parameter `callback=?` toe te voegen. Meer is het niet.

In deze voorbeelden gebruiken we enkel de methode `$.getJSON()`, maar u kan perfect de methodes `$.get()`, `$.post()` of `$.ajax()` gebruiken.

Voor deze oefeningen zijn we volledig afhankelijk van services van derden. Deze services kunnen in verloop van tijd wijzigen of zelfs helemaal verdwijnen. Het is dus best mogelijk dat tijdens het lezen van dit boek bepaalde oefeningen niet meer het gewenste resultaat opleveren.

## Filminfo ophalen via IMDB

De Internet Movie Database, of kortweg [IMDB](http://www.imdb.com/) is een online databank met informatie over films, series en games. IMDB biedt voorlopig zelf nog geen eigen API aan, maar er zijn reeds verschillende externe hosts die voor u de gegevens in JSONP formaat kunnen aanleveren. Een van die hosts is <http://www.omdbapi.com/>.

{% hint style="info" %}
Om seze service te kunnen gebruiken, moet u eerst een **gratis** apikey genereren!
{% endhint %}

![omdbapi API](/files/-L9sHk4XlErri0qt1xBp)

De API is zeer eenvoudig. In onze toepassing verwerken we dadelijk drie parameters, namelijk *t* voor de titel, *y* voor het jaartal en *plot*. Al deze parameters zijn optioneel.\
Voor we de code bekijken kunnen we best eerst de structuur van de JSON response bestuderen.

{% hint style="success" %}
★ Open **ajaxLokaal/JSONP\_imdb.html** in een browser.\
★ Open op deze pagina de voorbeeldlink **Zoek Pulp Fiction**.
{% endhint %}

![JSON zonder formatering](/files/-L9sHkaiOV1ZtmMvS9Ph)

Om de response zo klein mogelijk te houden, zijn alle overbodige spaties verwijderd. Dit maakt het ons wel extra moeilijk om de structuur te interpreteren. Gelukkig bestaat er een Chrome extensie **JSON Formatter** waarmee we JSON data kunnen herformatteren.\
(De link staat eveneens op de voorbeeldpagina.)

![JSON met formatering](/files/-L9sHkm-XlpUBcfnRPUh)

De structuur is nu makkelijk leesbaar. Een aantal van deze velden wordt in onze toepassing verwerkt. Let vooral op *Poster*. Dit veld bevat de URL naar de coverafbeelding.

{% hint style="success" %}
★ Open **ajaxLokaal/JSONP\_imdb.html**.\
★ Vul in het hidden-field **apikey** uw eigen apikey in!\
★ Bekijk de broncode en test het resultaat in een browser.\
★ Zoek op pulp fiction.
{% endhint %}

![](/files/-L9sHlFgOR-d77-opOtS)

Let in de code vooral op de structuur van het formulier!

```markup
<form name="imdbForm" id="imdbForm" method="get" action="http://www.omdbapi.com/">
    <div>
        <label for="t">Zoek titel:</label>
        <div class="input">
            <input type="text" name="t" id="t" required value="pulp fiction">
        </div>
    </div>
    <div>
        <label for="y">Jaar:</label>
        <div class="input">
            <input type="number" name="y" id="y">
        </div>
    </div>
    <div>
        <label for="plot">Plot:</label>
        <div class="select">
            <select name="plot" id="plot">
                <option value="short">korte samenvatting</option>
                <option value="full">volledig</option>
            </select>
            <i class="fa fa-angle-down fa-2"></i>
        </div>
        <input type="hidden" name="apikey" id="apikey" value="xxxxxx">
        <input class="button" type="submit" name="submit" id="submit" value="zoek">
    </div>
</form>
```

{% hint style="info" %}
Kies voor alle formuliervelden net dezelfde naam als de parameters in de API. Als we dadelijk het formulier verzenden, komen de juiste parameters automatisch correct in de URL terecht.
{% endhint %}

En nu het script.\
Omwille van de soms grote vertragingstijden, werken we bij het ophalen van externe gegevens best altijd met een preloader.

Zodra het formulier verzonden wordt (submit-event), gaan we met `e.preventDefault()` voorkomen dat de pagina wordt omgeleid naar de URL op de form-tag (<http://www.omdbapi.com/>). Vervolgens wordt de preloader getoond.

```javascript
$('#imdbForm').submit(function (e) {
    e.preventDefault();
    $('#imdbInfo').hide();
    $('.preloader-success').show();
    var pars = $(this).serialize();
    // alert(pars);
    $.getJSON('http://www.omdbapi.com/?callback=?&' + pars, function (data) {
        console.log('data', data)
        $('#titel').text(data.Title);
        $('#genre').text(data.Genre);
        $('#release').text(data.Released);
        $('#acteurs').text(data.Actors);
        $('#director').text(data.Director);
        $('#runtime').text(data.Runtime);
        $('#plotInfo').text(data.Plot);
        $('#cover').attr('src', data.Poster);
        $('#link').attr('href', 'http://imdb.com/title/' + data.imdbID);
        if (data.Poster) {
            data.Poster.length > 10 ? $('#cover').show() : $('#cover').hide();
        }
        $('#imdbInfo').show();
    }).fail(function (err) {
        console.error('error', err);
        alert(JSON.stringify(err));
    }).always(function () {
        $('.preloader-success').hide()
    });
});
```

De methode `serialize()` leest alle formuliervelden uit, zet de naam + waardes om naar de juiste URL decoding en plaatst deze in een string.

![](/files/-L9sHn0YB2PZ_t3wZxJF)

Dit is tevens het correcte formaat waarin we de gegevens moeten doorsturen naar de API. Vervolgens maken we een JSONP request met als URL: <http://www.omdbapi.com/?callback=?&t=pulp+fiction&y=&plot=short&apikey=xxxxxx>

Let vooral op de extra parameter **callback=?**.\
Zonder deze parameter geen JSONP en dus geen resultaat!

De logica binnen de callback functie kennen we ondertussen. De gegevens worden uitgelezen en op de juiste plaats op de pagina getoond. Zodra alles verwerkt is, wordt de preloader verwijderd.

Nog een kleine opmerking over de afbeelding. Voor sommige films bestaat (nog) geen cover. Indien Poster de waarde *N/A* heeft, maken we *#cover* onzichtbaar.

```javascript
if (data.Poster) {
    data.Poster.length > 10 ? $('#cover').show() : $('#cover').hide();
}
```

## Stadsinfo opvragen via GeoBytes

GeoBytes geeft ons algemene informatie (coördinaten, land, munteenheid, ...) van steden over de ganse wereld.

{% hint style="success" %}
★ Open **ajaxLokaal/JSONP\_stadsInfo.html**.\
★ Bekijk de broncode en test het resultaat in een browser.
{% endhint %}

![](/files/-L9sHneGgwIuk1yexqh2)

In deze toepassing maken we gebruik van drie API's.

* Links: GeoBytes API voor het tonen van de stadslijst.
* Midden: GeoBytes API voor het tonen van de stadsinfo.
* Rechts: Yandex Maps API voor het stadsplan.

Meer info over de gebruikte API's vindt u hier:

* <http://www.geobytes.com/free-ajax-cities-jsonp-api.htm>
* <https://tech.yandex.com/maps/doc/staticapi/1.x/dg/concepts/input_params-docpage/>

Als voorbeeld gaan we zoeken naar alle steden die de tekenreeks *antw* bevatten.

{% hint style="success" %}
★ Open <http://gd.geobytes.com/AutoCompleteCity?q=antw> in een browser.\
★ Herformatteer het resultaat met **JSONlint**.
{% endhint %}

![](/files/-L9sHoXJhdcesx2ZSn8d)

De details kunnen we opvragen via een tweede URL op GeoBytes.

{% hint style="success" %}
★ Open <http://gd.geobytes.com/GetCityDetails?fqcn=Antwerp,+AN,+Belgium> in een browser.\
★ Herformatteer het resultaat met JSONlint:
{% endhint %}

(De waarde voor de parameter *fqcn* kan u eventueel kopiëren uit voorgaande array.)

![](/files/-L9sHoius9QUUPkVoyT8)

De coördinaten *geobyteslatitude* en *geobyteslongitude* uit dit bestand gebruiken we om een statische afbeelding op Yandex te berekenen.

{% hint style="success" %}
★ Open de afbeelding in een browser:\
★ <https://static-maps.yandex.ru/1.x/?lang=en-US&z=12&l=map&size=400,400&ll=4.417000,51.216999&pt=4.417000,51.216999,pm2rdl1>
{% endhint %}

![](/files/-L9sHp-N78IMB-XSutY-)

Als we dit nu allemaal combineren, krijgen we volgende code:

```javascript
$('#geoForm').submit(function (e) {
    e.preventDefault();
});

// stadslijst
$('#q').keyup(function (e) {
    if ($('#q').val().length > 2) {
        var pars = $('#geoForm').serialize();
        $.getJSON('http://gd.geobytes.com/AutoCompleteCity?callback=?&' + pars, function (data) {
            $('#stadslijst li').remove();
            $.each(data, function (index, value) {
                $('#stadslijst ul').append('<li>' + this + '</li>');
            });
            $('#stadslijst li:first').text() == '' ? $('#stadslijst, #stadInfo').hide() : $('#stadslijst').show();
        });
    }
}).keyup();

// detail van de stad
$('#stadslijst ul').on('mouseenter', 'li', function () {
    var stad = $(this).text();
    $.getJSON('http://gd.geobytes.com/GetCityDetails?callback=?&fqcn=' + stad, function (data) {
        $('#stadInfo h2').text(data.geobytescity);
        $('#land').text(data.geobytescountry);
        $('#inwoners').text(data.geobytespopulation);
        $('#hoofdstad').text(data.geobytescapital);
        $('#tijdzone').text(data.geobytestimezone);
        $('#munt').text(data.geobytescurrency);
        var lat = data.geobyteslatitude;
        $('#lat').text(lat);
        var lng = data.geobyteslongitude;
        $('#lng').text(lng);
        var lngLat = lng + ',' +lat;
        var mapURL = 'https://static-maps.yandex.ru/1.x/?lang=en-US&z=12&l=map&size=400,400&ll=' + lngLat + '&pt=' + lngLat + ',pm2rdl1';
        $('#map').attr('src', mapURL);
    });
    $('#stadInfo').show();
});
```

Het keyup-event wordt getriggerd vanuit het zoekveld *q*. Indien dit veld meer dan twee karakters bevat, komt de eerste JSON request in actie. De gegevens die we als een array ontvangen, worden in een ul-lijst verwerkt. Eerst worden de oude items uit de lijst gewist en daarna wordt de lijst opnieuw opgebouwd.

Telkens we de muis op één van de steden plaatsen (*mouseenter*) worden de stadsdetails opgevraagd en wordt het middenstuk geüpdatet. Met de coördinaten kunnen we via de Yandex API een nieuwe afbeelding ophalen.

Merk op dat de stadslijst volledig dynamisch wordt opgebouwd.\
Op een dynamisch gegenereerde lijst kunnen we enkel het on-event gebruiken.

* **Goed**: `$('#stadslijst ul').on('mouseenter', 'li', function(){...})`. &#x20;
* **Fout**: `$('#stadslijst ul li').mouseenter(function(){...})`.

## JSONP met $.get(), $.post() of $.ajax()

Werkt u liever met deze methodes, vergeet dan niet het juiste formaat te vermelden.

De URL-parameter `callback=?` komt dan te vervallen.

* `$.get('url', function(data) {...},` `'jsonp'` `);`
* `$.post('url', function(data) {...},` `'jsonp'` `);`
* `$.ajax({..., dataType:` `'jsonp'` `, ...});`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://1itf.gitbook.io/jquery/10-ajax-zonder-server-side-scripting/externe-gegevens-ophalen-via-jsonp.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
