0

I have run into issues while writing a web-app to fetch JSON data from our CRM application.

What I want to do is use Twitter's typeahead.js plugin to remotely fetch customer information from our CRM application. Microsoft does provide a way to use JSON data to communicate. They call it OData. However, this does not look like your typical JSON responses. This is why I have trouble setting up the typeahead plugin with it.

When I send a GET request to the API URL, I get the following response:

{
    "d":{
        "results":[
            {
                "__metadata":{
                    "uri":"http://*****/*****/XRMServices/2011/OrganizationData.svc/AccountSet(guid'de227fde-fb40-dd11-b5d3-001cc46325e5')",
                    "type":"Microsoft.Crm.Sdk.Data.Services.Account"
                },
                "Name":"Some company as",
                "AccountId":"de227fde-fb40-dd11-b5d3-001cc46325e5"
            },
            {
                "__metadata":{
                    "uri":"http://*****/*****/XRMServices/2011/OrganizationData.svc/AccountSet(guid'5dc70a19-e91e-e311-9ad7-005056ac083a')",
                    "type":"Microsoft.Crm.Sdk.Data.Services.Account"
                },
                "Name":"Compnay AS",
                "AccountId":"5dc70a19-e91e-e311-9ad7-005056ac083a"
            }
        ]
    }
}

So here is the question: How do I setup Twitter's typeahead plugin to work with this data structure?

I want the Name value from the JSON response when displaying the suggestions. And I want to grab the associated AccountId value when a suggestion is selected.

This is what I got in my code so far:

HTML:

<!DOCTYPE html>
<html lang="no">
    <head>
        <title>Company :: Time Registrering</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" type="text/css" href="css/global.css" />
    </head>
    <body>

        <form action="" method="GET" autocomplete="off">
            <input type="text" name="account" id="account" placeholder="Kunde...">
        </form>

        <script type="text/javascript" src="js/jquery.min.js"></script>
        <script type="text/javascript" src="js/typeahead.js"></script>
        <script type="text/javascript" src="js/global.js"></script>
    </body>
</html>

JavaScript: (js/global.js)

$(document).ready(function () {
    var accounts = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('Name'),
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        remote: "http://*****/*****/xrmservices/2011/OrganizationData.svc/AccountSet?$select=Name,AccountId&$filter=substringof('%QUERY',Name) and StateCode/Value eq 0"
    });

    accounts.initialize();

    $("#account").typeahead({
        hint: true,
        highlight: true,
        minLength: 2
    }, {
        name: 'account',
        displayKey: 'd.results[0].Name',
        source: accounts.ttAdapter()
    });

});

However: My code does not work. All I get is a text saying "undefined" under the input field. I have a suspicion that my datumTokenizer or the displayKey reference is incorrect. I don't fully understand the datumTokinizer. So if someone could enlighten me on it, I'd be thankful :)

Alexander Johansen
  • 522
  • 1
  • 14
  • 28

2 Answers2

1

You should make use of filter and use jQuery.map

html

 <input type="text" name="account" id="account" placeholder="Kunde..." />

js

$(document).ready(function () {



    var accounts = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('Name'),
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        remote: {
        url : "https://gist.githubusercontent.com/anonymous/80a75d841a055ea0e480/raw/4eb8d4f1833d8a15cae1830097c090f5d581bd12/gistfile1.txt",
        filter: function(jsonValue) {

                return $.map(jsonValue.d.results, function (result) {
                return {
                    value: result.Name
                };
            });
        }
    }     


    });

    accounts.initialize();

    $("#account").typeahead({
        hint: false,
        highlight: true,
        minLength: 2
    }, {
        source: accounts.ttAdapter()
    });

});

Fiddle here

Quannt
  • 2,035
  • 2
  • 21
  • 29
1

I found a solution to the problem. I noticed I could use a filter function in the Bloodhound object and generate an array with $.map so the Bloodhound engine could look it up like it was intended to do.

This is what my JavaScript code looks like now (The HTML is unchanged from the question):

$(document).ready(function () {
    var accounts = new Bloodhound({
        datumTokenizer: Bloodhound.tokenizers.obj.whitespace('Name'),
        queryTokenizer: Bloodhound.tokenizers.whitespace,
        remote: {
            url: "http://****/****/xrmservices/2011/OrganizationData.svc/AccountSet?$select=Name,AccountId&$filter=substringof('%QUERY',Name) and StateCode/Value eq 0",
            filter: function (accounts) {
                return $.map(accounts.d.results, function (account) {
                    return {
                        Name: account.Name,
                        AccountId: account.AccountId
                    };
                });
            }
        }
    });

    accounts.initialize();

    $("#account").typeahead({
        hint: true,
        highlight: true,
        minLength: 2
    }, {
        name: 'account',
        displayKey: 'Name',
        source: accounts.ttAdapter()
    });


    $("#account").on('typeahead:selected', function(dom, selectedItem) {
        console.log(selectedItem.AccountId);
    });
});

Hope this will help other people doing the same thing as me :)

Alexander Johansen
  • 522
  • 1
  • 14
  • 28