简体   繁体   中英

Issue with parsing JSON for typeahead

I am new to the use of the typeahead plugin and my javascript(not jquery) skills are terrible. This is my JSON:

{"Product":[
    {"@ProductCode":"C1010","@CategoryName":"Clips"},       
    {"@ProductCode":"C1012","@CategoryName":"Clips"},
    {"@ProductCode":"C1013","@CategoryName":"Clips"},
    {"@ProductCode":"C1014","@CategoryName":"Clips"},
    {"@ProductCode":"C1015","@CategoryName":"Clips", "EAN":"0987654321"}
]}

I have the typeahead bundle 0.10.5 And this is my js:

$(document).ready(function () {
    var products = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        limit: 100,
        remote: {
            url: 'TypeAhead.ashx?q=%QUERY&cat=prod',
            filter: function (data) {
                return data.Products;
            }
        }
    });

    products.initialize();

    $("#tbSSearch").typeahead({
        highlight: true,
        minLength: 2
    }, {
        source: products.ttAdapter(),
        displayKey: function (products) {
            return products.product.code;
        },
        templates: {
            header:"<h3>Products</h3>"
        }
    });
});

Chrome console gives me:

Uncaught TypeError: Cannot read property 'length' of undefined

But that is in my jquery.2.1 (minified) lib and not the above js source. browser shows no popup below #tbSearch input.

as @Mike suggested, jsfiddle http://jsfiddle.net/gw0sfptd/1/ but I had to modify some stuff to work with local json. and this also does not work LOL

edit as David suggested, I should clean up my json. so it is now :

[{"Code":"C1010","Gtin13":0,"CategoryName":"Clips"},
 {"Code":"C1012","Gtin13":0,"CategoryName":"Clips"},
 {"Code":"C1013","Gtin13":0,"CategoryName":"Clips"}]

and the js:

remote: {
    url: 'TypeAhead.ashx?q=%QUERY&cat=prod',
    filter: function (products) {
        return $.map(products.results, function (product) {
            return {
                value: product.Code
            };
        });
    }
}
datumTokenizer: function (datum) {
    return Bloodhound.tokenizers.whitespace(datum.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,

But no working typeahead and no (useable)error in firefox console. My desired output would be a list of productcode, but also the category that they are in and the gtin13 (if not null) because the sql searches for all those three options. Should I make a javascript 'class' for product on the client side and parse the json to it? It is still unclear to me how the whole bloodhound thing works. (yes I have looked at the samples and read the docs of both typeahead and bloodhound) I don't know if it is possible but what my ultimate wish is, is that when you select an item from the typeahead suggestions this productdatasource links to productdetail.aspx and if you select an item of the categorydatasource (not visisble in this question) that it redirects the page to categorydetail.aspx

我的Chrome控制台错误

I've written a fiddle to demonstrate how to use your JSON (the local, not the remote, example) with typeahead.js:

http://jsfiddle.net/Fresh/f9rbeqyc/

In the following answer I chose to use the ProductCode as the suggestion, but you could obviously use the CategoryName if you wanted.

The key part of the code I used, along with some comments is here:

var json = '{"Product":[ ' +
 '{"@ProductCode\":\"C1010\",\"@CategoryName\":\"Clips\"},' +
 '{"@ProductCode\":\"C1012\",\"@CategoryName\":\"Clips\"},' +
 '{"@ProductCode\":\"C1015\",\"@CategoryName\":\"Clips\", \"EAN\":\"0987654321\"}]}';

// Parse the JSON string to a JSON object
var jsonObject = JSON.parse(json);

var products = new Bloodhound({
    // Use $.map() to create an array of ProductCode key value pairs
    local: $.map(jsonObject.Product, function (product) {
        return {
            value: product["@ProductCode"]
        };
    }),
    datumTokenizer: function (datum) {
        // Specify the variable within the datum to use as suggestion data
        // In this case it's the value
        return Bloodhound.tokenizers.whitespace(datum.value);
    },
    queryTokenizer: Bloodhound.tokenizers.whitespace
});

Also note that the datumTokenizer is specifying which value to use as a suggestion; an array of datums with a key called 'value' was created so we want to use 'value' as the display key. In your example you had "return products.product.code;" which isn't going to work as your datums don't have a field called "code", nor does your JSON(!).

You should be able to refer to my example and this answer to get your typeahead which uses remote working.

Bergi was right. You've since fixed the capitalisation but not the pluralisation: it should be data.Product , not data.Products . Or perhaps the JSON you quoted was just data.Products , in which case the array is data.Products.Product .

BADGERFISH AND ARRAYS

One more thing you should be aware of. It looks like the JSON here is from badgerfish . I don't know whether you know what this means - basically it's a way of translating XML to JSON. The format will be different if there is only one product or none at all. For example, the following XML:

<Products>
    <Product ProductCode="C1010" ="Clips"/>
    <Product ProductCode="C1012" ="Clips"/>
</Products>

would give the following JSON:

{
    "Products": {
        "Product": [
            {"@ProductCode":"C1010","@CategoryName":"Clips"},       
            {"@ProductCode":"C1012","@CategoryName":"Clips"},
        ]
    }
}

but with just one product, badgerfish wouldn't know to make it an array, and you'd get this:

{
    "Products": {
        "Product": {"@ProductCode":"C1010","@CategoryName":"Clips"}
    }
}

and with no products, it wouldn't know to include "Product" at all:

{
    "Products": {}
}

The upshot is you should probably prepare for these cases. Similarly, it looks to me like the function displayKey will throw an exception unless it receives exactly one product.

I work on a project where our nodejs servers connect to backend servers. These backends traditionally used XML, but now optionally respond with JSON using badgerfish. This situation with arrays is so common that we have a utility function which takes data.Products.Product as an argument and converts it to an array, if it isn't already one.

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