Mystery ajax request occurring somehow - javascript

Whenever I type in the autocomplete field an ajax request is sent and there is no code I've written to do this. Checking the console I see it's a 400 GET request to the controller that loaded this view with param (json) appended to the url. I'm absolutely stumped.
<head>
<script data-main="<?=base_url()?>public/requirejs/main.js" src="<?=base_url()?>public/requirejs/require-jquery.js"></script>
<script>
requirejs(['a_mod'],
function(a_mod) {
$(document).ready(function() {
var param = [];
param = $('#elem').attr('value');
a_mod.foo(param, "#someElem");
});
});
<script>
main.js
require(["jquery",
"jquery-ui"],
function() {
}
);
The autocomplete function
'foo' : function(param, elementAutocomplete, elementTags) {
console.log("init ac");
$(elementAutocomplete).autocomplete({
source: param,
minLength: 1,
select: function (event, ui) {
event.preventDefault();
//
}
}).data( "autocomplete" )._renderItem = function( ul, item ) {
return $("<li></li>")
.data( "item.autocomplete", item )
.append( '<a>' + item.label + '</a>' )
.appendTo(ul);
}
},

Your source attribute for the autocompleter is a string:
param = $('#elem').attr('value');
And a string source means that it is a URL:
Autocomplete can be customized to work with various data sources, by just specifying the source option. A data source can be:
an Array with local data
a String, specifying a URL
a Callback
Saying var param = []; just means that param is initialized as an empty array, it doesn't mean that param will always be an array. You need to fix your param value to be an array.

Related

Jquery autocomplete not filling textbox

I have an autocomplete function that filters through local json to return results to a textbox, however on selecting a location, the autocomplete does not fill the text box. I have tried to include a select method as per the docs but it breaks my functionality. Where should I include the select in my codebase?
Autocomplete function:
$('#autocomplete').autocomplete({
minLength: 1,
source: function(request, response) {
var data = $.grep(suggestion, function(value) {
return value.city.substring(0, request.term.length).toLowerCase() == request.term.toLowerCase(); // Here the suggestion array is filtered based on what the user has typed. User input will be captured in the request.term
});
response(data); // this will return the filtered data which will be attached with the input box.
}
}).data( "ui-autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "ui-autocomplete-item", item )
.append( "<a>" + item.city + "," + item.country + "</a>" )
.appendTo( ul ); // here we are creating and appending appending element based on the response object we got after filtering
};
});
Data
var suggestion =
[
{"id":"1","name":"Goroka","city":"Goroka","country":"Papua New Guinea","iata":"GKA","icao":"AYGA","latitude":"-6.081689","longitude":"145.391881","altitude":"5282","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"2","name":"Madang","city":"Madang","country":"Papua New Guinea","iata":"MAG","icao":"AYMD","latitude":"-5.207083","longitude":"145.7887","altitude":"20","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"3","name":"Mount Hagen","city":"Mount Hagen","country":"Papua New Guinea","iata":"HGU","icao":"AYMH","latitude":"-5.826789","longitude":"144.295861","altitude":"5388","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"4","name":"Nadzab","city":"Nadzab","country":"Papua New Guinea","iata":"LAE","icao":"AYNZ","latitude":"-6.569828","longitude":"146.726242","altitude":"239","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"5","name":"Port Moresby Jacksons Intl","city":"Port Moresby","country":"Papua New Guinea","iata":"POM","icao":"AYPY","latitude":"-9.443383","longitude":"147.22005","altitude":"146","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
]
The select can be placed before or after the source in your case, as long as it stays in the autocomplete object as a property. You can follow this example:
$('#autocomplete').autocomplete({
minLength: 1,
source: function (request, response) { ... },
select: function (event, ui) {
event.preventDefault();
// [...] your code here
return false;
}
}).data( "ui-autocomplete" )._renderItem = function( ul, item ) { ... };

jquery autocomplete with external json source

I have an autocomplete function that was working with a local json source. Given that it's 16k lines of code, I want to move this to an external json file. However I can't seem to get it working with the external source file. Can anyone point me in the right direction? At the moment this code does not work, but also does not return any errors to the console.
Autocomplete script
$(function() {
$.ajax({
url: "javascripts/airports.json",
dataType: "json",
success: function(request, response) {
var data = $.grep(suggestion, function(value) {
return value.city.substring(0, request.term.length).toLowerCase() == request.term.toLowerCase();
});
$('#autocomplete').autocomplete({
minLength: 1,
source: data,
focus: function(event, ui) {
$('#autocomplete').val(ui.item.city,ui.item.country);
return false;
},
select: function(event, ui) {
$('#autocomplete').val(ui.item.name);
return false;
}
}).data( "ui-autocomplete" )._renderItem = function( ul, item ) {
return $( "<li></li>" )
.data( "ui-autocomplete-item", item )
.append( "<a>" + item.city + "," + item.country + "</a>" )
.appendTo( ul );
};
}
});
});
External data structure
var suggestion =
[
{"id":"1","name":"Goroka","city":"Goroka","country":"Papua New Guinea","iata":"GKA","icao":"AYGA","latitude":"-6.081689","longitude":"145.391881","altitude":"5282","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"2","name":"Madang","city":"Madang","country":"Papua New Guinea","iata":"MAG","icao":"AYMD","latitude":"-5.207083","longitude":"145.7887","altitude":"20","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"3","name":"Mount Hagen","city":"Mount Hagen","country":"Papua New Guinea","iata":"HGU","icao":"AYMH","latitude":"-5.826789","longitude":"144.295861","altitude":"5388","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"4","name":"Nadzab","city":"Nadzab","country":"Papua New Guinea","iata":"LAE","icao":"AYNZ","latitude":"-6.569828","longitude":"146.726242","altitude":"239","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
,
{"id":"5","name":"Port Moresby Jacksons Intl","city":"Port Moresby","country":"Papua New Guinea","iata":"POM","icao":"AYPY","latitude":"-9.443383","longitude":"147.22005","altitude":"146","timezone":"10","dst":"U","tz":"Pacific/Port_Moresby"}
]
Your response should be a JSON object (array) where each item is an object with id, label and value keys.
The items in your json files doesn't have the label and value keys, so the autocomplete can't really show them.
Best solution - change the content of the file/response to follow the id/label/value structure.
If you can't do this - you can use the _renderItem function to create your own items in the autocomplete based on the content of the json file:
$('#autocomplete').autocomplete({
...
_renderItem: function( ul, item ) {
return $( "<li>" )
.append( item.name )
.appendTo( ul );
}
...
});

How to combine two similar scripts and run it with slight variations

I have the following two scripts:
The first one, on grabs a keyword from input#search and populates a dropdown#search-results with the results from the ajax call for that keyword.
$(document.body).on( 'keyup', '#search', function ( e ) {
//e.preventDefault();
value = $(this).val(); //grab value of input text
jQuery.ajax({
url : ajaxsearch.ajax_url,
type : 'post',
data : {
action : 'search_client',
key : value,
},
success : function( response ) {
response = jQuery.parseJSON(response);
//console.log(response);
$.each(result, function(k, v) {
$('#search-results').append('<li>' + v['Name'] + '</li>');
});
}
});
});
The second script, grabs the value of the clicked dropdown result, does the same action as the first script only this time the ajax result is used to populate fields located on the page.
$(document.body).on('click','#search-results > li', function ( e ) {
//e.preventDefault();
value = $( this ).text(); //grab text inside element
jQuery.ajax({
url : ajaxsearch.ajax_url,
type : 'post',
data : {
action : 'search_client',
key : value,
},
success : function( response ) {
response = jQuery.parseJSON(response);
//console.log(response);
$.each(response, function(k, v) {
$('#clientID').val( v['ClientId'] );
$('#denumire').val( v['Name'] );
$('#cui').val( v['CUI'] );
$('#regcom').val( v['JRegNo'] );
$('#adresa').val( v['Address'] );
$('#iban').val( v['IBAN'] );
$('#banca').val( v['Bank'] );
$('#telefon').val( v['Phone'] );
$('#pers-contact').val( v['Contact'] );
});
}
});
});
Is there a way to combine the second script into the first one so not to make the second ajax call, but be able to populate the fields on the page with the results from the first ajax call depending on the clicked result in the dropdown list?
If the text you insert from v['Name'] into the list item in the first script is the exact same thing you want to use elsewhere in the page in the second script, you can reduce the code way, way down. After all, if you already have the value you want, there's no need to go search for it again.
//first function, just the relevant bits...
$.each(result, function(k, v) {
var newItem = $('<li>' + v['Name'] + '</li>');
$.data(newItem, "value", v);
$('#search-results').append(newItem);
});
//second function, the whole thing
$(document.body).on('click','#search-results > li', function ( e ) {
e.preventDefault();
var v = $.data($( this ), "value"); //grab object stashed inside element
$('#clientID').val( v['ClientId'] );
$('#denumire').val( v['Name'] );
$('#cui').val( v['CUI'] );
$('#regcom').val( v['JRegNo'] );
$('#adresa').val( v['Address'] );
$('#iban').val( v['IBAN'] );
$('#banca').val( v['Bank'] );
$('#telefon').val( v['Phone'] );
$('#pers-contact').val( v['Contact'] );
});
This should let you store the entire result object into the list item, then retrieve it later. If you have some elements in that list that you're not putting there with searches, you'll have to do some more work to get their relevant data too.

cannot get the results to be displayed on the page

I cannot display the results which I got from database:
{"results": ["USA", "Canada"]}
{"message":"Could not find any countries."} //else
I got this error from console:
Uncaught TypeError: Cannot read property 'length' of undefined.
Could you please check my code to find out what is my mistake.
Here is my view:
My Travel Plans
<div id="my_div">
<div id="country_list_is_got"></div>
<div id="country_list_is_not_got"></div>
</div>
Controller:
if ($this->my_model->did_get_country_list($user_id)) {
$country["results"]= $this->model_users->did_get_country_list($user_id);
echo json_encode($country);
}
else {
$country = array('message' => "Could not find any countries." );
echo json_encode($country);
}
JS file:
$("#load_country_list").click(function() {
$.post('cont/get_country_list', function (country) {
if (country.message !== undefined) {
$( "#country_list_is_not_got").text(country.message);
} else {
$.each(country.results, function(i, res) {
var item = $('<div>'),
title = $('<h3>');
title.text(res);
item.append(title);
item.appendTo($("#country_list_is_got"));
});
}
});
});
You need to tell jQuery what content type is coming back from the server (json)
It defaults to 'string' and it has no reason to think that's incorrect.
See the documentation for the correct parameter order.
Your .each iterator is trying to loop over a string, and - obviously - failing.
Edit: As a point of pedantry, why are you using POST to GET data? "Get" is literally in your URL.
I think it should be $.get or the $.getJSON shortcut, instead of $.post
$.getJSON("cont/get_country_list", function( data ) {
console.log(data);
// something like this for list construction and append to body
var countries = [];
// maybe you need data.results here, give it a try or see console
$.each( data, function( key, val ) {
countries.push( "<li id='" + key + "'>" + val + "</li>" );
});
$( "<ul/>", {
"class": "country-list",
html: countries.join( "" )
}).appendTo( "body" );
});
Live Demotry this, issue is results contain array.but you try to use key,value
if (country.message !== undefined) {
$( "#country_list_is_not_got").text(country.message);
} else {
for(i=0;i<country.results.length;i++){
var item = $('<div>'),
title = $('<h3>');
title.text(country.results[i]);
item.append(title);
item.appendTo($("#country_list_is_got"));
}
}

Intercept and pre-process jQuery-ui autocomplete data

I have a Jquery UI autocomplete code that grabs data from an ajax request, as i grab the data the results are already put in the input box where the autocomplete is attached. my problem is i have a other data along the data that will be posted with the result of the autocomplete.
I had tried to grab all the i need and put it in a single string with delimeters so i can split() it on the client-side. I want to save the other data in a hidden text field
here is my code
<div id="01ac091c834d81b41f0ef4b6eb09cde90bb9aa1a" style="display:none" title="Add Member">
Type the name of the member
<br>
<br>
<div style="text-align:center">
<input type="text" id="txtUserFind" size="35">
</div>
<input type="hidden" id="hidtxtUserFind-nickname">
<input type="hidden" id="hidtxtUserFind-userhash">
<input type="hidden" id="hidtxtUserFind-picture">
<input type="hidden" id="hidtxtUserFind-sex">
</div>
<script type="text/javascript">
head(function() {
$(":button:contains('Select User')").attr("disabled","disabled").addClass("ui-state-disabled");
$("#txtUserFind").keydown(function(){
$(":button:contains('Select User')").attr("disabled","disabled").addClass("ui-state-disabled");
});
$("#txtUserFind").change(function(){
var userdetails = $("#txtUserFind").val().split(";");
alert($("#txtUserFind").val());
/*
0 profiles.nickname,
1 profiles.firstname,
2 profiles.surname,
3 users.user_hash,
4 profiles.sex,
5 profiles.picture
*/
$("input#hidtxtUserFind-nickname").val(userdetails[0]);
$("input#txtUserFind").val(userdetails[1] + " " + userdetails[2]);
$("input#hidtxtUserFind-userhash").val(userdetails[3].replace("u-",""));
$("input#hidtxtUserFind-sex").val(userdetails[4]);
if(userdetails.length > 5){
$("input#hidtxtUserFind-picture").val(userdetails[5]);
}
});
$("<?php echo $tagmemberbtn; ?>").click(function(){
$("#01ac091c834d81b41f0ef4b6eb09cde90bb9aa1a").dialog({
modal:true,
resizable: false,
height:250,
width:400,
hide:"fade",
open: function(event, ui){
searchdone = false;
$(":button:contains('Select User')").attr("disabled","disabled").addClass("ui-state-disabled");
},
beforeClose: function(event, ui){
$("#txtUserFind").val("");
},
buttons:{
"Select User":function(){
$(this).dialog("close");
},
"Close":function(){
searchdone = false;
$("#txtUserFind").val("");
$(this).dialog("close");
}
}
});
});
$(function() {
var cache = {},
lastXhr;
$("#txtUserFind").autocomplete({
source:function(request,response) {
var term = request.term;
if ( term in cache ) {
response(cache[term]);
return;
}
lastXhr = $.getJSON(cvars.userburl+"getusers", request, function(data,status,xhr) {
stopAllAjaxRequest();
cache[ term ] = data;
if ( xhr === lastXhr ) {
response( data );
}
});
},
minLength: 1,
select: function(event, ui) {
$(":button:contains('Select User')").removeAttr("disabled").removeClass("ui-state-disabled");
}
}).data("autocomplete")._renderItem = function(ul,item){
if(item.picture==null){
//know if girl or boy
if(item.sex<=0){
item.picture = cvars.cthemeimg + "noimagemale.jpg";
}
else{
item.picture = cvars.cthemeimg + "noimagefemale.jpg";
}
}
else{
item.picture = cvars.gresuser + "hash=" + item.user_hash.replace("u-","") +"&file="+item.picture.replace("f-","");
}
var inner_html = '<a><div class="autocomplete-users-list_item_container"><div class="autocomplete-users-image"><img src="' + item.picture + '" height="35" width="35"></div><div class="label">' + item.nickname + '</div><div class="autocomplete-users-description">' + item.firstname + " " + item.surname + '</div></div></a>';
return $("<li></li>")
.data("item.autocomplete",item)
.append(inner_html)
.appendTo(ul);
};
});
});
You idea is right, you must use a callback as the source parameter. I've put together an example here:
Demo on jsFiddle
If you read the documentation carefully it says:
The third variation, the callback, provides the most flexibility, and
can be used to connect any data source to Autocomplete. The callback
gets two arguments:
A request object, with a single property called "term", which refers
to the value currently in the text input. For example, when the user
entered "new yo" in a city field, the Autocomplete term will equal
"new yo".
A response callback, which expects a single argument to contain the
data to suggest to the user. This data should be filtered based on the
provided term, and can be in any of the formats described above for
simple local data (String-Array or Object-Array with label/value/both
properties). It's important when providing a custom source callback to
handle errors during the request. You must always call the response
callback even if you encounter an error. This ensures that the widget
always has the correct state.
So here is an example implementation I used in the demo:
$("#autocomplete").autocomplete({
source: function(request, response) {
$.ajax({
url: "/echo/html/", // path to your script
type: "POST", // change if your script looks at query string
data: { // change variables that your script expects
q: request.term
},
success: function(data) {
// this is where the "data" is processed
// for simplicity lets assume that data is a
// comma separated string where first value is
// the other value, rest is autocomplete data
// the data could also be JSON, XML, etc
var values = data.split(",");
$("<div/>").text("Other value: " + values.shift()).appendTo("body");
response(values);
},
error: function() {
response([]); // remember to call response() even if ajax failed
}
});
}
});
You can include a function on select. Within that function you can access the value and the label of the selected item and process as needed:
$('#input_id').autocomplete({
source:"www.example.com/somesuch",
select: function(event, ui){
var value = ui.item.value;
valueArray = value.split('whatever delimiter here');
//do what you will with the values
ui.item.value = ui.item.label; //This ensures only the label is displayed after processing.
}
});

Categories

Resources