Why focusout event is not fired - javascript

I created code for dropdown menu instead of classic select menu which I am not able to style. I have last step to remove dropdown list if focusout event is fired, but I ahve this problem. It is not working for one element in my code.
I am thinking a long time why it is not fired focusout event on this element inputSelectSubCat = $("input[name=subcategory]"); or generally var inputSelect = $('.add-item__input-select');.
In firefox developer console it is added action for this event, but it is never fired.
Thank you very much for your advices.
This is my code:
/* SELECT CATEGORIES AND FILTER CONNECTIONS*/
// Declare variables
var inputSelectCat = $("input[name=category]"),
inputSelectSubCat = $("input[name=subcategory]"),
arrowDown = inputSelectSubCat.next(),
catNameOld;
// Defaultly setup subcategory input as disable until category is not chosen
inputSelectSubCat.addClass('stop');
// Disable placeholder hidding - disable focus event
inputSelectSubCat.on('mousedown', function() {
event.preventDefault();
});
// Defaultly hide arrowdown of input subcategory until category is not chosen
inputSelectSubCat.next().hide();
inputSelectCat.on('focusin', function() {
catNameOld = $(this).val();
});
localStorage.clear();
// If change value of category then change options of subcategory
inputSelectCat.on('focusout', function() {
var catNameNew = $(this).val(),
arrowDown = inputSelectSubCat.next();
// Send cat id to add.php to change select options in html according to cat id
$.ajax({
url: 'add.php',
type: 'post',
data: {
cat_name_js: catNameNew
}
}).done(function(html) {
var subCatMenuNew = $(html).find('select[name=subcategory]'),
subCatMenuCurrent = $('#section-info').find('select[name=subcategory]');
// Replace current select by new one - data for dropdown list are loaded from select
subCatMenuCurrent.html(subCatMenuNew);
})
// Allow subcategory input always if category is chosen and value is not empty
if (catNameNew !== '') {
arrowDown.show();
inputSelectSubCat.removeClass('stop');
}
// If different category is chosen, then clear input value
if (catNameOld !== catNameNew) {
inputSelectSubCat.val('');
}
});
// If change value of category then change options of subcategory
inputSelectSubCat.on('focusout', function() {
$('#filters, #section-filters').show();
});
/* SELECT REPLACED BY DIV JS */
var inputSelect = $('.add-item__input-select');
// Add new div with options after click on select
inputSelect.on('click', function(event) {
event.preventDefault();
var currentNewDropdown = $(this).next(),
currentInput = $(this),
currentSelect = $(this).parent().find('select');
// Do not allow to add dropdown list for subcategory if it has class 'stop'
if ( !currentInput.hasClass('stop')) {
// Check if new div dropdown already exists if not add new one
if ( !currentNewDropdown.hasClass('add-item__custom-select-box') ) {
var newDropdown = $('<div/>') // create new div element
.addClass('add-item__custom-select-box') // with class NewDropdown
.insertAfter($(this)); // and append it to page
}
}
// If select was already clicked on, then do not create new dropdown list
if ( !currentInput.hasClass('added') ) {
// Check each option value and attach it to new dropdown as div
currentSelect.find('option').each(function(index, element) {
var option = $(this); // this is the option from the original select
currentNewDropdown = $(this).parent().next();
// If option is disabled do not append it to new dropdown list
if (!option.prop('disabled')) {
// Create dropdown list as copy of original select list
var newOption = $('<div/>') // create new div element
.addClass('add-item__custom-select-box-items') // with class NewDropdown-item
.html(option.html()) // copy content from original option
.data('value', option.val()) // copy value from original option
.appendTo(newDropdown); // append it to the new dropdown
}
})
// Show new dropdown options after click on select
if ( !currentInput.hasClass('stop')) {
currentNewDropdown = $(this).next();
currentNewDropdown.show();
currentInput.addClass('added');
}
}
});
// Remove dropdown list if focusout without value chosen
inputSelect.on('focusout', function() {
console.log('2');
var newDropdown = $(this).parent().find('.add-item__custom-select-box'),
inputValue = $(this).val();
newDropdown.remove();
inputSelect.removeClass('added');
inputSelect.addClass('black-text');
});
// Add value of clicked element to original option
$('.add-item__input-wrapper').on('mousedown','.add-item__custom-select-box-items', function() {
var clickedOptionText = $(this).text(), // Get choosen otion text
clickedOptionVal = $(this).data('value'), // Get choosen option value
currentInput = $(this).parent().prev(),
currentSelect = $(this).parent().parent().find('select'),
newDropdown = $(this).parent();
currentSelect.val(clickedOptionVal); // Set up value of original select
currentInput.val(clickedOptionText); // Show chosen value in input
newDropdown.remove();
inputSelect.removeClass('added');
inputSelect.addClass('black-text');
});

Related

Event Handler for Input values and select option together

I have multiple input values with one select box option and validating and capturing all data based on keypress event. My issue is get all data input fields and select box and send using keypress event
To find all input values
var all_details = $('.myform');
var all_inputs = all_details.find('input');
var all_details_complete;
to get select values
var Country = $('#country').children("option:selected").val();
Adding few more additional data
var some_data = {
Country: Country, //select box title displaying on image
ReceiveOffers: 0
};
Bind event! With following function I am getting all input field data except select box data. how can I add select change event and have tried following?
all_inputs.on('keypress onchange', function() {
all_details_complete = false;
_.each(all_inputs, function (input) {
var $input = $(input);
all_inputs[$input.attr('name')] = $input.val();
if ($input.val() === '') all_details_complete = false;
});
if (all_details_complete) {
// post data successfully
}
});
That is because there is no onchange event, but a change event instead:
all_inputs.on('keypress change', function() {
// Rest of the code here
};
However, for ease of standardization it's way easier to simply listen to the input event:
all_inputs.on('input', function() {
// Rest of the code here
};

Isotope v2 Grid - Multiple Filters - Hide empty filters

My current isotope grid has two dropdown filters that sort the grid items. The first filter is menu type, and the second filter is drink type. Each menu type however does not contain all drink types so when some filter configurations are chosen, no results are showed, which is correct. But i would like to stop this from happening by when the user selects the first filter, the second filter hides the empty types.
Working Codepen of current filters: https://codepen.io/whitinggg/pen/zYGEaNb
This was my old filter code:
// Select Filters
jQuery(function ($) {
var $grid = $('.grid');
var $selects = $('div#filterGroup select').change(function() {
var selector = $selects.get().map(function(el) { // map the select elements ...
return $(el).val(); // ... to an array of values
}).join('') || '*'; // if joined array is empty-string, then default to a single '*'
$grid.isotope({
'filter': selector
});
return false;
});
$grid.imagesLoaded().progress( function() {
$grid.isotope('layout');
});
});
I have tried to change my code to the below from other links around the internet on this topic but havent had any luck getting it to work.
// Select Filters
jQuery(function ($) {
var $grid = $('.grid');
var $selects = $('div#filterGroup select').change(function() {
var selector = $selects.get().map(function(el) { // map the select elements ...
return $(el).val(); // ... to an array of values
}).join('') || '*'; // if joined array is empty-string, then default to a single '*'
$grid.isotope({
'filter': selector
});
return false;
});
//Hide Empty Filters
var DROP = $('div#filterGroup select option:not([data-filter=""])');
// list of all class in html
var strall = ''; $('.grid-item').each(function(el){ strall += $(this).attr('class') });
// remove select if not in strall.. TODO : needs improvement, this is kind a hack
DROP.each(function(el){
var nowfilter = $(this).attr('data-filter').replace('.', ''); // co_kenya
if( strall.indexOf( nowfilter ) == -1 ){
console.log( 'this one is missing ' + nowfilter );
$(this).remove();
}
});
$grid.imagesLoaded().progress( function() {
$grid.isotope('layout');
});
});
Is this possible? Any help much appreciated!
Working codepen
First, add an ID to each drop-down so that we can distinguish them.
<select id="menu-selector" class="filter option-set" data-filter-group="menu">
[...]
<select id="type-selector" class="filter option-set" data-filter-group="categories">
Then, for each drop-down, add a change listener. We'll look at the code for the menu drop-down change listener.
First, get the class filter from the selected drop-down:
$('#menu-selector').change(function() {
var selectedClass = $('#menu-selector option:selected').attr('value');
Then we're going to select all of the grid items matching that type, to see what other classes they have. These other classes will be the available types
var availableTypes = $(`.grid-item${selectedClass}`)
.toArray()
.flatMap(div => Array.from(div.classList.values())) //get all of the classes
.filter(i => !['grid-item', selectedClass.substring(1)].includes(i)); //eliminate useless ones
Last, toggle the disabled property on the other drop-down, enabling only those that are available.
$('#type-selector option')
.each( (i,el) => $(el).prop('disabled', el.value != "" && !availableTypes.includes(el.value.substring(1))));
That should do it. The change handler for the type drop-down is the same but references the opposite drop-down. Check the codepen for details.

Using UI Sortable, move item to new location based on a given value when I click a button?

Is there a way to force the UI Sortable to change item position in a list when I click some link or a button that pass a value to any of the possible UI events?
Here the Sortable function:
$("#sortable").sortable({
start: function(event, ui) {
// ...
},
update: function(event, ui) {
// ...
},
stop: function(event, ui) {
// ...
}
});
And here is the even of a button which update the value of a text input in spicific row ... It actually fires an Ajax but I'm making it simple here:
$("#sortable tr").on("click", ".row-button", function () {
var sort_id = $this.closest('tr').find('.text-sort-id').val();
...
...
});
UPDATE:
Here is a jsFiddle result of what I did till now. I need to be able when I change the input in second row for example to "5" and click change it visually move to the bottom of the table and so on when change the fourth row input to "1".
I want to be able to change item value when click the change button without resetting all others and from another side, be able to drag any row and change its input value to be less than the one after and more then the input before it and this all happens without changing other values even if we needed to set an equal value.
Please see the comments in the code for an explanation of what I'm doing. I've updated the .sort-btn click event with the following code:
$(".grid-sort-table tbody tr").on("click", ".sort-btn", function() {
var allItems = $('.ui-sortable').children();
//Select all of the input values
var orderedInputValues = $.map(allItems, function(item) {
return $(item).find('input').val();
});
//Order the input values (smallest to largest, by default)
orderedInputValues = orderedInputValues.sort();
//Store the "tr" in a variable so it can be manipulated.
var selectedItem = $(this).closest('tr');
var selectedItemVal = $(selectedItem).find('input').val();
var indexToInsertAt = 0;
for (var i = 0; i < orderedInputValues.length; i++) {
if (orderedInputValues[i] == selectedItemVal) {
indexToInsertAt = i;
break;
}
}
//Find the item at the index the selected item will be inserted at (before or after)
var itemAtIndex = allItems[indexToInsertAt];
//If the selected item's value is greater than the item at the required index, insert it after the item.
if ($(selectedItem).find('input').val() > $(itemAtIndex).find('input').val()) {
selectedItem.insertAfter(itemAtIndex);
}
else { //Otherwise, insert it before the item at the required index.
selectedItem.insertBefore(itemAtIndex);
}
//Additional code below
...
});
Updated Fiddle

How do I prevent duplicate entries in a row at chosen jQuery multiple select?

I have several rows with few select boxes. There are several select boxes in each row with the same content. Every item in the row can only be used once, because every column has a classification. If an item is used in a select box, I want it to be greyed out in the other boxes of the row.
I tried this:
function setChosen() {
var config = {
'.chosen-select' : {},
'.chosen-select-deselect': {allow_single_deselect:true},
'.chosen-select-no-single' : {disable_search_threshold:10},
'.chosen-select-no-results': {no_results_text:'Oops, nothing found!'},
'.chosen-select-width' : {width:'95%'}
}
for(var selector in config) {
$(selector).chosen(config[selector]);
}
}
setChosen();
$('.chosen-select').on('change', function() {
var selVal = $(this).val();
var rel = $(this).attr('rel');
$('.'+rel).children('option').each(function() {
if($(this).val() == selVal) {
$(this).attr('disabled',true).siblings().removeAttr('disabled').trigger('chosen:updated');
}
});
});
fiddle
I would do this:
From the select that fires the onchange event we can travel up in the DOM to its parent using jQuery's parent(). Then select all the select elements in that parent. Iterate over each select. First reset the option back to enabled, lastly disable the option that matches the selected value of the select that fired the event.
$('.chosen-select').on('change', function() {
var self = this; //create a reference to the owner of the event.
var selVal = $(this).val(); //selected value
var parent = $(this).parent(); //select parent row
//traverse all children in that row that are selects
parent.children('select').each(function() {
$(this).find("option").attr("disabled", false); //set all disabled attributes to false. Basically a reset!
if (this != self) //skip the select that is the owner of the event
{
//set the other options to disabled that matches the value of the select.
$(this).find("option[value='"+selVal+"']").attr("disabled", true);
}
});
});

Link Select Input to Another Input

I want my inputs to link to the other input using jQuery, while the all 3 inputs stays at their places and not vanish.
Input 1 -> Input 2 -> Input 3 ->
Selected Choose option Choose option
Finally, when the user click on all selection, the "Go button" will appear next, and will have a unique hyperlink inside.
like that:
Input 1 -> Input 2 -> Input 3 -> Go Button (with unique hyperlink to each selection)
Selected Choose option Choose option
I have seen this Add input text when option selected, but this is don't what I need, but the opposite.
Something like that http://jsfiddle.net/Mm2mu/2/ but without the radio boxes.
See here the image example http://oi62.tinypic.com/kew60n.jpg
One solution would be to watch inputs with specific class all disabled. Check if they got value set up and eventually enable next input with same class within the same form.
$(document).ready(function() {
var $forms = $('form');
$forms.each(function(){
var $form = $(this);
// scan each form for inputs with .input-step class
var $steps = $(this).find('.input-step');
if ( $steps.length > 0 ) {
$steps.not(':first').prop('disabled', true);
$steps.change(function(){
var val = $(this).val();
if ( val !== '' ) {
checkSubmitAvailability($form);
$form.find('.input-step:disabled:first').prop('disabled', false);
}
});
}
});
});
// Checks if all steps were made
// eventually enables submit actions
function checkSubmitAvailability($form) {
if ($form.find('.input-step:disabled').length === 0 ) {
$form.find('.input-finish').each(function(){
$(this).removeClass('hidden');
if ( typeof $(this).attr('href') !== 'undefined' ) {
// element has attribute href, add data to this attribute
var data = $form.find('.input-step');
$(this).attr('href', $(this).attr('href') + '?' + data.serialize());
}
});
}
}
Im using one form as scope and input with class "input-step" here, but that could be any other.
Here is a fiddle http://jsfiddle.net/hMEad/19/
I just add:
$('input').hide();
http://jsfiddle.net/guinatal/Mm2mu/4/

Categories

Resources