Walk-through: step by step

This walk-through is designed to illustrate common tasks and situations an application will perform when manipulating resources through the Mendeley API. The walk-through is based on the sample code Readership Locations, written in JavaScript.

Readership Locations in a web browser

The Readership Locations sample application displays a world map showing the regions where a document has been read. The application lists the documents from a user library and for each document selected will request the catalog document using a Digital Object Identifier (DOI) value or an ArXiv value to link the catalog document to the document in the user's library.

The javascript application performs a number of tasks:

  1. Display a usage map or redirect to an authorization page, depending on the presence of an OAuth access token
  2. Request the user's documents and use the results to populate a menu
  3. Request catalog document statistics and use the results to mark regions on a map

This walk-through will examine each of these tasks in detail and explain how the Mendeley API and the Mendeley Javascript SDK is used to accomplish each task.

Note: before running the example you should ensure you have a Mendeley account and your library contains a number of documents. Only documents with a DOI or ArXiv identifier will be displayed in the app. Use the tool Populator to insert appropriate sample documents into the user library.

1. Display a usage map or redirect to an authorization page

The HTML page, once loaded, executes the following JavaScript code


    if (typeof window.oauthImplicitGrantConfig === 'object') {
        MendeleySDK.API.setAuthFlow(MendeleySDK.Auth.implicitGrantFlow(window.oauthImplicitGrantConfig));
    // ..
    } else {
        console.log("something is wrong");
    }

The code uses the Mendeley SDK to retrieve and set the OAuth data. The authentication token has a limited lifespan so you will be able to use the page for a while before having to re-authorize the app.

2. Request the user's documents and use the results to populate a menu

Once the HTML page has loaded and you are authenticated, the Javascript function getDocuments is invoked by binding a ready event to the page.

    $(document).ready(getDocuments)

The getDocuments function looks like this:

    var getDocuments = function () {
        MendeleySDK.API.documents
        .list()
        .done(populateDropdown)
        .fail(errorHandler);
        }

There is no need to do any kind of configuration.

The argument populateDropdown passed to the done method processes the result

var populateDropdown = function (docs) {
    var i, len, doc, identifierType, identifierValue,
    popup_menu = document.getElementById("user_doc_popup");
    for (i = 0, len = docs.length, doc; i < len; i+=1) {
        doc = docs[i];
        if (doc.identifiers) {
            if (doc.identifiers.arxiv) {
                identifierType = "arxiv";
                identifierValue = doc.identifiers.arxiv;
            }
            if (doc.identifiers.doi) {
                identifierType = "doi";
                identifierValue = doc.identifiers.doi;
            }
        }
        if (identifierType) {
            var option = document.createElement("option");
            option.textContent = doc.title;
            option.setAttribute("data-identifier-type", identifierType);
            option.value = identifierValue;
            popup_menu.appendChild(option);
        }
    }
    $("#user_doc_popup").trigger("change");
}

If the API response is successful, the JSON response text is used to populate the popup menu. The function checks each object for the existence of a DOI or ArXiv identifier. If the document has at least one of these two identifiers, an <option> element is appended to the popup menu. The document's title is used for the visible label and the identifier is stored in the hidden value of the HTML select element. The identifier type is also stored as a data attribute for later use.

Once the popup menu is composed, the function triggers a change event to color code the map using the first item in the popup menu. Instantly providing gratification and indication of function improve the user experience.

3. Request catalog document statistics and use the results to mark regions on a map

Whenever the user selects a new document, or immediately after the document popup menu is populated, the reading statistics for the newly selected document are loaded with the help of the Javascript SDK. The reading statistics are used to color regions of the map. The JavaScript function getCatalog sends the API request and calls updateMap to color maps regions on a successful response:

var getCatalog = function (event) {
    var identifierType = this.selectedOptions.item(0).dataset.identifierType,
    identifierValue = this.value,
    uriArgs = {};
    uriArgs[identifierType] = identifierValue;
    uriArgs["view"] = "stats";
    MendeleySDK.API.catalog
    .search(uriArgs)
    .done(updateMap)
    .fail(errorHandler);
    event.preventDefault();
    }

First the function obtains the identifier type and value stored in the popup menu. Next the function creates an array with this information and passes it as argument to the search method. To be more precise, the URL will contain the following settings:

  • the identifier type and value to search for a single document with a matching identifier
  • the value of the view field in the query string to stats to include reading statistics in the response

The updateMap function looks like this:

var updateMap = function (stats) {
    var arrayData = {},
    maxCount = 0,
    ratio;
    $.each(stats, function(i, obj) {
        if (obj.reader_count_by_country) {
            for (var property in obj.reader_count_by_country) {
                if(arrayData[property]) {
                    arrayData[property] += obj.reader_count_by_country[property];
                } else {
                    arrayData[property] = obj.reader_count_by_country[property];
                }
                maxCount = Math.max(maxCount, arrayData[property]);
            }
        }
    });
    var map_regions = map.contentDocument.getElementsByClassName('land');
    for (var index = 0; index < map_regions.length; index++) {
        var map_region = map_regions[index].getAttribute("title");
        if (arrayData[map_region]) {
            ratio = arrayData[map_region]/maxCount;
            map_regions[index].style.fill = "rgba(157, 22, 32, " + ratio + ")";
        } else {
            map_regions[index].style.fill = "rgb(204,204,204)";
        }
    }
}

If the API response is successful, an array containing the total number of readers by country is built using the data. This is an array with keys labelled with English descriptions of the country and the corresponding value is an integer indicating the number of times a document has been read.

After that, the function simply looks for matches between the region title label in the SVG map and the country member label in the /catalog API response:

** API response **
    "reader_count_by_country": {
    "Ireland": 2,
    "United Kingdom": 1
    }

    ** SVG document **
    <path id="GB" title="United Kingdom" class="land" d="M459.38,281l-1.5,3.29l-2.12,-0.98l-1.73…" />
    <path id="IE" title="Ireland" class="land" d="M457.88,284.29L458.34,287.65L456.22,291.77L451…" />

The function also calculates a ratio of readers distribution and uses an alpha value when coloring the map so that it reflects the relative number of readers

As geographic regions without reading statistics are not included, the function simply iterates through the map regions and if a reading statistic country is found, the function sets the map region's SVG fill color to red. If no country entry is found, the SVG map region is filled gray.

Suggestions for experimentation

Now that you understand how the sample code works, explore further by enhancing the application with new features.

  • Try caching the results of /catalog document responses to avoid repeatedly performing identical API requests each time the user changes document in the popup menu. Perhaps use an object global variable to store reading statistics keyed to an identifier.