Dropdown menu save the choice on reload - javascript

I need to create popup language dropdown menu with country name, flag and link to the language version of the site. After user select menu item - it should take you to the needed url (language version of the page) and this choice should stay visible on the new page (after reload).
Example of the menu - https://prnt.sc/sjumj8 (https://www.farfetch.com/shopping/women/items.aspx)
Here is an example of what I'm trying to create: https://jsfiddle.net/Okean/8x0atLpy/62/
<ul class="list-unstyled" id="select-lang">
<li class="init">[SELECT]</li>
<li data-value="value 1"> <img src="https://image.flaticon.com/icons/svg/197/197615.svg"> Language 1 </li>
<li data-value="value 2"> <img src="https://image.flaticon.com/icons/svg/197/197386.svg">Language 2 </li>
<li data-value="value 3"> <img src="https://image.flaticon.com/icons/svg/197/197484.svg">Language 3 </li>
<li data-value="value 4"> <img src="https://image.flaticon.com/icons/svg/197/197380.svg">Language 4 </li>
</ul>
$("ul").on("click", ".init", function() {
$(this).closest("ul").children('li:not(.init)').toggle();
});
var allOptions = $("ul").children('li:not(.init)');
$("ul").on("click", "li:not(.init)", function() {
allOptions.removeClass('selected');
$(this).addClass('selected');
$("ul").children('.init').html($(this).html());
allOptions.toggle();
});
window.onload = function() {
var selItem = sessionStorage.getItem("SelItem");
$('#select-lang').val(selItem);
}
$('#select-lang').change(function() {
var selVal = $(this).val();
sessionStorage.setItem("SelItem", selVal);
});
body{
padding:30px;
}
ul {
height: 30px;
width: 150px;
border: 1px #000 solid;
}
ul li { padding: 5px 10px; z-index: 2; }
ul li:not(.init) { float: left; width: 130px; display: none; background: #ddd; }
ul li:not(.init):hover, ul li.selected:not(.init) { background: #09f; }
li.init { cursor: pointer; }
a#submit { z-index: 1; }
li img {
width: 20px;
}

You can use localStorage. Once user is selected an option, you can save it to browser's local storage where 'language' is your key and you can name it anything and where 'selectedOption' is the language user has selected.
// Set the preference
window.localStorage.setItem("language", selectedOption);
// Get the preference, anytime you want once set
window.localStorage.getItem("language")

Related

Dropdown menu - save the choice on reload

I need to create popup language dropdown menu with country name, flag and link to the language version of the site. After user select menu item - it should take you to the needed url (language version of the page) and this choice should stay visible on the new page (after reload). Example of the menu - https://prnt.sc/sjumj8 (https://www.farfetch.com/shopping/women/items.aspx)
Here is an example of what I'm trying to create: https://jsfiddle.net/Okean/8x0atLpy/62/
<body>
<ul class="list-unstyled" id="select-lang">
<li class="init">[SELECT]</li>
<li data-value="value 1"> <img src="https://image.flaticon.com/icons/svg/197/197615.svg"> Language 1 </li>
<li data-value="value 2"> <img src="https://image.flaticon.com/icons/svg/197/197386.svg">Language 2 </li>
<li data-value="value 3"> <img src="https://image.flaticon.com/icons/svg/197/197484.svg">Language 3 </li>
<li data-value="value 4"> <img src="https://image.flaticon.com/icons/svg/197/197380.svg">Language 4 </li>
</ul>
</body>
<script>
$("ul").on("click", "li:not(.init)", function() {
allOptions.removeClass('selected');
$(this).addClass('selected');
$("ul").children('.init').html($(this).html());
allOptions.toggle();
});
window.onload = function() {
var selItem = sessionStorage.getItem("SelItem");
$('#select-lang').val(selItem);
}
$('#select-lang').change(function() {
var selVal = $(this).val();
sessionStorage.setItem("SelItem", selVal);
});
</script>
<style>
body{
padding:30px;
}
ul {
height: 30px;
width: 150px;
border: 1px #000 solid;
}
ul li { padding: 5px 10px; z-index: 2; }
ul li:not(.init) { float: left; width: 130px; display: none; background: #ddd; }
ul li:not(.init):hover, ul li.selected:not(.init) { background: #09f; }
li.init { cursor: pointer; }
a#submit { z-index: 1; }
li img {
width: 20px;
}
</style>
<ul> tag element won't ever trigger a .change event,
you can't even use li.val() as it doesn't have an actual value attribue.
So you need to workaround a little, something like this
$(document).ready(() => {
// cache selectors for better performance
const listItem = $("ul");
const listSelected = listItem.find('.init');
const allOptions = listItem.children('li:not(.init)');
listItem.on('click', '.init', () => {
listItem.children('li:not(.init)').toggle();
});
listItem.on('click', 'li:not(.init)', (e) => {
const that = $(e.target);
const setHTML = that.html();
allOptions.removeClass('selected');
that.addClass('selected');
listSelected.html(setHTML);
allOptions.toggle();
sessionStorage.setItem('SelItem', setHTML);
});
const selectItem = $("#select-lang");
const storedItem = sessionStorage.getItem('SelItem');
if (storedItem) {
listSelected.html(storedItem);
}
});
this should work as expected, storing target <li> HTML inside SelItem on sessionStorage

Making ul li dropdown filter

I have a dropdown menu, now trying to use it as a filter. pass a value when I click the menu item start filtering But I am a bit confused at Jquery part. How to pass "name" & "value" and start filtering. And the important issue is when I click one item and filter. After that when I click next item, I don't want it to start over. I want to keep old history of search. and add it to new filter.
var allOptions = $(".init").children('li');
$("ul").on("click", function() {
allOptions.removeClass('selected');
$(this).addClass('selected');
$("ul").children('.init').html($(this).html());
allOptions.slideUp();
});
#filter-wrapper
{
margin-top:15px
}
#filter-wrapper ul
{
list-style:none;
position:relative;
float:left;
margin:0;
padding:0
}
#filter-wrapper ul a
{
display:block;
color:#333;
text-decoration:none;
font-weight:700;
font-size:12px;
line-height:32px;
padding:0 15px;
font-family:"HelveticaNeue","Helvetica Neue",Helvetica,Arial,sans-serif
}
#filter-wrapper ul li
{
position:relative;
float:left;
margin:0;
padding:0
}
#filter-wrapper ul li.current-menu-item
{
background:#ddd
}
#filter-wrapper ul li:hover
{
background:#f6f6f6
}
#filter-wrapper ul ul
{
display:none;
position:absolute;
top:100%;
left:0;
background:#fff;
padding:0
}
#filter-wrapper ul ul li
{
float:none;
width:200px
}
#filter-wrapper ul ul a
{
line-height:120%;
padding:10px 15px
}
#filter-wrapper ul ul ul
{
top:0;
left:100%
}
#filter-wrapper ul li:hover > ul
{
display:block
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<div id="filter-wrapper">
<ul>
<li name="sortbyprice" class="current-menu-item">Cheapest Cars</li>
<li name="sortbyprice" class="current-menu-item">Newest Cars</li>
<li>Car Color
<ul class="init" name="sortbycolor">
<li data-value="red">Red</li>
<li data-value="black">Black</li>
<li data-value="silver">Silver</li>
</ul>
</li>
</ul>
</div>
For example, when I select Red then Car Color changed with the Red.
P.S: And by the way the name="" that I gave, it comes from Laravel controller. It contains the data.
And this is the old filter of mine. It's working with this. I can filter the data.
<form>
<select name="sortbyprice" class="custom-select custom-select-md" style="width: 100px;">
<option value="asc">cheapest</option>
<option value="desc">Expensive</option>
</select>
<select id="cars" name="cars" class="custom-select custom-select-md" style="width: 100px;">
<option value="" disabled selected>car colors</option>
<option value="red">red</option>
<option value="blue">blue</option>
<option value="black">black</option>
</select>
<button type="submit" name="button" class="btn btn-success" id="filter-btn">Filter</button>
</form>
Not sure whether this is what you want, but you can try the code below and tell me what you think
var mockData = [
{
make: 'a',
color: 'red',
price: 1000
},
{
make: 'a',
color: 'black',
price: 2000
},
{
make: 'b',
color: 'red',
price: 1
},
{
make: 'a',
color: 'silver',
price: 3000
},
{
make: 'c',
color: 'black',
price: 1500
},
{
make: 'a',
color: 'red',
price: 1500
}
];
var allOptions = $('.init').children('li');
// use an object to store the filter options selected by the user
// you can then use the information in this object to do the filtering
// by sending an AJAX request or just filter the already fetched data
var filterOptions = {
sortbycolor: '',
sortbymake: '',
sortbyprice: ''
};
$(allOptions).on('click', function () {
// get the items' data-value
var value = $(this)[0].dataset.value;
// select the corresponding <a> tag
var button = $(this).parent()[0].previousElementSibling;
// get the corresponding name attribute, e.g. sortbycolor
var type = $($(this).parent()[0]).attr('name');
// set the filterOptions
filterOptions[type] = value;
// change the displayed text of the filter when the user select something
$(button).text(function (idx, content) {
// here I choose using a colon ':' as the separator,
// you can use whatever you want
var colonIndex = content.indexOf(':');
// example for baseContent is 'Car Color'
var baseContent = content;
if (colonIndex > -1) {
baseContent = content.slice(0, colonIndex);
}
// e.g 'Car Color: red
return baseContent + ': ' + value;
});
allOptions.slideUp();
console.log('update filterOptions: ', filterOptions);
// filter the already fetched data
var filteredData = mockData.filter(function (val) {
var isValid = true;
if (isValid && filterOptions.sortbycolor) {
isValid = val.color === filterOptions.sortbycolor;
}
if (isValid && filterOptions.sortbymake) {
isValid = val.make === filterOptions.sortbymake;
}
return isValid;
});
// sort the data by price
// hard-code the sorting direction here for simplicity,
// you can set this dynamically with the onclick event
filterOptions.sortbyprice = 'asc';
if (filterOptions.sortbyprice === 'asc') {
filteredData.sort(function (a, b) {
return a.price - b.price;
});
} else if (filterOptions.sortbyprice === 'desc') {
filteredData.sort(function (a, b) {
return b.price - a.price;
});
}
console.log('filteredData: ', filteredData);
// or you can send an ajax request to the server,
// and let the server handle the filtering for you
// you have to set the keys and values inside
// the 'data' youself, below is just an example
// as I don't know what your server's API looks like
$.get({
url: 'url-to-your-server',
data: {
color: filterOptions.sortbycolor,
make: filterOptions.sortbymake
},
success: function (response) {
// do something with the response,
// maybe it contains the filtered result
// however, I am not sure how does your API look like
}
});
});
// to deal with the left over css style(display: none) introduced by .slideUp()
$('.dropdown').on('mouseenter', function () {
allOptions.css('display', 'block');
});
console.log('initial filterOptions: ', filterOptions);
#filter-wrapper {
margin-top: 15px
}
#filter-wrapper ul {
list-style: none;
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul a {
display: block;
color: #333;
text-decoration: none;
font-weight: 700;
font-size: 12px;
line-height: 32px;
padding: 0 15px;
font-family: "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif
}
#filter-wrapper ul li {
position: relative;
float: left;
margin: 0;
padding: 0
}
#filter-wrapper ul li.current-menu-item {
background: #ddd
}
#filter-wrapper ul li:hover {
background: #f6f6f6
}
#filter-wrapper ul ul {
display: none;
position: absolute;
top: 100%;
left: 0;
background: #fff;
padding: 0
}
#filter-wrapper ul ul li {
float: none;
width: 200px
}
#filter-wrapper ul ul a {
line-height: 120%;
padding: 10px 15px
}
#filter-wrapper ul ul ul {
top: 0;
left: 100%
}
#filter-wrapper ul li:hover>ul {
display: block
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="filter-wrapper">
<ul>
<li name="sortbyprice" class="current-menu-item">Cheapest Cars</li>
<li name="sortbyprice" class="current-menu-item">Newest Cars</li>
<li class="dropdown">
Car Color
<ul class="init" name="sortbycolor">
<li data-value="red">Red</li>
<li data-value="black">Black</li>
<li data-value="silver">Silver</li>
</ul>
</li>
<li class="dropdown">
Make
<ul class="init" name="sortbymake">
<li data-value="a">A</li>
<li data-value="b">B</li>
<li data-value="c">C</li>
</ul>
</li>
</ul>
</div>
I eliminated your css, you are just interested in the color value - correct ?
<div id="filter-wrapper">
<ul>
<li name="sortbyprice" class="current-menu-item">Cheapest Cars</li>
<li name="sortbyprice" class="current-menu-item">Newest Cars</li>
<li>Car Color
<ul class="init" name="sortbycolor">
<li>Red</li>
<li>Black</li>
<li>Silver</li>
</ul>
</li>
</ul>
</div>
<script>
var allOptions = $(".init").children('li');
// I think you are only interested in the html content of the a (anchor)
$("li[data-value] > a").on("click", function(e) {
e.preventDefault();
allOptions.removeClass('selected');
$(this).addClass('selected');
let filterVal = $(this).data('value'); // do something with this ...
let li = $('<li />').html( filterVal);
$("ul.init").html('').append( li); // ul.init just has the value of the filter
// allOptions.slideUp(); // superfluos
});
</script>

showing submenu one by one on hover

Actually, I am trying to make a sub-menu where user hovers on the first menu its child list should appear one after one and same on the other menu.
I think it is working fine just a minor problem. I am going to the 2nd or 3rd menu before the complete appearing of the first menu's child. 2nd and 3rd are working fine but again if I hover on the first menu it still shows the remaining list (child) which was left to appear.
(function($) {
$.fn.animateOneByOne = function(params) {
params = $.extend({
css: '',
duration: 700,
interval: 300,
order: 'ASC',
callback: ''
}, params);
if (params.order == 'ASC') {
elements = $(this);
} else {
elements = $(this).get().reverse();
}
count = $(this).length - 1;
$(elements).each(function(id) {
setTimeout(function(element) {
if (id == count) {
$(element).animate(params.css, params.duration, params.callback);
} else {
$(element).animate(params.css, params.duration);
}
}, id * (params.interval + params.duration), $(this));
});
};
})(jQuery);
$('.srvs_dropdown').hover(function() {
$(this).find("ul li").animateOneByOne({
css: {
opacity: '1'
},
duration: 450,
interval: 100
});
return false;
},
function() {
$(this).find("ul li").css("opacity", 0);
});
.srvs_dropdown li {
opacity: 0;
}
a {
color: #fff;
}
.pi-mm-list {
padding-left: 20px;
background-color: #09142D;
width: 250px;
color: #fff;
}
.pi-mm-list li ul {
display: none;
position: absolute;
left: 180px;
width: 234px;
padding-top: 7px;
background-color: #09142D;
z-index: 999;
}
.pi-mm-list li:hover ul {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="pi-mm-list">
<li class="srvs_dropdown">Network Security
<ul>
<li>Firewall and VPN</li>
<li>Web Security</li>
<li>Application Security</li>
<li>Threat Detection & Response</li>
<li>Data Leakage Prevention</li>
<li>IPS</li>
</ul>
</li>
<li class="srvs_dropdown">Endpoint Security
<ul>
<li>Antivirus</li>
<li>DLP</li>
</ul>
</li>
<li class="srvs_dropdown">Wireless Security
<ul>
<li>Access Point</li>
<li>Controller</li>
</ul>
</li>
</ul>
As far as I have understood or observed your question and code, looks like it only works correctly when you hover over all links for the first time top to bottom but once you reach the last menu item in the first block and start hovering in reverse from bottom to top you will see that the submenu links start appearing in randomly, problem is the delay that you have used you just need a small fix i.e incremental delay which you were missing. The code below it works as you expect, observe the difference in the $(elements).each(function(id) { just replace the setTimeOut with delay and add the increment there and watch the difference, you can remove the interval param too see below code and working example, hope it solves the problem.
(function($) {
$.fn.animateOneByOne = function(params) {
params = $.extend({
css: '',
duration: 700,
order: 'ASC',
callback: ''
}, params);
if (params.order == 'ASC') {
elements = $(this);
} else {
elements = $(this).get().reverse();
}
count = $(this).length - 1;
$(elements).each(function(id) {
let isLastLi = id == count;
console.log('animate', id);
(isLastLi) ? $(this).delay((id + 1) * params.duration).animate(params.css, 0, params.callback): $(this).delay((id + 1) * params.duration).animate(params.css, 0);
});
};
})(jQuery);
$('.srvs_dropdown').hover(function() {
console.log('here');
$(this).find("ul li").animateOneByOne({
css: {
opacity: '1'
},
duration: 400
});
return false;
},
function() {
$(this).find("ul li").stop().css("opacity", 0);
});
.srvs_dropdown li {
opacity: 0;
}
a {
color: #fff;
}
.pi-mm-list {
padding-left: 20px;
background-color: #09142D;
width: 250px;
color: #fff;
}
.pi-mm-list li ul {
display: none;
position: absolute;
left: 180px;
width: 234px;
padding-top: 7px;
background-color: #09142D;
z-index: 999;
}
.pi-mm-list li:hover ul {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="pi-mm-list">
<li class="srvs_dropdown">Network Security
<ul>
<li>Firewall and VPN</li>
<li>Web Security</li>
<li>Application Security</li>
<li>Threat Detection & Response</li>
<li>Data Leakage Prevention</li>
<li>IPS</li>
</ul>
</li>
<li class="srvs_dropdown">Endpoint Security
<ul>
<li>Antivirus</li>
<li>DLP</li>
</ul>
</li>
<li class="srvs_dropdown">Wireless Security
<ul>
<li>Access Point</li>
<li>Controller</li>
</ul>
</li>
</ul>
The main idea is to cancel timed-out function when it doesn't need to execute. It looks that out part in .hover(in, out) is the best place to do it. But first we need a list of setTimeout handlers which are generated in the in part. Something like this.
(function($) {
$.fn.animateOneByOne = function(params) {
params = $.extend({
css: '',
duration: 700,
interval: 300,
order: 'ASC',
callback: ''
}, params);
if (params.order == 'ASC') {
elements = $(this);
} else {
elements = $(this).get().reverse();
}
count = $(this).length - 1;
var handlers = [];
$(elements).each(function(id) {
var handle = setTimeout(function(element) {
if (id == count) {
$(element).animate(params.css, params.duration, params.callback);
} else {
$(element).animate(params.css, params.duration);
}
}, id * (params.interval + params.duration), $(this));
handlers.push(handle);
});
return handlers;
};
})(jQuery);
$('.srvs_dropdown').hover(function() {
$(this).data('handler',
$(this).find("ul li").animateOneByOne({//returns the list of handlers
css: {
opacity: '1'
},
duration: 450,
interval: 100
}));
return false;
},
function() {
$(this).data('handler').forEach(function(handle) {
clearTimeout(handle); //cancel setTimeout if it didn't start yet
});
$(this).find("ul li").css("opacity", 0);
});
.srvs_dropdown li {
opacity: 0;
}
.pi-mm-list {
padding-left: 20px;
}
.pi-mm-list li ul {
display: none;
position: absolute;
left: 180px;
width: 234px;
padding-top: 7px;
background: #09142D;
z-index: 999;
}
.pi-mm-list li:hover ul {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="pi-mm-list">
<li class="srvs_dropdown">Network Security
<ul>
<li>Firewall and VPN</li>
<li>Web Security</li>
<li>Application Security</li>
<li>Threat Detection & Response</li>
<li>Data Leakage Prevention</li>
<li>IPS</li>
</ul>
</li>
<li class="srvs_dropdown">Endpoint Security
<ul>
<li>Antivirus</li>
<li>DLP</li>
</ul>
</li>
<li class="srvs_dropdown">Wireless Security
<ul>
<li>Access Point</li>
<li>Controller</li>
</ul>
</li>
</ul>

Go to Specified text in ul li based select box

i want to have functionality such as that of select box, when using select box, if we type some keyword and that keyword happens to match in that select box, the pointer moves to the specified text, i want to achieve similar functionality here, following is my HTML
Get Value
<ul>
<li class="init">SELECT</li>
<li data-value="value 1">1</li>
<li data-value="value 2">2</li>
<li data-value="value 3">3</li>
</ul>
Following is my JS
$("ul").on("click", ".init", function() {
$(this).closest("ul").children('li:not(.init)').toggle();
});
var allOptions = $("ul").children('li:not(.init)');
$("ul").on("click", "li:not(.init)", function() {
allOptions.removeClass('selected');
$(this).addClass('selected');
$("ul").children('.init').html($(this).html());
allOptions.toggle();
});
$("#submit").click(function() {
alert("The selected Value is "+ $("ul").find(".selected").data("value"));
});
Following is my CSS
ul {
height: 30px;
width: 150px;
border: 1px #000 solid;
}
ul li { padding: 5px 10px; z-index: 2; }
ul li:not(.init) { float: left; width: 130px; display: none; background: #ddd; }
ul li:not(.init):hover, ul li.selected:not(.init) { background: #09f; }
li.init { cursor: pointer; }
a#submit { z-index: 1; }
Fiddle
http://jsfiddle.net/Starx/a6NJk/2/
Check out something like chosen or selectize. Download their files and add them to your site. if you go with Chosen you can initialize the plugin by adding .chosen-select to your form element:
<select class="chosen-select">
<option>Hello</option>
<option>Whats Up</option>
<option>How Are You</option>
<option>Nice to See You</option>
<option>Goodbye</option>
</select>
EXAMPLE

jQuery UI Snap to Element then Resize to fit container

https://jsfiddle.net/tk48ecxb/24/
Here is an example of the code I'm working with. It works fairly well with larger sizes but it breaks the small size boxes. Not sure why its moving them when removing resized boxes, that isn't happening in the actual project I'm working on. Need the boxes, which are actually svg's in the project, to fill the width of the larger boxes and not really be choppy or attach in weird ways.
Also, anyway to trigger an event when all boxes are filled?
HTML
<div class="top-row">
<ul class="holderList">
<li class="holder" id="large"></li>
<li class="holder" id="medium"></li>
<li class="holder" id="small"></li>
<li class="holder" id="tiny"></li>
</ul>
</div>
<div class="bottom-row">
<ul>
<li class="square" id="square1">
</li>
<li class="square" id="square2"></li>
<li class="square" id="square3"></li>
<li class="square" id="square4"></li>
</ul>
</div>
CSS
ul li{
border: 1px solid black;
display: inline-block;
}
.holderList > li{
margin: 20px;
}
#large{
height: 200px;
width: 200px;
}
#medium{
height: 150px;
width: 150px;
}
#small{
height: 100px;
width: 100px;
}
#tiny{
height: 50px;
width: 50px;
}
.square{
height: 60px;
width: 60px;
background: green;
}
JS
$(".square").draggable({
drag: function(event, ui) {
var draggable = $(this).data("ui-draggable");
$.each(draggable.snapElements, function(index, element) {
ui = $.extend({}, ui, {
snapElement: $(element.item),
snapping: element.snapping
});
if (element.snapping) {
if (!element.snappingKnown) {
element.snappingKnown = true;
draggable._trigger("snapped", event, ui);
}
} else if (element.snappingKnown) {
element.snappingKnown = false;
draggable._trigger("snapped", event, ui);
}
});
},
snap: ".holder",
snapMode: "inner",
snapped: function(event, ui) {
var squareWidth = ui.snapElement.width();
var squareHeight = ui.snapElement.height();
ui.helper.css({width: squareWidth, height: squareHeight});
}
});
All I need to do was add snapTolerance apparently.
Now to figure out how to create a popup if all windows are filled.

Categories