Bootstrap Typeahead with AJAX source: not returning array as expected

微笑、不失礼 提交于 2020-01-04 04:30:07

问题


I am having a lot of trouble getting bootstraps typeahead to work properly with an AJAX source.

If I alert out the array that is being returned it is perfectly fine, even when I hard code it to test it. It seems to return nothing most of the time or only a few items from the array when you have typed in a near match.

Here is what I have at the moment:

$('#companyNameInput').typeahead({
      source: function(query, process){

          $.ajax({
            url: ROOT+'Record/checkCompanyName',
            async: false,
            data: 'q='+query,
            type: 'POST',
            cache: false,
            success: function(data)
            {
              companiesFinal = [];
              map = {};
              companies = $.parseJSON(data);
              $.each(companies, function(i, v){
                map[v.name] = v.id;
                companiesFinal.push(v.name);
              })
            }
          })
          process(companiesFinal);

          // return ['test1', 'test2'] This works fine
          return companiesFinal;
      }

Does anyone have an idea why this is working properly?


Here is an example of the object array returned from my PHP script. Objects with IDs 1 and 1216 show up on the typeahead dropdown, but non of the others do. I can not see any patterns or clue as to why only these would show and not the others.

[
   {
      "id": "1265",
      "score": "40",
      "name": "LMV AB"
   },
   {
      "id": "10834",
      "score": "33",
      "name": "Letona"
   },
   {
      "id": "19401",
      "score": "33",
      "name": "Lewmar"
   },
   {
      "id": "7158",
      "score": "33",
      "name": "Lazersan"
   },
   {
      "id": "3364",
      "score": "33",
      "name": "Linpac"
   },
   {
      "id": "1216",
      "score": "33",
      "name": "L H Evans Limted"
   },
   {
      "id": "1",
      "score": "33",
      "name": "LH Evans Ltd"
   },
   {
      "id": "7157",
      "score": "33",
      "name": "Lazersan"
   }
]

And finally the array that is past in process(companiesFinal):

["LMV AB", "Letona", "Lewmar", "Lazersan", "Linpac", "L H Evans Limted", "LH Evans Ltd", "Lazersan"]

Anyone have any clue? I am still totally clueless as to why this isn't working still :(


$('#companyNameInput').typeahead({
      source: function(query, process){

        companyTOut = setTimeout(function(){
          return $.ajax({
            url: ROOT+'Record/checkCompanyName',
            data: 'q='+query,
            type: 'POST',
            dataType: 'json',
            cache: false,
            success: function(data)
            {
              var count = 0;
              var companiesFinal = [];
              map = [];
              $.each(data, function(i, v){
                map[v.name] = [v.id, v.score];
                companiesFinal.push(v.name);
              })
              process(companiesFinal);

            }
          })
        }, 250)
      },
      minLength: 2,
      highlighter: function(item)
      {
        $('#companyNameInput').closest('.control-group').removeClass('success')
        companyLocked = false;
        return '<span class="unselectable" title="'+map[item].score+'">'+item+'</span>';
      },
      updater: function(item)
      {
        selectedEntityId = map[item][0];
        selectedCountryScore = map[item][1];
        lockCompany(selectedEntityId);
        return item;
      }
    });

$output .= '['.$output;
    foreach($results as $result) {
      $output .= '{"id":"'.$result['id'].'",';
      $output .= '"score":"'.$result['score'].'",';
      $output .= '"name":'.json_encode($result['name']).'},';
    }
    header('Content-Type: application/json');
    echo substr($output, 0, strlen($output)-1).']';

Console output for "parm":

[Object, Object, Object, Object, Object, Object]
0: Object
id: "25024"
name: "part"
score: "75"
__proto__: Object
1: Object
id: "15693"
name: "pari"
score: "75"
__proto__: Object
2: Object
id: "28079"
name: "Pato"
score: "50"
__proto__: Object
3: Object
id: "18001"
name: "PASS"
score: "50"
__proto__: Object
4: Object
id: "15095"
name: "PSR"
score: "33"
__proto__: Object
5: Object
id: "22662"
name: "PRP"
score: "33"
__proto__: Object
length: 6
__proto__: Array[0]

回答1:


Update 2

Ah, your service returns items that actually don't match the query parm. Your typeahead query is 'parm', with which none of the returned results match. You can override the matcher function used by the typeahead plugin, see the docs. Simply implement it as return true to match all results returned by your service.

Update 1

This is an updated version, that maps the name to an id, which can be used later. A jsfiddle is available.

var nameIdMap = {};

$('#lookup').typeahead({
    source: function (query, process) {
        return $.ajax({
            dataType: "json",
            url: lookupUrl,
            data: getAjaxRequestData(),
            type: 'POST',
            success: function (json) {
                process(getOptionsFromJson(json));
            }
        });
    },
    minLength: 1,
    updater: function (item) {
        console.log('selected id'+nameIdMap[item]);
        return item;
    }
});

function getOptionsFromJson(json) {
    $.each(json, function (i, v) {
        nameIdMap[v.name] = v.id;
    });

    return $.map(json, function (n, i) {
        return n.name;
    });
}

Original answer

You need to make the call async and call the process callback from within the success callback like this:

$('#companyNameInput').typeahead({
    source: function (query, process) {
        $.ajax({
            url: ROOT + 'Record/checkCompanyName',
            // async: false, // better go async
            data: 'q=' + query,
            type: 'POST',
            cache: false,
            success: function (data) {
                var companiesFinal = ... // snip
                process(companiesFinal);
            }
        })
    }
});

The return ['test1', 'test2']; works, because the source function is then basically set to:

// do ajax stuff, but do nothing with the result
// return the typeahead array, which the typeahead will accept as the result:
return ['test1', 'test2'];

Notes

There is a one-liner to fill companiesData:

var companiesFinal = return $.map(data, function (n, i) { n.name; });

And you probably want to declare your variables using var; otherwise they'll have global scope, which will bite you.



来源:https://stackoverflow.com/questions/15402768/bootstrap-typeahead-with-ajax-source-not-returning-array-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!