Multiple Autocomplete function Open render previous items - javascript

I'm having a litle problem with my autocomplete. I'm using two autocompletes in same page.
In both I'm rendering my elements from ajax (diferente sources), and also in both, i'm using the _render option to show my elements.
The problem is: In my second autocomplete, in the funcion Open I want use the $('.ui-autocomplete > li') but when I do this, it will return the new ones, but also with the li elements from the previous autocomplete...
This is my second autocomplete:
$(".chooseProduct").autocomplete({
source: function (request, response) {
$.ajax({
....
});
},
select: function (event, ui) {
if (ui.item != null)
selectedProduct(ui.item);
},
open: function (event, ui) {
//this length will return the newest and the other elements :(
var len = $('.ui-autocomplete > li').length;
if (!(len == 8 && showQtd > 8)) {
if ((len % 8) == 0) {
$('.ui-autocomplete').append("<li class='ui-menu-item'><a>------Show more------</a></li>");
}
}
else showQtd = 8;
}
}).data("autocomplete")._renderItem = function (ul, item) {
var extra = "";
if (item.dosagem != null)
extra = "DOS: " + item.dosagem + " ";
return $('<li></li>')
.data('item.autocomplete', item)
.append('<a>COD: <b>' + item.codigo + ' ' + item.name + '</b>' + item.pvp + '<br/>' + extra + '</a>')
.appendTo(ul);
};
How can I instead of using $('.ui-autocomplete > li') use only my returned elements?
Thanks

When you use the selector $('ui-element > li) it will render all the items that are included in the element that you define to do autocomplete. To obtain the current elements (the elements that are being rendered by this autocomplete) do this way:
var len = $(this).data("autocomplete").menu.element.children().length;
To get all elements:
var elements = $(this).data("autocomplete").menu.element.children();

Related

Definig element.sortable()-function

My html table supports changing the row-order using mouse drag and drop. The used jquery-ui version is v1.12.1. It works for old tables (i.e. those whose row count is known since load of the page), but it doesn't work for rows added after the page has been loaded. I think the reason is that the below sortable()-function is inside document.ready()-function.
<script type="text/javascript">
<script src="{% static 'js/jquery-ui.js' %}"></script>
$(document).ready(function(){
$('#luok_table tbody').sortable({
stop: function( event, ui ){
$(this).find('tr').each(function(i){
$(this).attr("id", $(this).attr("id").replace(/\d+/, i) );
$(this).find(':input').each(function(){
$(this).attr("id", $(this).attr("id").replace(/\d+/, i) );
$(this).attr("name", $(this).attr("name").replace(/\d+/, i) );
});
});
}
});
});
</script>
If that's the reason, where should I define the sortable()-function ?
The table rows are added by jquery-formset-js-script:
;(function($) {
$.fn.formset = function(opts)
{
var options = $.extend({}, $.fn.formset.defaults, opts),
flatExtraClasses = options.extraClasses.join(' '),
$$ = $(this),
applyExtraClasses = function(row, ndx) {
if (options.extraClasses) {
row.removeClass(flatExtraClasses);
row.addClass(options.extraClasses[ndx % options.extraClasses.length]);
}
},
updateElementIndex = function(elem, prefix, ndx) {
var idRegex = new RegExp('(' + prefix + '-\\d+-)|(^)'),
replacement = prefix + '-' + ndx + '-';
if (elem.attr("for")) elem.attr("for", elem.attr("for").replace(idRegex, replacement));
if (elem.attr('id')) elem.attr('id', elem.attr('id').replace(idRegex, replacement));
if (elem.attr('name')) elem.attr('name', elem.attr('name').replace(idRegex, replacement));
},
hasChildElements = function(row) {
return row.find('input,select,textarea,label').length > 0;
},
insertDeleteLink = function(row) {
if (row.is('TR')) {
// If the forms are laid out in table rows, insert
// the remove button into the last table cell:
row.children(':last').append('<a class="' + options.deleteCssClass +'" href="javascript:void(0)">' + options.deleteText + '</a>');
} else if (row.is('UL') || row.is('OL')) {
// If they're laid out as an ordered/unordered list,
// insert an <li> after the last list item:
row.append('<li><a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a></li>');
} else {
// Otherwise, just insert the remove button as the
// last child element of the form's container:
row.append('<a class="' + options.deleteCssClass + '" href="javascript:void(0)">' + options.deleteText +'</a>');
}
row.find('a.' + options.deleteCssClass).click(function() {
var row = $(this).parents('.' + options.formCssClass),
del = row.find('input:hidden[id $= "-DELETE"]');
if (del.length) {
// We're dealing with an inline formset; rather than remove
// this form from the DOM, we'll mark it as deleted and hide
// it, then let Django handle the deleting:
del.val('on');
row.hide();
} else {
row.remove();
// Update the TOTAL_FORMS form count.
// Also update names and IDs for all remaining form controls so they remain in sequence:
var forms = $('.' + options.formCssClass).not('.formset-custom-template');
$('#id_' + options.prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
applyExtraClasses(forms.eq(i), i);
forms.eq(i).find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, i);
});
}
}
// If a post-delete callback was provided, call it with the deleted form:
if (options.removed) options.removed(row);
return false;
});
};
$$.each(function(i) {
var row = $(this),
del = row.find('input:checkbox[id $= "-DELETE"]');
if (del.length) {
// If you specify "can_delete = True" when creating an inline formset,
// Django adds a checkbox to each form in the formset.
// Replace the default checkbox with a hidden field:
del.before('<input type="hidden" name="' + del.attr('name') +'" id="' + del.attr('id') +'" />');
del.remove();
}
if (hasChildElements(row)) {
insertDeleteLink(row);
row.addClass(options.formCssClass);
applyExtraClasses(row, i);
}
});
if ($$.length) {
var addButton, template;
if (options.formTemplate) {
// If a form template was specified, we'll clone it to generate new form instances:
template = (options.formTemplate instanceof $) ? options.formTemplate : $(options.formTemplate);
template.removeAttr('id').addClass(options.formCssClass).addClass('formset-custom-template');
template.find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, 2012);
});
insertDeleteLink(template);
} else {
// Otherwise, use the last form in the formset; this works much better if you've got
// extra (>= 1) forms (thnaks to justhamade for pointing this out):
template = $('.' + options.formCssClass + ':last').clone(true).removeAttr('id');
template.find('input:hidden[id $= "-DELETE"]').remove();
template.find('input,select,textarea,label').each(function() {
var elem = $(this);
// If this is a checkbox or radiobutton, uncheck it.
// This fixes Issue 1, reported by Wilson.Andrew.J:
if (elem.is('input:checkbox') || elem.is('input:radio')) {
elem.attr('checked', false);
} else {
elem.val('');
}
});
}
// FIXME: Perhaps using $.data would be a better idea?
options.formTemplate = template;
if ($$.attr('tagName') == 'TR') {
// If forms are laid out as table rows, insert the
// "add" button in a new table row:
var numCols = $$.eq(0).children().length;
$$.parent().append('<tr><td colspan="' + numCols + '"><a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a></tr>');
addButton = $$.parent().find('tr:last a');
addButton.parents('tr').addClass(options.formCssClass + '-add');
} else {
// Otherwise, insert it immediately after the last form:
$$.filter(':last').after('<a class="' + options.addCssClass + '" href="javascript:void(0)">' + options.addText + '</a>');
addButton = $$.filter(':last').next();
}
addButton.click(function() {
var formCount = parseInt($('#id_' + options.prefix + '-TOTAL_FORMS').val()),
row = options.formTemplate.clone(true).removeClass('formset-custom-template'),
buttonRow = $(this).parents('tr.' + options.formCssClass + '-add').get(0) || this;
applyExtraClasses(row, formCount);
row.insertBefore($(buttonRow)).show();
row.find('input,select,textarea,label').each(function() {
updateElementIndex($(this), options.prefix, formCount);
});
$('#id_' + options.prefix + '-TOTAL_FORMS').val(formCount + 1);
// If a post-add callback was supplied, call it with the added form:
if (options.added) options.added(row);
return false;
});
}
return $$;
}
/* Setup plugin defaults */
$.fn.formset.defaults = {
prefix: 'form', // The form prefix for your django formset
formTemplate: null, // The jQuery selection cloned to generate new form instances
addText: 'add another', // Text for the add link
deleteText: 'remove', // Text for the delete link
addCssClass: 'add-row', // CSS class applied to the add link
deleteCssClass: 'delete-row', // CSS class applied to the delete link
formCssClass: 'dynamic-form', // CSS class applied to each form in a formset
extraClasses: [], // Additional CSS classes, which will be applied to each form in turn
added: null, // Function called each time a new form is added
removed: null // Function called each time a form is deleted
};
})(jQuery)

Remove "comma" separator after last element

I have the below code.
$(document).ready(function(){
$('input[type="checkbox"]').click(function(){
elem = $(this);
part = $(this).attr("data-part-name");
//alert(part);
selected_options = "";
$('.' + part).each(function () {
if ($(this).is(":checked")) {
selected_options += $(this).attr("data-option-name") + ' <b>,</b> '
}
});
$("#part_child_" + elem.attr("data-part-id")).html(selected_options);
});
});
If you see I am adding a "comma" to selected options.
Now problem is it adds comma even after the last element.
How can I remove the last comma
.map() will a perfect fit for this. Also you can filter the checked items using :checked and filter
$(document).ready(function () {
$('input[type="checkbox"]').click(function () {
var elem = $(this);
var part = $(this).attr("data-part-name");
//alert(part);
var selected_options = $('.' + part).filter(':checked').map(function () {
return '<b>' + $(this).attr("data-option-name") + '</b>'
}).get();
$("#part_child_" + elem.attr("data-part-id")).html(selected_options.join(', '));
});
});
You can use the index of iteration to compare with length of parts element and do the decision whether a comma needs to be added or not.Modify the code to:
var totalparts=$('.' + part).length;
$('.' + part).each(function (i) {
if ($(this).is(":checked")) {
selected_options += $(this).attr("data-option-name") + totalparts!=(i+1) ?' <b>,</b> ':'';
}});
Just remove last , substring from the string,
if(selected_options.length > 0){
selected_options = selected_options.slice(0,-1)
}
$("#part_child_" + elem.attr("data-part-id")).html(selected_options);
replace this line
$("#part_child_" + elem.attr("data-part-id")).html(selected_options.replace(/[\<\>\,b\/\s]+$/,''));

removing clicked item from array in javascript

I have a click function to make a list of chosen items. Also, I push the chosen items to an array. There is no problem in that part, here is the function.
$('#addToCartButton2').click(function(){
var toAdd=$("#chooseItem2 option:selected").text();
var itemNbr2=$("#itemNbr2").val();
if(toAdd !== defaultSelectFormText && itemNbr2 >=1){
$('#defaultText').remove();
$('.col-md-5').append('<p id="items">' + itemNbr2 + ' Adet ' + toAdd + '<span class="extra">Sipariş listesinden çıkarmak için tıklayın!</span>' + '</p>');
ordersArray.push(itemNbr2 + ' Adet ' + toAdd);
alert(ordersArray.toString());
};
});
But I also have a function to remove the clicked item from that list. So I want to remove that item also from array when it is clicked. I tried to use splice method but I can not get the index of the clicked item. Here is the remove function.
$(document).on('click', '#items', function() {
$(this).remove();
var index = ordersArray.indexOf($(this).val());
alert(index);
if (index > -1) {
ordersArray.splice(index, 1);
}
});
How can I get the index of the clicked item in the list?
Firstly, either you make id of items unique or use class instead of id as I done in this solution.
$('#addToCartButton2').click(function(){
var toAdd=$("#chooseItem2 option:selected").text();
var itemNbr2=$("#itemNbr2").val();
if(toAdd !== defaultSelectFormText && itemNbr2 >=1){
$('#defaultText').remove();
$('.col-md-5').append('<p class="items"><span>' + itemNbr2 + ' Adet ' + toAdd + '</span><span class="extra">Sipariş listesinden çıkarmak için tıklayın!</span>' + '</p>');
ordersArray.push(itemNbr2 + ' Adet ' + toAdd);
alert(ordersArray.toString());
};
});
$(document).on('click', '.items', function() {
var index = ordersArray.indexOf($('span:first', this).text());
alert(index);
if (index > -1) {
ordersArray.splice(index, 1);
}
$(this).remove();
});
In function to remove the clicked item from that list, make the following changes:
$(document).on('click', '#items', function() {
var index = ordersArray.indexOf($(this).text());
alert(index);
if (index > -1) {
ordersArray.splice(index, 1);
}
$(this).remove();
});
It seems like you're way of deleting the item is a little to complex.
Why not just use a uniqe ID for each item you're appending and just delete
the item by it's ID ?

Finding the closest, previous element with specific data attribute jquery

This has been troubling me for the passed few hours now.
I have a table. Within that table i'm looking for the closest, previous table row with a specific data attribute. I'm doing this search right after a successful use of jquery sortable. I've tried almost everything and it ALWAYS comes up with the wrong thing.
Here's what i'm using
var newIndex = ui.item.index();
var menuLevel = parseInt($("#menu-table").find("[data-menu-nesting='" + newIndex + "']").attr("data-menu-level"));
var menuId = $("#menu-table").find("[data-menu-nesting='" + newIndex + "']").attr("data-menu-id");
if (menuLevel == 2) {
var findAboveRowName = $(".menu-table-rows[data-menu-nesting='" + newIndex + "']").prev(".menu-table-rows").data("menu-level","1").attr("data-menu-name");
alert(findAboveRowName);
}
if (menuLevel == 3) {
var findAboveRowName = $(".menu-table-rows[data-menu-nesting='" + newIndex + "']").prev(".menu-table-rows").data("menu-level","2").attr("data-menu-name");
alert(findAboveRowName);
}
Essentially, the variable "newIndex" is supposed to grab the new position of the row after being sorted, menuLevel is supposed to grab the data attribute "menu-level" of that table row, and menuId is grabbing another data attribute of that table row.
It's specifically looking for the nearest, previous menu-level attribute in the table rows. So if a table row with a menu-level attribute of 2 is moved, it's looking for the nearest table row with a menu-level attribute of 1.
The full jquery sortable script i'm using if needed
$("#sortable").sortable({
update: function(event, ui) {
var serial = $('#sortable').sortable('serialize');
var newIndex = ui.item.index();
var menuLevel = parseInt($("#menu-table").find("[data-menu-nesting='" + newIndex + "']").attr("data-menu-level"));
var menuId = $("#menu-table").find("[data-menu-nesting='" + newIndex + "']").attr("data-menu-id");
if (menuLevel == 2) {
var findAboveRowName = $(".menu-table-rows[data-menu-nesting='" + newIndex + "']").prev(".menu-table-rows").data("menu-level","1").attr("data-menu-name");
alert(findAboveRowName);
// $.post("./menu-controller.php", { adjustParent: true, id: menuId, parent: findAboveRowName });
}
if (menuLevel == 3) {
var findAboveRowName = $(".menu-table-rows[data-menu-nesting='" + newIndex + "']").prev(".menu-table-rows").data("menu-level","2").attr("data-menu-name");
alert(findAboveRowName);
// $.post("./menu-controller.php", { adjustParent: true, id: menuId, parent: findAboveRowName });
}
$.ajax({
url: "./menu-controller.php",
type: "post",
data: serial,
success: function() {
$("#sortable").load("./menu-manager.php #menu-table", function() {
$.get('./menu-admin.js');
});
},
error: function(){
alert("A problem occurred when moving this menu item. Please try again or contact support.");
}
});
},
handle:'.move-item',
connectWith:'#menu-table',
placeholder: "highlight",
containment: "parent",
revert: true,
tolerance: "pointer",
items: 'tbody > *'
});
JSFIDDLE
.prev only returns the immediately previous element, it doesn't keep looking for the nearest element that matches the selector. Use .prevAll to find all the elements matching a selector, and then use .first() to narrow it down to the first one, which is the nearest. And if you want to search for a specific data-menu-level attribute, you have to put that in the selector; calling .data("menu-level", 1) sets the attribute, it doesn't search for it.
if (menuLevel == 2) {
var findAboveRowName = $(".menu-table-rows[data-menu-nesting='" + newIndex + "']").prevAll(".menu-table-rows[data-menu-level=1]").first().data("menu-name");
alert(findAboveRowName);
}

setTimeout() doesn't seem to be working in Firefox?

I have inherited a website! which was designed to work in IE and only IE it seems.. I've now been asked to make the site run in Firefox. I've fixed most of the bugs without any problems but this one has me stumped.
setTimeout(fDelayedFunc, 1000);
This line of Javascript, works fine in IE but in Firefox the function fDelayedFunc never fires. I've removed the setTimeout and the function wrapper and tried running the code as part of the main function. This works without any problems at all.
There is alot of code involved but here's the main but I'm having trouble with. If you'd like to see anymore of the code please let me know.
setTimeout(fDelayedFunc, 0);
//Save the current text box value
var vCurrentTBValue = vJQElement.val();
function fDelayedFunc() {
if (vJQElement.val() == vCurrentTBValue) {
alert("test");
//Get position list box should appear in
var vTop = vJQElement.position().top + 25;
var vLeft = vJQElement.position().left;
//Had to put a special case in for account due to the position co-ords being wrong. This is due to a css error
if (vHiddenFieldToWriteTo == "#ctl00_ContentPlaceHolder1_hfAccountCode") {
vTop = vJQElement.position().top + 58;
vLeft = vJQElement.position().left + 200;
}
else {
vTop = vJQElement.position().top + 25;
vLeft = vJQElement.position().left;
}
//Create div element
var vDivElement = $("<div id='divSearchBox' style='position:absolute; top:" + vTop + ";left:" + vLeft + "; z-index: 40000;'></div>");
//Create list box
var vListBox = $("<select id='lbResults' tabIndex='" + vJQElement.attr("tabIndex") + "' size='4' style='height:400px;'></select>");
//Bind a function to the list box which will select the item via either tab or enter
vListBox.bind("keydown", function() {
//Check if tab or enter has been pressed
if (event.keyCode == 9 || event.keyCode == 13) {
//Set hidden value to the selected items code
$(vHiddenFieldToWriteTo).val($(vListBox.find(":selected")).val());
//Create postback
$('#ctl00_ContentPlaceHolder1_wizNewConsignment_btnRefresh').click();
}
//Check if the up arrow has been pressed at the top of the listbox
else if (event.keyCode == 38 && $(vListBox.find(":selected")).val() == $(vListBox.find(":first")).val()) {
//Focus back on the search box
vElement.focus();
}
}).bind("dblclick", function() {
//Set hidden value to the selected items code
$(vHiddenFieldToWriteTo).val($(vListBox.find(":selected")).val());
//Create postback
$('#ctl00_ContentPlaceHolder1_wizNewConsignment_btnRefresh').click();
});
//Get search field
var vSearchText = vJQElement.val();
var vDepotID = $("#ctl00_ContentPlaceHolder1_wizNewConsignment_hfDepotID").val();
var vCustomerID = $("#ctl00_ContentPlaceHolder1_wizNewConsignment_hfCustomerID").val();
var vCountryID = $("#ctl00_ContentPlaceHolder1_wizNewConsignment_hfCountryID").val();
var vConsignee = vJQElement.attr("boolConsignee");
//Set a loading image in place until call completed
vJQElement.css("backgroundImage", "url(images/small-loader.gif)");
vJQElement.css("backgroundRepeat", "no-repeat");
vJQElement.css("backgroundPosition", "right");
//Make AJAX call
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "NewConsignment.asmx/fGetAddressesAndIDs",
data: "{'strSearchText' : '" + vSearchText + "', 'intDepotID' : '" + vDepotID + "', 'intCustomerID' : '" + vCustomerID + "', 'intCountryID' : '" + vCountryID + "', 'boolConsignee' : '" + vConsignee + "'}",
dataType: "json",
success: function fGetAddressesAndIDsResult(GetAddressesAndIDsResult) {
//Make sure there are results
if (GetAddressesAndIDsResult != null && GetAddressesAndIDsResult != "") {
var vNumberOfResults = 0;
var vNumberOfLearntAddresses = 0;
var vLearntAddressUniqueID = "";
//Try to get results (first call will work on Linux and catch will work on Windows)
try {
//Check array exists (if this fails will go to catch)
if (GetAddressesAndIDsResult.d.length > 0) {
//Loop through the results
$.each(GetAddressesAndIDsResult.d, function() {
//Check for results
if (this.length > 0) {
//Evaluate JSON
var vAddress = eval("(" + this + ")");
//Create list item
var vOption = $("<option class='AddressOption' value='" + vAddress.uniqueID + "'>" + vAddress.briefDescription + "</option>");
//Find out number of learnt addresses
if (vAddress.uniqueID.indexOf("ConLA") != -1) {
vNumberOfLearntAddresses++;
vLearntAddressUniqueID = vAddress.uniqueID;
}
//Add list item to list box
vListBox.append(vOption);
//Mark result added
vNumberOfResults++;
}
});
}
}
catch (err) {
//Loop through the results
$.each(GetAddressesAndIDsResult, function() {
//Check for results
if (this.length > 0) {
//Evaluate JSON
var vAddress = eval("(" + this + ")");
//Create list item
var vOption = $("<option class='AddressOption' value='" + vAddress.uniqueID + "'>" + vAddress.briefDescription + "</option>");
//Find out number of learnt addresses
if (vAddress.uniqueID.indexOf("ConLA") != -1) {
vNumberOfLearntAddresses++;
vLearntAddressUniqueID = vAddress.uniqueID;
}
//Add list item to list box
vListBox.append(vOption);
//Mark result added
vNumberOfResults++;
}
});
}
//Check if only 1 learnt address was found
if (vNumberOfLearntAddresses == 1) {
//Auto select this address
//Set hidden value to the selected items code
$(vHiddenFieldToWriteTo).val(vLearntAddressUniqueID);
//Create postback
$('#ctl00_ContentPlaceHolder1_wizNewConsignment_btnRefresh').click();
}
//Add list box to div
vDivElement.append(vListBox);
//Check if any results exist in div
if (vNumberOfResults != 0) {
//Append div to page
$("body").append(vDivElement);
//Auto select first item
vListBox.find(".AddressOption:first").attr("selected", "true");
}
}
//Hide loading image
vJQElement.css("backgroundImage", "none");
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
//Inform user of error
alert("An error occured, please try again");
//Hide loading image
vJQElement.css("backgroundImage", "none");
}
});
}
}
Try this:
setTimeout(function() { fDelayedFunc(); }, 0);
I took setTimeout(function () {function1();}, 1500) out from the addEventListener("load", () => {code})
it worked for me inside Firefox
try this : setTimeout('fDelayedFunc()', 0);

Categories

Resources