I am having a serious problem with trying to use a jquery autocomplete and javascript is not my strongest skill.
I am using the jquery.auto-complete plugin found here:
https://github.com/Pixabay/jQuery-autoComplete which is a rewrite of the devbridge.com version.
so far, getting it to work has been no problem, but now i am stuck with a problem and really need some help.
i have a form for data entry for a very large database. nothing special, but a very large database with lots of fields and about 80% of the data is simple text fields that have very similar or duplicated values, but still varied enough that nothing really other than an autocomplete will make life easier. this can be very time consuming and tedious, especially when database is 1M+ records.
so since i have around 40 fields that require lookups, this is my current code:
$(window).on('load', function () {
var xhr;
$('[data-autocomplete]').autoComplete({
source: function(term, response){
try { xhr.abort(); } catch(e){}
xhr = $.get( '/api.php',
{ field: $(this).attr('data-autocomplete'),
search: term,
}, function(data){ response(data); });
}
});
...
and this is my field:
<input type="text" name="data[title]" id="data[title]" data-autocomplete="title" />
but for some reason, i can't get the value of the attribute "data-autocomplete" to be passed to the autocomplete function. it just comes up as undefined and that is critical for the search
what i need is a way that i can bind the autocomplete on page load to any text input with an attribute of "data-autocomplete" (so far so good) and then pass that value to the autocomplete thus creating an url of:
api.php?field=[data-autocomplete]&search=[term]
sounds simple, but seems to be exceedingly difficult. my other option is to duplicate the autocomplete statements some 40+ times and that just seems ridiculous!
so can somebody please give me some direction? thank you!
Loop over the elements in an each loop so you can isolate instances.
$('[data-autocomplete]').each(function() {
let xhr,
$input = $(this),
field = $input.attr('data-autocomplete');
$input.autoComplete({
source: function(term, response) {
try {
xhr.abort();
} catch (e) {}
xhr = $.get('/api.php', { field: field, search: term}, response);
}
});
});
The first thing I notice is that you have an erroneous comma after the variable "term" in your get call:
xhr = $.get( '/api.php',
{
field: $(this).attr('data-autocomplete'),
search: term, <-- code-breaking comma.
}, function(data){ response(data); });
It's also possible that your get call's reference to this is no longer refferring to the expected object.
Try something like this instead:
$( window ).on( 'load', function () {
let xhr, me = this;
$( '[data-autocomplete]' ).autoComplete( {
source: function( term, response ) {
try { xhr.abort(); } catch( e ){}
xhr = $.get( '/api.php',
{
field: $( me ).attr( 'data-autocomplete' ),
search: term
},
function( data ){ response( data );
} );
}
} );
} );
Related
I have an autocomplete field, and on type I go to the PHP/Database to retrieve the matching options.
Thing is, my suggestion list isn't exactly matches of the text. I explain:
Say I type "Jon". My list will bring from the database "John Doe", "Jonatan", etc. Only "Jonatan" will be visible as the suggestion to the input, but I do need them all, because it considers approximation (there's a soundex element on my backend search).
My JavaScript/Ajax code:
function prePatientsList(){
//I'm limiting search so it only starts on the second character
if (document.getElementById("name").value.length >= 2) {
try
{
listExecute.abort();
}catch(err) {
null;
}
var nome= $("#name").val();
var nomeList = "";
listExecute = $.ajax({
url: '/web/aconselhamento/Atendimento/PrePacientesAutocomplete',
type: "POST",
async: true,
datatype: 'json',
data: { nome: nome}
}).done(function(data){
source = JSON.parse(data);
});
$(function() {
$("input#nome").autocomplete({
source: source,
// I know I probably don't need this, but I have a similar component which has an URL as value, so when I select an option, it redirects me, and I'll apply you kind answer on both.
select: function( event, ui ) {
ui.item.label;
}
});
});
}
}
Thanks.
I think you'd have to set your remote endpoint directly as the autocomplete's source (e.g. similar to https://jqueryui.com/autocomplete/#remote) so that it's the backend which does all the filtering. Right now, the autocomplete effectively thinks you've fed it a static list of options from which further filtering should take place, and therefore it decides to handle the filtering itself.
Your code can be as simple as this I think, no need to have a separate handler or an ajax request outside the scope of the autocomplete.
$(function() {
$("input#nome").autocomplete({
minLength: 2, //limit to only firing when 2 characters or more are typed
source: function(request, response)
{
$.ajax({
url: '/web/aconselhamento/Atendimento/PrePacientesAutocomplete',
type: "POST",
dataType: 'json',
data: { nome: request.term } //request.term represents the value typed by the user, as detected by the autocomplete plugin
}).done(function(data){
response(data); //return the data to the autocomplete as the final list of suggestions
});
},
// I know I probably don't need this, but I have a similar component which has an URL as value, so when I select an option, it redirects me, and I'll apply you kind answer on both.
select: function( event, ui ) {
ui.item.label;
}
});
});
See http://api.jqueryui.com/autocomplete/#option-source for more info.
I am trying out a small JavaScript library, SnackJS and am doing pretty well. But I've hit a wall, and can't seem to figure this one out:
Snack:
<script type="text/javascript">
snack.ready(function () {
var parameters = {
node: document.body,
event: 'change',
delegate: function (node) {
return node.getElementsByClassName("qty")
}
}
snack.listener(parameters, postToOtherPage);
function postToOtherPage() {
var options = {
method: 'post',
url: '/InlineEditing',
data: {
qty: 5,
id: "hi"
}
}
}
});
</script>
My question is, on the change event of an input element, how do I post the id of the element, along with that element's value (qty) to another page?
I did look through the documentation, but I can't quite figure it out.
You're missing a
snack.request(options, callback);
call. A part from that, your code looks fine.. what's wrong with it?
Update
oh, I see you're not retrieving the id from the element.. from the docs: the first argument to event callback is the node which fired the event, so:
snack.ready(function () {
var parameters = {
node: document.body,
event: 'change',
delegate: function (node) {
return node.getElementsByClassName("qty")
}
}
snack.listener(parameters, postToOtherPage);
function postToOtherPage(event) {
var options = {
method: 'post',
url: '/InlineEditing',
data: {
qty: 5,
id: this.id
}
}
snack.request(options, function(){
// do something with response..
});
}
});
should work fine..
Update
Nope, sorry, further reading the docs I found out they're using callback.apply(this, [event]), as usual.. updated code above.
By the way, I don't see the point in using this kind of micro-libraries instead of well-established libraries such as jQuery/Zepto, since the pros of the micro-libaries in terms of size are not worth IMO the disadvantages.
Consider that "larger" libaries:
have a lot more features: what about the day you'll decide to extend your application functionality more?
have a larger community/commercial-based support: books, reference, guides, ...
are more likely to have already solved problems/issues that are still there in micro libraries. Just think of the hundreds of cross-browser compatibility hacks...
However, this one is just my opinion, just take it as my personal advice.
I have used JQuery UI autocomplete to cut down on the list of parts I have to display in a drop down, I am also using json to pass the list of parts back but I am failing to see the results, I am sure this is to do with my limited understanding of JQuery's Map function.
I have the following json
{"parts":[{"partNumber":"654356"},{"partNumber":"654348"},{"partNumber":"654355-6"},{"partNumber":"654355"},{"partNumber":"654357"},{"partNumber":"654357-6"},{"partNumber":"654348-6"}]}
which on JSONLint is validated correct
I have viewed the post and response utilising Firebug and seen them to be correct but my auto complete does not seem to display, the closest I have got it to doing so, was when I displayed the entire JSON string with each character having a new line.
here is my JS
$('.partsTextBox').autocomplete({
minLength: 3,
source: function(request, response) {
$.ajax({
url: './PartSearch.ashx',
data: $('.partsTextBox').serialize(),
datatype: 'JSON',
type: 'POST',
success: function(data) {
response($.map(data, function(item) {
return { label: item.partNumber }
}))
}
});
},
select: function(e) {
ptb.value = e;
}
});
Any help anyone can give would be much appreciated. Have edited to include help given by soderslatt
I'm not sure, but shouldn't parts.part be an array ?
http://jsfiddle.net/jfTVL/3/
From the jQuery autocomplete page:
The local data can be a simple Array of Strings, or it contains Objects for each item in the array, with either a label or value property or both. The label property is displayed in the suggestion menu. The value will be inserted into the input element after the user selected something from the menu. If just one property is specified, it will be used for both, eg. if you provide only value-properties, the value will also be used as the label.
Which means that if you use "value" instead of "partNumber", you should get want you want.
jquery autocomplete plugin format out have to
{"query":"your_query","suggestions":["suggestions_1","suggestions_2"],"data":[your_data]}}
and use autocomplete that
$('#your_input').autocomplete({
minChars: 2
, serviceUrl: './PartSearch.ashx'
, deferRequestBy: 50
, noCache: true
, params: { }
, onSelect: function(value, data) {
}
, ajaxCallBack: function() {
response($.map(data, function(item) {
return { label: item.partNumber}
}))
}
});
With this code:
function setupRow(event, ui) {
var textbox, // how do i get to the textbox that triggered this? from there
// on i can find these neighbours:
hiddenField = textbox.next(),
select = textbox.parents('tr').find('select');
textbox.val(ui.item.Name);
hiddenField.val(ui.item.Id);
$.each(ui.item.Uoms, function(i, item){
select.append($('<option>' + item + '</option>'));
});
return false;
}
function setupAutoComplete(){
var serviceUrl = "/inventory/items/suggest";
$("input.inputInvItemName").autocomplete({
source: function(request, response) {
$.ajax({
url: serviceUrl,
data: request,
dataType: "json",
success: function(data) {
response($.map(data.InventoryItems, function(item) {
return {
value: item.Name
};
}));
},
select: function(event, ui) {
setupRow(event, ui);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert(textStatus);
}
});
},
minLength: 3,
delay: 500
});
}
everything seems ok. Problem is the select handler never fires, not even the anonymous function that wraps my original delegate setupRow for debugging purposes is ever called.
anyone can see my error?
I also left a question in the comment: how do I get to the textbox that had the autosuggestion. Cannot use id here, because these text boxes are multiples and generated on the fly, interactively. Or is there another way to do the same thing?
Thanks for any help!
OP point of view
var textbox, // how do i get to the textbox that triggered this? from there
// on i can find these neighbours:
My Point of view
have you tried,
var textbox = $(event.target);
or you can do this,
OP point of view
select: function(event, ui) {
setupRow(event, ui);
},
My point of view
select: setupRow;
then
var textbox = this; // just a guess... wait..
anyone can see my error?
I think you forgot to put ';' .
$.ajax({
url: serviceUrl,
data: request,
dataType: "json",
success: function(data) {
response($.map(data.InventoryItems, function(item) {
return {
value: item.Name
}
}));
Or is there another way to do the same thing?
I think u are using the jquery ui autocomplete plugin.If yes, you can retreive like this.
$('.ui-autocomplete-input')
Otherwise, you can set a specific class to those textboxes and access those textbox through that class.
ok, got a step closer by using
inputs.bind("autocompleteselect", setupRow);
now setupRow fires.
Now it seems, that the success callback transforms the data, I get returned.I need to find a way, to both display the right value in the dropdown, without destroying the requests response...
Any ideas?
I am using Rails and jQuery, making an ajax call initiated by clicking a link. I setup my application.js file to look like the one proposed here and it works great. The problem I'm having is how can I use $(this) in my say.. update.js.erb file to represent the link I clicked? I don't want to have to assign an ID to every one, then recompile that id in the callback script..
EDIT
To give a simple example of something similar to what I'm trying to do (and much easier to explain): If a user clicks on a link, that deletes that element from a list, the controller would handle the callback, and the callback (which is in question here) would delete the element I clicked on, so in the callback delete.js.erb would just say $(this).fadeOut(); This is why I want to use $(this) so that I dont have to assign an ID to every element (which would be the end of the world, just more verbose markup)
application.js
jQuery.ajaxSetup({ 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript,application/javascript,text/html")} })
function _ajax_request(url, data, callback, type, method) {
if (jQuery.isFunction(data)) {
callback = data;
data = {};
}
return jQuery.ajax({
type: method,
url: url,
data: data,
success: callback,
dataType: type
});
}
jQuery.extend({
put: function(url, data, callback, type) {
return _ajax_request(url, data, callback, type, 'PUT');
},
delete_: function(url, data, callback, type) {
return _ajax_request(url, data, callback, type, 'DELETE');
}
});
jQuery.fn.submitWithAjax = function() {
this.unbind('submit', false);
this.submit(function() {
$.post(this.action, $(this).serialize(), null, "script");
return false;
})
return this;
};
// Send data via get if <acronym title="JavaScript">JS</acronym> enabled
jQuery.fn.getWithAjax = function() {
this.unbind('click', false);
this.click(function() {
$.get($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
// Send data via Post if <acronym title="JavaScript">JS</acronym> enabled
jQuery.fn.postWithAjax = function() {
this.unbind('click', false);
this.click(function() {
$.post($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
jQuery.fn.putWithAjax = function() {
this.unbind('click', false);
this.click(function() {
$.put($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
jQuery.fn.deleteWithAjax = function() {
this.removeAttr('onclick');
this.unbind('click', false);
this.click(function() {
$.delete_($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
// This will "ajaxify" the links
function ajaxLinks(){
$('.ajaxForm').submitWithAjax();
$('a.get').getWithAjax();
$('a.post').postWithAjax();
$('a.put').putWithAjax();
$('a.delete').deleteWithAjax();
}
show.html.erb
<%= link_to 'Link Title', article_path(a, :sentiment => Article::Sentiment['Neutral']), :class => 'put' %>
The combination of the two things will call update.js.erb in rails, the code in that file is used as the callback of the ajax ($.put in this case)
update.js.erb
// user feedback
$("#notice").html('<%= flash[:notice] %>');
// update the background color
$(this OR e.target).attr("color", "red");
jQuery already handles the this issue for you with the event properties:
$("a").click(function(e){
e.preventDefault();
$("#foo").fadeIn(3000, function(){
$(e.target).text("Foo loaded");
});
});
Note how I can refer back to the main link via its event. This is the case with any events that are handled within as well. Just give them unique names, such as e2, e3, etc. No more need to constantly write yet another var item = $(this) line to keep track of this three events back.
Online Demo: http://jsbin.com/egelu3/edit
If your JS is coming from the server, there is really no way that $(this) can operate in the same context. The closest you could get would be to load some script from the server and eval it in the context of your client-side function.
I basically have an id for each of the DOM elements I need to manipulate, and refer to them within my scripts. It is occasionally ugly, but the alternatives are worse.
If your JS is coming from the server,
there is really no way that $(this)
can operate in the same context. The
closest you could get would be to load
some script from the server and eval
it in the context of your client-side
function.
Not true
I basically have an id for each of the
DOM elements I need to manipulate, and
refer to them within my scripts. It is
occasionally ugly, but the
alternatives are worse.
I don't think this is ugly.
The key to this problem is functional scoping. Let me show you what I mean. You need to create a function that is called before you send your XHR call. In your case, you're doing it with a click event, so let me show you an example tailored for you:
$( '#somelink' ).click( function( )
{
// this stores the location of the current "this" value
// into this function, and will available even after we
// end this function (and will still live while the XHR's
// callback is being executed
var theLink = this;
// fire the AJAX call
$.post
(
'some/url',
{ 'some':'data' }, // optional
function( )
{
// use theLink however you want
// it'll still be there
// also, if you're sending in callbacks
// as variables, you can safely say
hideAndStore.call( theLink, data );
// which executes callback( ), overriding
// "this" with theLink (your DOM node)
// and sending in the responseText as the
// first argument
}
);
} );
and then you could make your callback something like:
function hideAndStore( response )
{
// you can safely use "this" as the DOM node
$( this ).css( { 'display':'none' } );
// and you can do whatever you wish with the response
window.globalData = response;
}
where you'd make it do whatever you actually want it to do, haha.
For more info about functions in JavaScript that change the "this" value, check out .apply and .call at MDC
https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Function/Apply https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Function/Call
What are you doing in the javascript you are sending back? Maybe you can send back some html or json and operate on it in a callback.
$('a:clickable').bind('click', function() {
var elem = $(this);
$.ajax({
url: ...,
dataType: 'json',
success: function(data) {
// elem is still in scope
elem.addClass(data.class_to_add_to_link);
}
});
});
This cannot be accomplished, The method in which i am trying to do this makes it impossible, i cannot pass references to javascript objects through views.
Solution was to assign IDs to each item, and refer to them by that.