简体   繁体   中英

Pulling external JSON file into a javascript variable using jQuery

I've been building onto some example code for the Twitter Bootstrap Typeahead plugin.

In an early development version of the script, I included the following, lifted almost directly from the example, with a few customisations that have worked perfectly;

$('.building_selector').typeahead({
    source: function (query, process) {
        buildings = [];
        map = {};   
        var data = [{"buildingNumber":"1","buildingDescription":"Building One"},{"buildingNumber":"2","buildingDescription":"Building Two"},{"buildingNumber":"3","buildingDescription":"Building Three"}];
        $.each(data, function (i, building) {
            map[building.buildingDescription] = building;
            buildings.push(building.buildingDescription);
        });
        process(buildings);
},
updater: function (item) {
    selectedBuilding = map[item].buildingNumber;
    return item;    
},
});

In practice, this isn't much use while I've got the array of options written directly into the code, so I've been looking at reading an external file with the JSON written in. I've created a file, containing just the array as follows;

[{"buildingNumber":"1","buildingDescription":"Building One"},
{"buildingNumber":"2","buildingDescription":"Building Two"},
{"buildingNumber":"3","buildingDescription":"Building Three"}]

And I've now attempted to update the Javascript to include the code to load up the remote file. I can verify the file exists and is in the correct relative location.

$('.building_selector').typeahead({
    source: function (query, process) {
        buildings = [];
        map = {};
        var data = function () {
            $.ajax({
                'async': false,
                'global': false,
                'url': "../json/buildings",
                'dataType': "json",
                'success': function (result) {
                    data = result;
                }
             });
            return data;
        }(); 

    $.each(data, function (i, building) {
        map[building.buildingDescription] = building;
        buildings.push(building.buildingDescription);
    });

process(buildings);
    },

updater: function (item) {
    selectedBuilding = map[item].buildingNumber;
    return item;    
},
});

On running the page, all of the elements appear to work as expected, and nothing appears in the Console, until you click inside the text field and being typing. After each keypress, nothing visibly happens, but the following is produced in the Console;

Uncaught TypeError: Cannot read property 'length' of undefined [jquery.min.js:3]

Any ideas/thoughts/starting points to try and fix this would be much appreciated!

First of all, I would recommend you to use $.getJSON instead of $.ajax (you can save a lot of unnecessary lines of code). // See $.getJSON doc here: http://api.jquery.com/jQuery.getJSON/

Second, you have to reference the data variable according to its scope (when calling data var inside the success function, the scope has changed and the data var is not found, that is why it's throwing "Cannot read 'leangth' of undefined"). You have to set a self reference variable that points to the data variable scope.

This will help:

$('.building_selector').typeahead({
    source: function (query, process) {
        var buildings = [];
        var map = {};
        var self = this; //This is a self reference to use in the nested function of $.getJSON

        $.getJSON('../json/buildings', function(data){
            if ($.isArray(data)) {
                $.each(data, function (i, building) {
                    self.map[building.buildingDescription] = building;
                    self.buildings.push(building.buildingDescription);
                });
                process(self.buildings);
            }
        });
    },

    updater: function (item) {
        selectedBuilding = map[item].buildingNumber; // This won't work. I'd suggest to move the map variable as part of the top level object.
        return item;    
    }
});

I shall add a little explaination of the point I reached in the end, as it's quite a change;

As the content of the JSON file is dynamic, but doesn't need to be called on every keypress, I decided to import it once, using $.getJSON inside a $document.ready() . It then writes the content into a global variable, which can be loaded by the source function exactly as before.

Here's the code for reference;

$('.building_selector').typeahead({
    source: function (query, process) {
        buildings = [];
        map = {};   
        $.each(buildinglist, function (i, building) {
            map[building.buildingDescription] = building;
            buildings.push(building.buildingDescription);
        });
        process(buildings);
    },
    updater: function (item) {
        selectedBuilding = map[item].buildingNumber;
        return item;    
    },
});
var buildingList;
$(document).ready(function() {
    $.getJSON('../json/buildings/', function(json){
        buildinglist = json;
    });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM