Autocomplete with Ajax more options than only ID and Name?


#1

is there any possibility to have more options like an object instead for an Autocomplete to use after a selection is done inside the ID in the JSON?

now autocomplete-languages.json has only two elements… ID and name

{
    "id": 0,
    "name": "country_name"
},

I tried to modify it to have more than just one value for the hidden input with an object like this:

{
    "id": [{'lng':-23434234,'lat':434234234,code:'US',iata:'MIA'}],
    "name": "country_name"
},

the problem that if doing so, the autocomplete works but cannot select any other value of the search list…

In my case it will be useful if the autocomplete Ajax can hold more element values for having all the data we need in the JSON instead of looking for this data after with a request to the db…

can autocomplete hold more options values in the JSON to use after a selection is done?

any ideas?
thanks


#2

you can play with “Autocomplete.prototype.renderItem”
(extremely not recommended)

in the meanwhile
you can use this:

[
  {
    // will be compiled as <input value="0" data-id="ok">
    "id": "0\" data-id=\"ok",
    "name": "A# .NET"
  },
  {
    // will be compiled as <input value="1" data-context='{"id":"ok","value":"ko"}'>
    "id": "1\" data-context='{\"id\":\"ok\",\"value\":\"ko\"}'",
    "name": "A# (Axiom)"
  }
]

later i’ll see for a better way


#3

Thank you for you reply!! it will be good to consider it for a better way to do that!! thanks for considering it!!! in the meantime I will use that options instead…

:slight_smile:


#4
[
  {
    "myId": "ok",
    "myValue": "ko",
    "id": 0,
    "name": "A# .NET"
  },
  {
    "myId": "okok",
    "myValue": "koko",
    "id": 1,
    "name": "A# (Axiom)"
  }
]
 
app.autocomplete.create({
  openIn: 'page', 
  openerEl: '#autocomplete-standalone-ajax',
  renderItem:function (item,index) {
    var myItem=app.utils.extend(item,this.items[index]);
    // you can/need change the tmpl to what you want
    var tmpl='<li>\
                <div class="item-content" data-value="{{value}}" data-my-id="{{myId}}" data-my-value="{{myValue}}">\
                  <div class="item-inner">\
                    <div class="item-title">{{text}}</div>\
                    <div class="item-after">{{myValue}}</div>\
                  </div>\
                </div>\
              </li>';
    return Template7.compile(tmpl)(myItem)
  }
  // other params
});

#5

it wiil be better if you’ll compile the tmpl outside (globaly)
and then only render it inside “renderItem”


#6

big thanks trying it this way as well! I think it will work too :slight_smile:


#7

when using renderItem function for autocomplete with Ajax to create my own version of template because I need to pass more than an id or name but a context of data after selecting the item … using this below make the selection unresponsive, this means the items are rendered perfectly as I want but when I select the item from the list the items is not selectable anymore and I cannot select anything from the list … this makes the autocomplete items not responding to selection…

any clues?
here your sample I used:

renderItem:function (item,index) {
var myItem=app.utils.extend(item,this.items[index]);
// you can/need change the tmpl to what you want
var tmpl=’




  • {{text}}

    {{myValue}}



  • ’;
    return Template7.compile(tmpl)(myItem)
    }

    #8

    post the html-tmpl of the item


    #9

    if I take a look in the framework7.js how the autocomplete object is created it shows in the line 28090

      itemHtml = "\n        <li>\n          <label class=\"item-radio item-content\" data-value=\"" + (item.value) + "\">\n            <div class=\"item-inner\">\n              <div class=\"item-title\">" + (item.text) + "</div>\n            </div>\n          </label>\n        </li>\n      ";
    

    in my case I need to have a radio button and close on select

    I think it is missing the radio button as well in the template definition below to be selectable but I tried my way using the itemHtml above as the template but it does not work either… :frowning:

    here the code

               // Standalone With Ajax
                      self.autocompleteStandaloneAjax = app.autocomplete.create({
                        openIn: "popup", //open in page
                        openerEl: "#destination-ajax", //link that opens autocomplete
                        closeOnSelect: true, //go back after we select something
                        multiple: false, //allow multiple values
    
                        renderItem:function (item,index) {
                          var obj=app.utils.extend(item,this.items[index]);
                          // you can/need change the tmpl to what you want
                          var tmpl='<li>\
                                      <div class="item-content" data-latlng="{{LatLng}}" data-country-code="{{CountryCode}}">\
                                        <div class="item-inner">\
                                          <div class="item-title">{{Name}}, {{CountryName}}</div>\
                                          <div class="item-after"></div>\
                                        </div>\
                                      </div>\
                                    </li>';
                          return Template7.compile(tmpl)(obj)
                        },
    
    
                        valueProperty: "ID", //object's "value" property name
                        textProperty: "Name", //object's "text" property name
                        limit: 50,
                        requestSourceOnOpen: false,
                        preloader: true, //enable preloader
                        source: function(query, render) {
                          var data = [];
    
                          var autocomplete = this;
                          var results = [];
    
                          if (query.length <= 1) {
                            results = data;
                            render(results);
                            return;
                          }
                          // Show Preloader
                          autocomplete.preloaderShow();
                          // Do Ajax request to Autocomplete data
                          console.log('query');
                          console.log(query);
    
                          app.request({
                            url: "assets/_request_cities.php",
                            method: "POST",
                            dataType: "json",
                            //send "query" to server. Useful in case you generate response dynamically
                            data: {
                              query: query
                            },
                            success: function(data) {
                              console.log(data);
                              // Find matched items
                              for (var i = 0; i < data.length; i++) {
                                if (
                                  data[i].name.toLowerCase().indexOf(query.toLowerCase()) >= 0
                                )
                                  results.push(data[i]);
                              }
                              // Hide Preoloader
                              autocomplete.preloaderHide();
                              // Render items by passing array with result items
                              console.log('autocomplete data');
                              console.log(data);
                              render(data.cities);
                            }
                          });
                        },
                        on: {
                          change: function(value) {
                            var itemText = [],
                                inputValue = [];
                            for (var i = 0; i < value.length; i++) {
                                itemText.push(value[i].Name);
                                inputValue.push(value[i].ID);
                            }
    
                            // Add item text value to item-after
                            $("#destination-ajax")
                              .find(".item-after")
                              .text(itemText.join(", "));
                            // Add item value to input value
                            $("#destination-ajax")
                              .find("input")
                              .val(inputValue.join(", "));
                          }
                        }
                      });
    

    and the json returned from the php file is this structure

    { “cities”: [ { “ID”: “LDY”, “CityCode”: “LDY”, “Name”: “Londonderry”, “LatLng”: “54.9966,-7.30857”, “CountryCode”: “GB”, “CountryName”: “United Kingdom” }, { “ID”: “84747”, “CityCode”: “84747”, “Name”: “Londonderry”, “LatLng”: “42.8651,-71.3739”, “CountryCode”: “US”, “CountryName”: “United States” }, { “ID”: “46337”, “CityCode”: “46337”, “Name”: “Londonderry”, “LatLng”: “43.2264,-72.8069”, “CountryCode”: “US”, “CountryName”: “United States” } ] }


    #10
    // do NOT change/add/remove anything
    // it will work
    self.autocompleteStandaloneAjax = app.autocomplete.create({
      openIn:'popup',
      openerEl:'#destination-ajax',
      closeOnSelect:true,
      valueProperty:'ID', 
      textProperty:'Name',
      limit:50,
      preloader:true, 
      renderItem:function(item,index){
        var obj=app.utils.extend(item,this.items[index]);
        var tmpl='<li>\
                   <label class="item-radio item-content">\
                     <input type="radio" name="{{inputName}}"\
                       value="{{value}}" {{#if selected}}checked="checked"{{/if}}>\
                     <i class="icon icon-radio"></i>\
                     <div class="item-inner">\
                       <div class="item-title">{{Name}}, {{CountryName}}</div>\
                     </div>\
                   </label>\
                 </li>';
        return Template7.compile(tmpl)(obj)
      },  
      source:function(query,render){
        if (query.length <= 1) {
          return;
        }
        var autocomplete = this;
        autocomplete.preloaderShow();
        app.request.json('assets/_request_cities.php',{query:query},function(data){
          autocomplete.preloaderHide();
          // i guess your db will sort the data based on "query"
          // so you dont need to do it again
          // just render the result
          render(data.cities);
        });
      },
      on:{
        change:function(value){
          // "value" is array of obj
          // each obj has: ID,CityCode,Name,LatLng,CountryCode,CountryName
          var itemText = [],inputValue = [];
          for (var i=0;i<value.length;i++){
            // will "store" => ID,Name,CountryCode
            inputValue.push(value[i].ID);
            itemText.push(value[i].Name+' '+value[i].CountryCode);
            // you can get also the other keys
            // console.log(value[i].LatLng);
            // console.log(value[i].CityCode);
          }
          $('#destination-ajax').find('input').val(inputValue.join(', '));
          $('#destination-ajax').find('.item-after').text(itemText.join(', '));
        }
      }
    });
    

    #11

    I will try now ! BIGGEST thanks! let you know my feedback!


    #12

    your Ajax.request didn’t work in my case so I have to do it this way:

                          app.request({
                            url: "assets/_request_cities.php",
                            method: "POST",
                            dataType: "json",
                            data: {
                              query: query
                            },
                            success: function(data) {
                              render(data.cities);
                            }
                          });
    

    then the only thing I could see that when selecting the item the item is selected and displayed in item-after correctly…

    but… there is still a strange behaviour…

    when I open the search again to look for another city the selected item is not the right one selected previously checked but the first item on the list when searching the first time…

    let us say the city I am searching is starting with

    “mada…”

    then the cities shown are:

    madaba, Jordan
    madalena, Italy

    I select madalena, Italy and then after selected I open the search again and the one selected it is the madaba, Jordan as default not madalena, Italy

    any clues?


    #13

    Also I will like to pass a context object with data after the item is selected in the data-context using your sample above:

    In my case I need to pass more than one value and it will be great if this value can be an object array instead of one value…

    is it possible to pass data-context as below too?

    thanks for any ideas…


    #14

    you dont need to pass other values
    you can get them on “change”

        change:function(value){
          // "value" is array of obj
          // each obj has: ID,CityCode,Name,LatLng,CountryCode,CountryName
          var itemText = [],inputValue = [];
          for (var i=0;i<value.length;i++){
            // will "store" => ID,Name,CountryCode
            inputValue.push(value[i].ID);
            itemText.push(value[i].Name+' '+value[i].CountryCode);
            // you can get also the other keys
            // console.log(value[i].LatLng);
            // console.log(value[i].CityCode);
          }
          $('#destination-ajax').find('input').val(inputValue.join(', '));
          $('#destination-ajax').find('.item-after').text(itemText.join(', '));
        }
    

    #15

    Sorry I got now the idea where to pass them all!!

    can you find the issue of the name selected above I explained? I am trying to find it out the issue whey It is selected wrong when opened again…

    big thanks for your attention !
    5 stars!


    #16

    i checked this code on kitchen-sink
    all works as expected

    did you change anything?


    #17

    Nope at all I only used this in the request

    app.request({
                        url: "assets/_request_cities.php",
                        method: "POST",
                        dataType: "json",
                        data: {
                          query: query
                        },
                        success: function(data) {
                          render(data.cities);
                        }
                      });
    

    the rest is the same! weird behaviour for me

    what version of framework7 you tested it out?

    thanks again!


    #18

    sorry my mistake

    renderItem:function(item,index){
      for(var i=0;i<this.items.length;i++){
        if(this.items[i]["ID"]===item["value"]){
          app.utils.extend(item,this.items[i]);
          break;
        }  
      }
      var tmpl='<li>\
                 <label class="item-radio item-content">\
                   <input type="radio" name="{{inputName}}"\
                     value="{{value}}" {{#if selected}}checked="checked"{{/if}}>\
                   <i class="icon icon-radio"></i>\
                   <div class="item-inner">\
                     <div class="item-title">{{Name}}, {{CountryName}}</div>\
                   </div>\
                 </label>\
               </li>';
      return Template7.compile(tmpl)(item)
    }
    

    #19

    here is a working example

    var data={
      cities:[
        {
          "ID":"LDY", 
          "CityCode":"LDY",
          "Name":"Londonderry",
          "LatLng":"54.9966,-7.30857",
          "CountryCode":"GB",
          "CountryName":"United Kingdom" 
        },
        {
          "ID":"84747", 
          "CityCode":"84747",
          "Name":"Londonderry",
          "LatLng":"42.8651,-71.3739",
          "CountryCode":"US",
          "CountryName":"United States" 
        },
        {
          "ID":"46337", 
          "CityCode":"46337",
          "Name":"Londonderry",
          "LatLng":"43.2264,-72.8069",
          "CountryCode":"US",
          "CountryName":"United States" 
        }
      ]
    };
    
    var html='<div id="destination-ajax">\
                <span class="item-title">test</span>\
                <input type="hidden"/>\
                <span class="item-after"></span>\
              </div>';
    Dom7('.page-content').prepend(html);
    
    var autocompleteStandaloneAjax = app.autocomplete.create({
      openIn:'popup',
      openerEl:'#destination-ajax',
      closeOnSelect:true,
      valueProperty:'ID', 
      textProperty:'Name',
      limit:50,
      preloader:true, 
      renderItem:function(item,index){
        for(var i=0;i<this.items.length;i++){
          if(this.items[i]["ID"]===item["value"]){
            app.utils.extend(item,this.items[i]);
            break;
          }  
        }
        var tmpl='<li>\
                   <label class="item-radio item-content">\
                     <input type="radio" name="{{inputName}}"\
                       value="{{value}}" {{#if selected}}checked="checked"{{/if}}>\
                     <i class="icon icon-radio"></i>\
                     <div class="item-inner">\
                       <div class="item-title">{{Name}}, {{CountryName}}</div>\
                     </div>\
                   </label>\
                 </li>';
        return Template7.compile(tmpl)(item)
      },  
      source:function(query,render){
        if (query.length <= 1) {
          return;
        }
        var autocomplete = this;
        autocomplete.preloaderShow();
        setTimeout(function(){
          autocomplete.preloaderHide();
          render(data.cities);
        },100);
        //app.request.json('assets/_request_cities.php',{query:query},function(data){
        //  autocomplete.preloaderHide();
        //  render(data.cities);
        //});
      },
      on:{
        change:function(value){
          var itemText = [],inputValue = [];
          for (var i=0;i<value.length;i++){
            inputValue.push(value[i].ID);
            itemText.push(value[i].Name+' '+value[i].CountryCode);
          }
          Dom7('#destination-ajax').find('input').val(inputValue.join(', '));
          Dom7('#destination-ajax').find('.item-after').text(itemText.join(', '));
        },
        close:function(){
          setTimeout(function(){
            autocompleteStandaloneAjax.open();
          },1000);
        }
      }
    }).open();
    

    #20

    yes this fix, fixed the issue with the selected item! BIG BIG thanks! :blush:

    renderItem:function(item,index){
    for(var i=0;i<this.items.length;i++){
    if(this.items[i][“ID”]===item[“value”]){
    app.utils.extend(item,this.items[i]);
    break;
    }
    }
    var tmpl=’



  • <input type=“radio” name="{{inputName}}“
    value=”{{value}}" {{#if selected}}checked=“checked”{{/if}}>


    {{Name}}, {{CountryName}}



  • ’;
    return Template7.compile(tmpl)(item)
    }

    Now I will try to pass all data id city code … to the next pages! let you know if I find a thing here but I think it will work now…

    BIG THANKS EVER!