jQuery autocomplete variable scope - javascript

I'm having an issue with scope of variables in this function. Basically, when a user focuses on a textbox which will have a jQuery dropdown, I want to save the old value in the textbox, if present in order to restore it if required. I have also tried to declare previous outside the function and as window.previous but without success. The problem is that when I use the previous variable from within the .dropdown function I always get it back as undefined
// Delete option allows a user to delete the value directly from the textbox associated with the dropdown.
// Otherwise he will be warned and always forced to make a choice.
// With value will add an extra value to a textbox that has _val apended to the current id
// Create new, if set will open a new confirmation to add the item to the dropdown list
function acomplete(element, source, deleteoption, withvalue, createnew, createtable, createcolumn, retid) {
var previous;
// Add arrow as this is a dropdown
$(element).addClass("dropdown");
$(element).autocomplete({
source: source,
minLength: 0,
global: false,
select: function (event, ui) {
if (withvalue == true) {
$("#" + $(this).attr("id") + "_val").val(ui.item.thevalue);
//$("#" + $(this).attr("id") + "_val").trigger("change");
}
// Update hidden on select option
$("#" + $(this).attr("id") + "_id").val(ui.item.id);
// For items that have change event bound trigger ot so we are updating data in table.
$("#" + $(this).attr("id") + "_id").trigger("change");
},
focus: function (event, ui) {
// Save old value for backup
previous = this.value;
},
change: function (event, ui) {
//alert($(this).val());
if (!ui.item && $(this).val().length > 0) { // Item not selected in the dropdown list
$.ajax({
url: "ajax/check_dropdown_item_exists.php",
global: false,
method: "POST",
data: {
table: createtable,
colnames: createcolumn,
colvals: encodeURI(String($(this).val().toUpperCase())),
},
success: function (data) {
if (data != "TRUE") {
// Ask confirm to add new item to table
$.confirm('ITEM DOES NOT EXIST! ADD TO LIST?', function (answer) {
if (answer) {
$.ajax({
url: "inc/insert_table_field.php",
global: false,
method:"POST",
data: {
table: createtable,
colnames: createcolumn,
colvals: String($(this).val().toUpperCase()),
retid: retid,
},
success: function (data) {
if ($.isNumeric(data)) {
$("#" + $(element).attr("id") + "_id").val(data);
// Set the newly created value in dropdown
//$(element).val(String($(element).val().toUpperCase()));
// And update DB
$("#" + $(element).attr("id") + "_id").trigger("change");
} else {
$.alert(data);
}
},
error: function () {
$.alert('ERROR CREATING THE NEW ITEM!');
}
})
} else {
alert(previous)
// NO so blank
$(this).val(previous).focus();
}
})
} else {
// Commit change with value that already exists
// fecth item id and trigger select event
$.ajax({
url: "ajax/get_dropdown_item_id.php",
global: false,
method: "POST",
data: {
table: createtable,
colnames: createcolumn,
colvals: String($(element).val().toUpperCase()),
retid: retid,
},
success: function (data) {
if ($.isNumeric(data)) {
$("#" + $(element).attr("id") + "_id").val(data);
$("#" + $(element).attr("id") + "_id").trigger("change");
}
}
})
}
}
})
} else {
$(this).val((ui.item ? ui.item.label : "")); // If empty put back the last one
if (!ui.item) {
if (deleteoption !== true) {
this.value = "";
$.alert('YOU CAN SELECT FROM DROPDOWN ONLY!');
$(element).val(element.oldvalue).focus();
} else {
$("#" + $(this).attr("id") + "_id").val("");
$("#" + $(this).attr("id") + "_id").trigger("change");
}
}
}
}
}).dblclick(function () {
$(this).autocomplete("search", "");
}).click(function () {
$(this).autocomplete("search", "");
})
}

The problem is that focus don't react on focusing the textbox/input, but instead the result from autocomplete.
That means that when you click in the textbox the function focus will not start only if you select a result.
The best solution for you to get previous would be:
$(your element).click(function() {
previous = $(this).val()
}
This is from the documentation of jQueryUi Autocomplete:
focus( event, ui )
Triggered when focus is moved to an item (not selecting). The default action is to replace the text field's value with the value of the focused item, though only if the event was triggered by a keyboard interaction.
Canceling this event prevents the value from being updated, but does not prevent the menu item from being focused.
focus documentation

Related

Function onSelect is faster than click

I use autosuggestion plugin and option onSelect - that option change values to other fields. Everything is fine when I select first time item but when I click on input field with class .auto second time (where already have item) then fucntion onSelect is faster than function click which give me ID where I need to update field.
This looks like this:
function dajjson() {
$('.auto').click(function () {
koji = $(this).attr('data-ajdi5');
console.log(koji);
});
$.ajax({
url: "autoUsluge.php",
type: "GET",
async: true,
dataType: "JSON",
success: function (data) {
$('.auto').autocomplete({
lookup: data,
showNoSuggestionNotice: true,
noSuggestionNotice: '<div> + Dodaj novu uslugu</div>',
beforeRender: function (container) {
$('.autocomplete-suggestions').append('<div> + Dodaj novu uslugu</div>');
},
onSelect: function (suggestion) {
console.log(koji);
$('#cena_' + koji).val(suggestion.cena);
console.log(suggestion.cena);
$('#jmere' + koji).val(suggestion.jmere);
$('#kol' + koji).val(suggestion.kol);
$('#popust' + koji).val(suggestion.popust);
$('#pdv' + koji).val(suggestion.porez);
koji = 0;
}
});
},
error: function (data) {
console.log(data);
console.log('GRESKA NEKA');
}
});
};
So how I can solve problem with function select. How I can get koji before onSelect start?
I think using the .change() event is what you want here. It will fire after the value has changed. The .mousedown() event will fire even earlier than .click().

click event without any response

i got an asp.net mvc project, but actually most of functions i achieved via javascript, below screenshot is the part which makes me frustrating, here you can see i use a date picker to define time slot then filter content for next dropdown button with related contents.
$('.input-daterange').datepicker({
format: "yyyymm",
minViewMode: 1,
language: "zh-CN",
beforeShowMonth: function (date) {
switch (date.getMonth()) {
case 0:
return false;
case 1:
return false;
case 2:
return false;
case 3:
return false;
case 4:
return false;
}
}
}).on('changeDate', function (e) {
var from = $('#from-date').val();
var to = $('#to-date').val();
if (from !== to) {
$.ajax({
type: "GET",
url: "DataChanged?fromDate=" + $('#from-date').val() + "&toDate=" + $('#to-date').val(),
dataType: "json"
})
.done(function (data) {
//var legth = data.chart.length;
$('#brandtable').empty();
var contents = $.parseJSON(data);
$.each(contents, function (key, values) {
$.each(values, function (k, v) {
$('#brandtable').append("<td><button class='btn btn-default' id=" + v.ID + ">" + v.BrandName + "</button></td>");
if (k % 9 === 0) {
if (k !==0) {
$('#brandtable').append("<tr></tr>");
}
}
});
});
});
};
});
});
Ok now, everything is fine, content was added successfully with button tag, but now i want click on button to get data from server just like above action, it is very strange that click event doesn't work, i don't know why? i did it in this way,
#foreach (var item in Model)
{
<text>
$("##item.ID").click(function () {
$.getJSON("#Url.Action("ReturnContentForSrpead", new { #ID = item.ID })", function (msg) {
var tags = BID.getParams.C32().tags;
var data = (msg.data || {}).wordgraph || [{ key: tags[0] }, { key: tags[1] }, { key: tags[2] }, { key: tags[3] }, { key: tags[4] }];
iDemand.drawBg().setData(data[lastTab]).drawCircle(BID.getColor(lastTab)).wordgraph = data;
});
});
</text>
}
i passed all instances from controller when i render page at very beginning, so that means all content already got, but only use jquery ajax to achieve kind of asynchronous. if you confuse with why i used Razor to render scripts, ok, i tried javascript as well, but got same result.
but one thing makes me shake was, when i run below code from console, it works fine.
$("##item.ID").click(function () {
console.log('clicked');
});
Do not render inline scripts like that. Include one script and add a class name to the dynamically added elements and store the items ID as a data- attribute, then use event delegation to handle the click event
In the datepickers .on function
var table = $('#brandtable'); // cache it
$.each(values, function (k, v) {
// Give each cell a class name and add the items ID as a data attribute
table .append("<td><button class='btn btn-default brand' data-id="v.ID>" + v.BrandName + "</button></td>");
Then use event delegation to handle the click event.
var url = '#Url.Action("ReturnContentForSrpead")';
table.on('click', '.brand', function() {
// Get the ID
var id = $(this).data('id');
$.getJSON(url, { ID: id }, function (msg) {
....
});
});
Side note: Its not clear what your nested .each() loops are trying to do and you are creating invalid html by adding <td> elements direct to the table. Best guess is that you want to add a new rows with 9 cells (and then start a new row) in which case it needs to be something like
$.each(values, function (k, v) {
if (k % 9 === 0) {
var row = $('</tr>');
table.append(row);
}
var button = $('</button>').addClass('btn btn-default brand').data('id', v.ID).text(v.BrandName);
var cell = $('</td>').append(button);
row.append(cell);
})
Recommend also that you change
url: "DataChanged?fromDate=" + $('#from-date').val() + "&toDate=" + $('#to-date').val(),
to
url: '#Url.Action("DataChanged")',
data: { fromDate: from, toDate: to }, // you already have the values - no need to traverse the DOM again
You are binding click event on every item ID but the way you are getting id is not right. This $("##item.ID") will not find any element because this will bind click to an element whose id is #item.ID and there is no such element will this id. You need to change it like below. Concatenate "#" with each item id.
$("#"+#item.ID).click(function () {
//your code
})

Jquery AJAX Post not hitting method in code behind

I have an ASP.NET website which uses jQuery 1.8.2. I have a dialog box which lists UserReporting Settings from a DB whether a column is displayed or not. The User can change this by clicking the change columns buttons which open the dialog box - there are then a list of Available Columns and Current Columns and the User can drag and drop from one side to the other.
The code in the Update button off the dialog button is what is not working - the 'Hello' alert fires but if I set a breakpoint in my ashx Handler it never gets hit?
$("#UserReportSettings").dialog({
resizable: false,
autoOpen: false,
height: 600,
width: 525,
modal: true,
buttons: {
"Update Columns": function () {
var columns = [];
$('#currentColumnsList').each(function () {
// this is inner scope, in reference to the .phrase element
var column = '';
$(this).find('li').each(function () {
// cache jquery var
var current = $(this);
// check if our current li has children (sub elements)
// if it does, skip it
// ps, you can work with this by seeing if the first child
// is a UL with blank inside and odd your custom BLANK text
if (current.children().size() > 0) {
return true;
}
// add current text to our current phrase
column += (current.text() + ',');
});
// now that our current phrase is completely build we add it to our outer array
columns.push(column);
});
$.ajax({
type: 'POST',
url: '/MyWebsite/Handlers/UpdateUserReportingSettings.ashx',
data: { reportingSettings: columns.join() },
beforeSend: function (xhr, opts) {
},
success: function (data) {
alert("Hello");
window.top.location.href = "landing.aspx";
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error' + xhr.responseText);
}
});
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
EDIT - Following Archers comment
If I paste localhost/Handlers/UpdateUserReportingSettings.ashx into the browser I can hit break point in my Handler.
So changed my URL in ajax call to :
url: '/MyWebsite/Handlers/UpdateUserReportingSettings.ashx',
and did a shift refresh to reload the js for page and hit the breakpoint.

jquery ui autocomplete with google places - force selection and remove original input while moving up down arrows

I've following jquery ui autocomplete, that grabs data from google places...
Problem I'm having is that, once user starts going through the list of suggests via up and down arrows, original input also appears at the end. I want to remove this original input, otherwise if user hits enter form saves without forcing selection...
// Autocomplete location with google places API
$("#edit_profile .location").autocomplete({
source: function(request, response) {
$.ajax({
url: "/words/lib/ajax.php",
type: "GET",
data: "autocomplete_location=1&term=" + request.term,
cache: false,
success: function(resp) {
try {
json = $.parseJSON(resp);
} catch (error) {
json = null;
}
//
if (json && json.status == "OK") {
//
response($.map(json.predictions, function(item) {
return {
label: item.description,
value: item.description
}
}));
//
}
}
});
},
minLength: 1,
change: function (event, ui) {
if (!ui.item){
$(this).val("");
}
}
});
I'm not sure if i get the question the right way, but if i did, try "focus" method instead of the "change" method.
So the code would look like this:
// Autocomplete location with google places API
$("#edit_profile .location").autocomplete({
source: function(request, response) {
$.ajax({
url: "/words/lib/ajax.php",
type: "GET",
data: "autocomplete_location=1&term=" + request.term,
cache: false,
success: function(resp) {
try {
json = $.parseJSON(resp);
} catch (error) {
json = null;
}
//
if (json && json.status == "OK") {
//
response($.map(json.predictions, function(item) {
return {
label: item.description,
value: item.description
}
}));
//
}
}
});
},
minLength: 1,
focus: function (event, ui) {
if (!ui.item){
$(this).val("");
}
}
});
You can not catch this with change event course it happen before, so I tried to change it to focus event but this event only fired when you select smth from suggestion list.Also I think default behavior have logic because in case I didn't found what I want in list I would like to have option to came back and continue typing.
But anyway if you want to change this behavior you can prevent from user access to input field after the ajax return.
For example with position the suggest box over input field.
<ul class="ui-autocomplete ui-menu ui-widget ui-widget-content ui-corner-all" role="listbox" aria-activedescendant="ui-active-menuitem" style="z-index: 1; top: 0px; left: 0px; display: block; width: 298px;">
Here is the demo.
Is your concern about disabling the default action when hitting [Enter] while the autocomplete menu is visible ?
If so, here is a solution : add some flag to your input, and if that flag is set, prevent the default action on keydown :
var $input = $('input[name="name"]');
$input.on('keydown', function(e) {
if ( $(this).data('acShown') && e.which == 13 /*enter key*/){
e.preventDefault();
}
});
$input.autocomplete({
source: function (request, response) {
setTimeout(function () {
$input.data('acShown', true); //set the flag when showing the menu
response(data)
}, 300);
},
close: function(){
$input.data('acShown', false); //unset the flag on close
}
});
fiddle
In the fiddle : as you can see, when the menu is shown, hitting [Enter] when the focus is on the input won't trigger the form submission - you will stay on the current page.

jQuery change event returns null when manually fired on $(document).ready();

I'm currently writing a JQuery plugin that loads colors from a JSON web service into a drop down list.
The drop down list background-color changes according to the selected value. For the most part it is working. on any regular change it works as expected, the problem I am having is on the initial page load I am using triggerHandler("change"); and it triggers but I seem to be getting an undefined error on the selected value from the drop down list on page load so it doesn't trigger the color change on the drop down list
My code is:
$.fn.bindColorsList = function (options) {
var defColor = options.defaultColor;
var svcUrl = options.svcurl;
//var f_target = options.filterTarget;
var $this = this;
$.ajax({
url: options.svcurl,
dataType: 'json',
/*data: { filter: src_filt },*/
success: function (fonts) { fillcolors(fonts, $this) },
error: function () { appendError(f_target, "colors failed to load from server") }
});
this.on("change", function (event) {
log($(event.target).attr("id") + " change detected");
//change ddl dropdown color to reflect selected item ;
var hcolor = $this.find('option:selected').attr("name");
$this.attr("style", "background-color:" + hcolor);
});
function fillcolors(colors, target) {
$(target).empty();
$.each(colors, function (i, color) {
$(target).append("<option name='"+color.HexValue+"' value='" + color.Name + "' style='background-color:"+color.HexValue+"'>"+color.Name+"</option>");
});
};
//in a seperate file
$(document).ready(function () {
$("#dd-font-color").bindColorsList({ svcurl: "/home/colors"});
$("#dd-back-color").bindColorsList({ svcurl: "/home/colors" });
});
You are doing an AJAX request to populate your dropdown which, by the way, is an asynchronous one. In this case you need to trigger the event in the success callback of the AJAX request.
var $this = this;
// Bind the onchange event
$this.on("change", function (event) {
..
});
// Populate using AJAX
$.ajax({
...
success: function (fonts) {
// Populate the values
fillcolors(fonts, $this);
// Trigger the event
$this.trigger("change");
},
...
});
That's it.

Categories

Resources