Autocomplete - change lookup/serviceurl based on dropdown selection - javascript

I have a dropdown with multiple options to select. When I select value1 (company), autocomplete should use the service call. When I select value2, lookup should be used.
How can I implement this?
$('#qckSearchKeyword').autocomplete({
serviceUrl: function() {
var option = $('#qck-unspsc').val();
if (option == "country") {
// when country selected through drop down i should use lookup rather then service call
serviceloc = "getCountries";
localStorage.option = "country";
}
if (option == "industry") {
serviceloc = "getSicCode";
localStorage.option = "sicCode";
}
return serviceloc;
},
onSelect: function(suggestion) {
localStorage.tmpSelectedTxt = $.trim($('#qckSearchKeyword').val());
$('#selectFromSuggestions').val("true");
$('#qckSearchKeyword').focus();
},
paramName: "searchTerm",
delimiter: ",",
minChars: 3,
transformResult: function(response) {
// alert(response);
return {
suggestions: $.map($.parseJSON(response), function(item) {
return {
value: item.suggesCode,
data: item.suggesString
};
})
};
}
});

Split up the options for the different autocomplete calls.
Use a data-type on the options you select.
Switch the data-type and extend the proper options
Init autocomplete with proper options
I simply copy/pasted some configuration I've done in the past for this functionality:
...
ajaxOptionsFlight: {
url: '/api/autocomplete/airport/',
type: 'get',
dataType: 'xml'
},
ajaxOptionsHotel: {
url: '/api/locations/hotel/',
type: 'get',
dataType: 'xml'
},
ajaxOptionsCitytrip: {
url: 'http://budapest.onlinetravel.ch/destfinder',
dataType: 'jsonp',
data: {
vendors: 'merger',
client: 'conbe',
filter: 'IATA',
format: 'json',
language: 'en'
}
},
ajaxOptionsCar: {
url: '/api/locations/car/',
dataType: 'json'
},
ajaxOptionsSubstitute: {
url: 'http://gd.geobytes.com/AutoCompleteCity',
dataType: 'jsonp'
},
autocompleteOptions: {
autoFocus: true,
minLength: 1
},
....
After that I make sure I can switch on data-type and hook it on the source parameter of the autocomplete options:
autocompleteOptions = $.extend({}, autocompleteOptions, {
source: type === 'citytrip' ? function (request, response) {
ajaxOptions = $.extend(true, {}, ajaxOptionsCitytrip, {
data: {
name: $.trim(request.term),
language: cookieLanguage
},
success: function (d) {
response($.map(d.Destinations, function (item) {
return {
label: item.name + ', ' + item.country,
value: item.name,
code: item.olt_id
};
}));
}
});
$.ajax(ajaxOptions);
} : type === 'flight' ? function (request, response) {
ajaxOptions = $.extend({}, ajaxOptionsFlight, {
url: ajaxOptionsFlight.url + $.trim(request.term),
success: function (d) {
response($.map($(d).find('airport'), function (item) {
return {
label: $(item).children("displayname").text(),
value: $(item).children("displayname").text(),
code: $(item).children("code").text()
};
}));
}
});
$.ajax(ajaxOptions);
} : type === 'hotel' ? function (request, response) {
// and so on ...
}
});
Not the most elegant way of writing, I admit. But it's basically a simple mapping between data-type and configuration options to provide for autocomplete.
In the end I only call:
input.autocomplete(autocompleteOptions);
And we're done. Hope that makes sense.

Related

Ext js 7 modern, form.submit vs ajax.request

I have a Ext.form.Panel with multiple textareafield and fileinput like this
// https://requestbin.com/r/en0ej96odon2sm/1n6r1tb49KK6eObGMPHlYa1hh4C
Ext.create({
xtype: 'formpanel',
renderTo: document.body,
buttons: {
submit: 'onSubmit',
},
controller: {
onSubmit: function () {
var form = this.getView();
form.submit({
method: 'POST',
url: 'https://en0ej96odon2sm.x.pipedream.net/test1',
success: function () {}
});
},
onSubmitTest: function () {
var form = this.getView();
Ext.Ajax.request({
url: 'https://en0ej96odon2sm.x.pipedream.net/test2',
method: 'POST',
params: {
data: form.getValues(),
},
success: function () {}
});
},
},
items: [{
xtype: 'textareafield',
name: 'testfield',
label: 'testfield',
value: 'test\nasd',
}, {
xtype: 'filefield',
label: 'Upload Test',
name: 'basedata-test',
}, {
xtype: 'button',
text: 'Ajax.request(), linebreaks but no files',
handler: 'onSubmitTest',
}]
});
Post Results:
https://requestbin.com/r/en0ej96odon2sm/1n6mtu8QtyreaisCAmV3csO724Q
Fiddle:
https://fiddle.sencha.com/#view/editor&fiddle/3b9j
So, cause i need fileinput/multipart, I have to use form.submit({}).
But when I do so, I don't get the linebreaks on Server side in my $_POST Var.
When I do a ajax.request({}) everything looks good, but $_FILES are missing, so this is not really an option. (but this is documented).
I also tried adding jsonSubmit to the form (then I get no $_POST at all).
When I add enableSubmissionForm: false I get the newline, but after submit the form disappears (and I don't know why).
Is there a solution for this or am I doing something wrong?
You can use the following override. Hope it will not make the framework unstable ;)
// https://requestbin.com/r/en0ej96odon2sm/1n6r1tb49KK6eObGMPHlYa1hh4C
// Override
Ext.define('overrides.form.Panel', {
override: 'Ext.form.Panel',
privates: {
createSubmissionForm: function (form, values) {
var fields = this.getFields(),
name, input, field, fileTrigger, inputDom;
if (form.nodeType === 1) {
form = form.cloneNode(false);
for (name in values) {
input = document.createElement('textarea');
input.setAttribute('type', 'string');
input.setAttribute('name', name);
input.innerHTML = values[name];
form.appendChild(input);
}
}
for (name in fields) {
if (fields.hasOwnProperty(name)) {
field = fields[name];
if (field.isFile) {
// The <input type="file"> of a FileField is its "file" trigger button.
fileTrigger = field.getTriggers().file;
inputDom = fileTrigger && fileTrigger.getComponent().buttonElement.dom;
if (inputDom) {
if (!form.$fileswap) {
form.$fileswap = [];
}
input = inputDom.cloneNode(true);
inputDom.parentNode.insertBefore(input, inputDom.nextSibling);
form.appendChild(inputDom);
form.$fileswap.push({
original: inputDom,
placeholder: input
});
}
} else if (field.isPassword) {
if (field.getInputType() !== 'password') {
field.setRevealed(false);
}
}
}
}
return form;
}
}
});
Ext.create({
xtype: 'formpanel',
renderTo: document.body,
buttons: {
submit: 'onSubmit',
},
controller: {
onSubmit: function () {
var form = this.getView();
form.submit({
method: 'POST',
url: 'https://en0ej96odon2sm.x.pipedream.net/test1',
success: function () {}
});
},
onSubmitTest: function () {
var form = this.getView();
Ext.Ajax.request({
url: 'https://en0ej96odon2sm.x.pipedream.net/test2',
method: 'POST',
params: {
data: form.getValues(),
},
success: function () {}
});
},
},
items: [{
xtype: 'textareafield',
name: 'testfield',
label: 'testfield',
value: 'test\nasd',
}, {
xtype: 'filefield',
label: 'Upload Test',
name: 'basedata-test',
}, {
xtype: 'button',
text: 'Ajax.request(), linebreaks but no files',
handler: 'onSubmitTest',
}]
});
Not ideal, but you also can do this:
form.submit({
method: 'POST',
//just like the ajax
params: {
data: form.getValues(),
},
url: 'https://en0ej96odon2sm.x.pipedream.net/test1',
success: function () {}
});
Here is a simple workaround for using Ajax.request instead of form.submit
I needed that because I have to set an Authorization header, which can't be done with IFRAME used by the framework
So preventing Ext.data.request.Ajax from setting Content-Type header seems to do the job.
multipart/form-data will be automatically set.
Warning : neither options.headers nor defaultHeaders should already have the 'Content-Type' header
Ext.define('Override.data.request.Ajax', {
override: 'Ext.data.request.Ajax',
setupHeaders: function(xhr, options, data, params) {
if (data instanceof FormData) {
if (Ext.apply({}, options.headers || {}, this.defaultHeaders).hasOwnProperty('Content-Type')) {
console.warn('The Content-Type header must not be set before request if you need to use FormData with this override');
}
/* prevent Ext.data.request.Ajax from setting Content-Type header */
return this.callParent([xhr, options, null, null]);
} else {
return this.callParent(arguments);
}
}
});
And call Ajax.request with a FormData as rawData
var formData = new FormData();
var files = myView.down('filefield').getFiles();
if (files.length > 0) {
formData.append('file', files[0], files[0].name);
}
Ext.Ajax.request({
url: 'your_url',
rawData: formData,
success: function(response) {
// handle success
},
failure: function(response) {
// handle failure
}
});

select2 won't show me results after transforming data into the required format

I use ajax call to fetch data from server and display the results via select2. The problem is that the fetched data is structured in a way that needs to be transformed for select2 to process it correctly.
When I transform data following their documentation, it won't show me the results.
The structure of the response:
{
type1: [{result1}, {result2}, {result3}...],
type2: [{result1}, {result2}, {result3}...],
type3: [{result1}, {result2}, {result3}...]
}
Select2 expects data to be: {"results": [{result1}, {result2}, {result3}...]}
My code:
function formatParent(parent) {
return parent.title || parent.text
}
Ember.$('#parent-select').select2({
ajax: {
url: '/api/parents/' + type,
headers: headers,
dataType: 'json',
data: function (params) {
let query = {
q: params.term,
}
return query;
},
processResults: function (data) {
const res = []
for (let property in data) {
if (data.hasOwnProperty(property)) {
res.push({
"text": property,
"children": data[property]
})
}
}
return res
}
},
width: 'resolve',
theme: 'bootstrap',
escapeMarkup: function (markup) {
return markup;
},
minimumInputLength: 1,
templateResult: formatParent,
templateSelection: formatParent
})
<select
data-tags="true"
data-placeholder={{placeholder}}
id="parent-select"
style="width: 100%;">
</select>
When I transform the data as presented below the results appear in the dropdown without any problems:
function formatParent(parent) {
return parent.title || parent.text
}
Ember.$('#parent-select').select2({
ajax: {
url: '/api/parents/' + type,
headers: headers,
dataType: 'json',
data: function (params) {
let query = {
q: params.term,
}
return query;
},
processResults: function (data) {
return {"results": data.type1}
}
},
width: 'resolve',
theme: 'bootstrap',
escapeMarkup: function (markup) {
return markup;
},
minimumInputLength: 1,
templateResult: formatParent,
templateSelection: formatParent
})

Unable to preselect value on select2

I'm using this library
https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.full.js">
I know there are a lot of examples out there and I've tried them all most recent:
var $client_id = $("#client_id").select2({
dropdownParent: $('#categoryForm'),
ajax: {
quietMillis: 300,
url: apiPath,
xhrFields: {
withCredentials: true
},
crossDomain: true,
type: "GET",
data: function (params) {
var queryParameters = {
search: params.term
}
return queryParameters;
},
processResults: function (data) {
return {
results: $.map(data.data, function (item) {
return {
text: item.client_name,
id: item.client_id
}
})
};
}
}
});
$client_id.val(6).trigger('change');
As you can see at the bottom I'm trying to select the value using the (valid) ID. I have been successfull using this method:
var option = new Option(data.customer_name, data.customer_id, true, true);
customerSelect.append(option).trigger('change');
But I'd rather just use the ID if it's possible

jquery ui autocomplete displays only first item in db

Am using JQuery Autocomplete on my templete, but as i get the results the Autocomplete only displays one item despite that the results that are fetched have more that one item. It only shows the first item on the list!
Example:
if i have a result list with ('type1', 'type2', 'type3')
and on the autocomplete i type 't' it only displays type1 on the drop down!
I am a newbie in jquery kindly rectify my mistakes( if any)
My autocomplete code:
$(".fro").each(function() {
$(this).autocomplete({
source : function(request, response) {
$.ajax({
serviceUrl: '${pageContext.request.contextPath}/index.htm',
datatype: "json",
paramName: "fro",
delimiter: ",",
data : {
term : request.term
},
success : function(data) {
response($.map(data.result, function(item) {
$.each(data, function() {
return {
label : this.fro,
value : this.fro
}
});
}));
}
});
},
minLength:1
});
});
My response controller looks like this:
#RequestMapping(value = "/getTags.htm", method = RequestMethod.GET, headers="Accept=*/*")
public #ResponseBody List<SearchFiller> getTags(#RequestParam("fro") String fro) {
return simulateSearchResult(fro);
}
private List<SearchFiller> simulateSearchResult(String fro) {
List<SearchFiller> data=searchFlightDao.fillerList();
List<SearchFiller> result = new ArrayList<SearchFiller>();
for (SearchFiller tag : data) {
if (tag.getFro().contains(fro)) {
result.add(tag);
}
}
return result;
}
Right answer gets appreciated
Let you try this:
$(".fro").each(function() {
$(this).autocomplete({
source : function(request, response) {
$.ajax({
serviceUrl: '${pageContext.request.contextPath}/index.htm',
datatype: "json",
paramName: "fro",
delimiter: ",",
data : {
term : request.term
},
success : function(data) {
dataArray = new Array();
$.each(data, function() {
var t = { label : this.fro, value : this.fro };
dataArray.push(t);
});
response(dataArray);
}
});
},
minLength:1
});
});

Set selected value on select2 without loosing ajax

I have this select2 code in my html (mvc with razor) page:
$('#QuickSearchState').select2({
minimumInputLength: 3,
width: 'resolve',
ajax: {
url: '#Url.Action("QuickSearchState", "DataCenter")',
contentType: 'application/json',
dataType: 'json',
type: 'POST',
traditional: true,
quietMillis: 400,
data: function(term, page) {
var data = {
term: term
};
return data;
},
results: function(data, page) {
return { results: data };
}
},
initSelection: function(element, callback) {
var data = { id: element.val(), text: element.val() };
callback(data);
},
formatResult: function(format) {
return format.label;
},
formatSelection: function(format) {
//this is a knockout view model
vmNewAddress.IdState(format.id);
vmNewAddress.StateName(format.stateName);
return format.label;
},
dropdownCssClass: "bigdrop",
escapeMarkup: function(m) { return m; }
});
But i have another select in my code that can set a state in this select, but i dont know how to set this value to that select.
In my html i have this:
<select class="width-xl" data-bind="options: vm.GivenLocationsForConnection, optionsText: 'DisplayFormat', value: SelectedLocation"></select> -> first select that can fill the second state search select with a state
#Html.Hidden("query", null, new { #id = "QuickSearchState", #class = "width-xl", placeholder = "Ej. Montevideo" }) -> second select, this is a search for states and selects a single state
I am not sure if this is what you want but if you only want to select a value in the select you can just do below
$("#QuickSearchState").select2("val", "<YOUR VALUE>");

Categories

Resources