I am allowing a user to select hours for each day of the week through the use of lists. Visually the lists are just boxes with 1am, 2am, 3am, etc inside them and when clicked are highlighted to show they are 'selected'. To do this I add a class of 'hour-selected' to the li item.
I also need to keep track of what hours the user has clicked for each day (those with class 'hour-selected'. I know this logic works as I have used this code before, but only for one day. In this example, I need to show all days on the same page.
With a few changes to my original code I came up with this, but I feel there must be some optimization I could do to prevent the repeating js used to push selected hours in for each day, but I am out of ideas and thoughts to do this...
html : (this would repeat for each day of the week with id different for day)
<ol id="hour-select-mon" class="clearfix">
<li class="">12am</li>
<li class="">1am</li>
<li class="">2am</li>
<li class="">3am</li>
<li class="">4am</li>
<li class="">5am</li>
<li class="">6am</li>
<li class="">7am</li>
<li class="">8am</li>
<li class="">9am</li>
<li class="">10am</li>
<li class="">11am</li>
<li class="">12pm</li>
<li class="">1pm</li>
<li class="">2pm</li>
<li class="">3pm</li>
<li class="">4pm</li>
<li class="">5pm</li>
<li class="">6pm</li>
<li class="">7pm</li>
<li class="">8pm</li>
<li class="">9pm</li>
<li class="">10pm</li>
<li class="">11pm</li>
</ol>
JS :
$('#hour-select-mon li, #hour-select-tue li, #hour-select-wed li, #hour-select-thu li, #hour-select-fri li, #hour-select-sat li, #hour-select-sun li').on('click', function() {
$(this).toggleClass('hour-selected');
});
// get selected hours in array
var monHours = var tueHours = var wedHours = var thuHours = var friHours = var satHours = var sunHours = [];
$('#hour-select-mon .hour-selected').each(function(k,v) {
monHours.push($(v).text());
});
$('#hour-select-tue .hour-selected').each(function(k,v) {
tueHours.push($(v).text());
});
$('#hour-select-wed .hour-selected').each(function(k,v) {
wedHours.push($(v).text());
});
$('#hour-select-thu .hour-selected').each(function(k,v) {
thuHours.push($(v).text());
});
$('#hour-select-fri .hour-selected').each(function(k,v) {
friHours.push($(v).text());
});
$('#hour-select-sat .hour-selected').each(function(k,v) {
satHours.push($(v).text());
});
$('#hour-select-sun .hour-selected').each(function(k,v) {
sunHours.push($(v).text());
});
Or if you want to collect all selected items at once you may use a code similar to this:
var selected = {};
$('.hour-selected').each(function(k,v) {
var day = $(v).parent().attr('id').substr(-3, 3);
selected[day] = selected[day] || [];
selected[day].push($(v).text());
});
Try this
var selectedHours = {};
$('ol > li').on('click', function() {
var li = $(this);
li.toggleClass('hour-selected');
var parentId = $(this).parent().attr("id");
selectedHours[parentId] ? selectedHours[parentId].push(li.text()) : selectedHours[parentId] = [li.text()]
});
selectedHours will have the following structure
{
"hour-select-mon" : ["4pm", "6pm"],
"hour-select-tue" : ["9am"],
...
}
Related
I have 2 sets of arrays which their value is grabbed by data-attribute(data-product-name), 1 is the whole list of available item, another 1 is selected item, for selected item they are attached to a country.
<!-- the item list -->
<div class="whole_list">
<ul>
<li data-product-name="a">item A<button>ATTACH</button></li>
<li data-product-name="b">item B<button>ATTACH</button></li>
<li data-product-name="c">item C<button>ATTACH</button></li>
<li data-product-name="d">item D<button>ATTACH</button></li>
<li data-product-name="e">item E<button>ATTACH</button></li>
</ul>
</div>
<!-- selected item block -->
<div class="selected_item_container">
<ul class="selected_items">
<li data-product-name="a">item A</li>
<li data-product-name="b">item B</li>
<li data-product-name="e">item E</li>
</ul>
<button class="edit_country">EDIT</button>
</div>
$('.edit_country').on('click', function () {
// to grab text/string from .whole_list data-product-name
var productName = []; // product name
$('.whole_list li').each(function (index) {
productName .push($(this).data('product-name'));
});
// to grab text/string from .selected_item_container data-product-name
var selProductName = []; // selected product name
$('.selected_item_container').find('[data-product-name]').each(function () {
selProductName .push($(this).data('product-name'));
});
// if the string/text matches, change the button text
$('.whole_list li').each(function (index) {
if ($(this).data('product-name') === arrProductName[index]) {
$(this).find('button').text('DETACH');
} else {
$(this).find('button').text('ATTACH');
}
});
});
Ideally is when user click on edit_country button, the .whole_list already have those selected item button changed to DETACH text. I tried, but the problem is, it only change the item A & item B button, item E button no changes.
I think it got to do with the indexing mismatch. I'm not sure, please advise, thanks.
Demo site
Use .indexOf to find if a value exists in an array.
Like this:
arrProductName.indexOf( $(this).data('product-name') ) != -1
Because, using $(this).data('product-name') === arrProductName[index]...
If your array is like:
var arrProductName = ["a","c","d"];
a will be found at index 0,
b will not be found,
c wil NOT be found at index 2... It is d,
d wil NOT be found at index 3... It is undefined,
e will not be found.
See it in CodePen.
Try the code below
$('.edit_country').on('click', function() {
// to grab text/string from .whole_list data-product-name
var productName = []; // product name
$('.whole_list li').each(function(index) {
productName.push($(this).data('product-name'));
});
// to grab text/string from .selected_item_container data-product-name
var selProductName = []; // selected product name
$('.selected_item_container').find('[data-product-name]').each(function() {
selProductName.push($(this).data('product-name'));
});
$(selProductName).each(function(index) {
$('.whole_list li[data-product-name=' + selProductName[index] + ']').find('button').text('DETACH');
});
});
How to append <li> to a <ul> on a button click.
I have tried below script, but want to have a number appended to the end of <li>. Like item 0, item 1, item 2, etc..
var list = document.getElementById("list");
var add = document.getElementById('addElem');
add.addEventListener('click', function() {
var itemsByTagName = document.getElementsByTagName("li");
list.innerHTML += '<li>item</li>'
});
<ul id="list">
<li>item
</li>
</ul>
<button id="addElem">Add</button>
Here is a example to get started.
Note: For production use you might need to handle the variable i through server/session/local storage variable.
var i = 1;
var list = document.getElementById("list");
var add = document.getElementById('addElem');
add.addEventListener('click', function() {
var itemsByTagName = document.getElementsByTagName("li");
list.innerHTML += '<li>item ' + i++ + '</li>'
});
<ul id="list">
<li>item
</li>
</ul>
<button id="addElem">Add</button>
I'm trying to append child to listing but what I want to do is to append it in the place ordering by data-price.
my template:
<ul>
<li data-price="18"></li>
<li data-price="27"></li>
<li data-price="28"></li>
<li data-price="31"></li>
<li data-price="99"></li>
<li data-price="101"></li>
<li data-price="191"></li>
</ul>
my js what I've tried so far:
var template = '<li data-price="100"></li>';
$('ul').find('li').filter(function() {
return $(this).attr("data-price") > 99;
}).after(template);
so if the price is 100 it should be appended by price ordering and in this case where price is greater then 99 but less then 101, but i dont have any working solution for that.
I'm not sure if this is the best way to do it and if it'll always work, but it works for your question. Try it out
var template = '<li data-price="100">100</li>';
var checkPrice = $(template).attr("data-price");
var appendBefore = $('ul li').filter(function(){
return parseInt($(this).attr("data-price")) > checkPrice-1;
})[0];
console.log(appendBefore);
$(appendBefore).before(template);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li data-price="18">18</li>
<li data-price="27">27</li>
<li data-price="28">28</li>
<li data-price="31">31</li>
<li data-price="99">99</li>
<li data-price="101">101</li>
<li data-price="191">191</li>
</ul>
check if that is what you need:
https://jsfiddle.net/3er0da9c/
var template = '<li data-price="100"></li>';
var itemValue = parseInt($(template).attr('data-price')); //Getting value that we should compare
var value, smaller = 0, smallerItem; //We will need those variables to know where to place our "template"
smallerItem = $('ul > li:first-of-type'); //Set the smaller item in our list to be the first one. Change that if your list wont be always asc sorted
$('ul > li').each(function(){ //run through the given list
value = parseInt($(this).attr('data-price'));
if ((itemValue == value) || ( itemValue > value )){ //if the actual item is equal, put our item right after it. If the item is smaller then our number, we save it and keep running
smaller = value;
smallerItem = $(this);
}
});
if (smaller != 0) //This will happens when we have at least one item smaller then our number
smallerItem.after(template);
else
smallerItem.before(template); //else, we add our number at top
I'm trying to check for a data attribute in multiple list items.
My HTML:
<ul id="year">
<li id="2006">2006</li>
<li id="2007">2007</li>
<li id="2008">2008</li>
<li id="2009">2009</li>
<li id="2010">2010</li>
<li id="2011">2011</li>
<li id="2012">2012</li>
<li id="2013">2013</li>
<li id="2014">2014</li>
</ul>
And this is the jQuery:
jQuery('#year li').click(function()
{
var year = jQuery(this).attr('id');
if ((jQuery(this).data('state') === undefined) || (jQuery(this).data('state') == "off"))
{
jQuery(this).data('state', 'on');
}
else
{
jQuery(this).data('state', 'off');
}
});
Now i am trying to check if there are any list items where the "state" == "on"
Like this:
if ((jQuery('#year li').data('state') == "on"))
But it does not seem to be working...
EDIT: So i tried all the different snippets you gave me: none of them worked so i made a simple for loop that looks in every list point itself:
for ( var y = 2006, l = 2015; y < l; y++ )
{
if ((jQuery('#year #'+y).data('state') == "on"))
{
alert('data found');
}
Another problem was that i didnt had any event before my code!
Thanks for the support!
the jQuery('#year li') will return an array of jquery objects.
you will need to loop each one
$('#year li').each(function () {
if ((jQuery(this).data('state') === "on")){
alert("on state found");
}
});
You can use .filter() then check length property
var list = jQuery('#year li').filter(function(){
return $(this).data('state') == "on";
//OR, using native dataset
//return this.dataset.state == 'on'
});
if (list.length){
//li with state on exits
}
The reason this doesn't work for you is that jQuery doesn't store data values in the "standard" element dataset. You can acheive your goal by doing that yourself:
$('#year li').click(function() {
this.dataset.state = this.dataset.state === 'off' ? 'on' : 'off';
if($('#year li[data-state="on"]').length > 0) {
alert('Found!')
}
});
#year li[data-state="on"] {
color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="year">
<li id="2006">2006</li>
<li id="2007">2007</li>
<li id="2008">2008</li>
<li id="2009">2009</li>
<li id="2010">2010</li>
<li id="2011">2011</li>
<li id="2012">2012</li>
<li id="2013">2013</li>
<li id="2014">2014</li>
</ul>
I want to retrive all the objects with one datakey and multiple values, for QuickSand:
<ul>
<li data-company="Microsoft">Steve</li>
<li data-company="Google">Jobs</li>
<li data-company ="Facebook">Michael</li>
<li data-company ="Google">Richard</li>
<li data-company ="Facebook">Tim</li>
</ul>
How can i retreve all the li items with data-company Microsoft and Google (these two values are in a array) like this:
var itemes = $('ul').find('li[data-comapany={"Microsoft","Google"}]');
Thank you.
you could create an array of the required companies, and check for each li if the data is contained in that array:
var companies = ["Microsoft", "Google"];
$(function() {
var items = $('ul li').filter(function() {
return $.inArray($(this).data("company"), companies) > -1;
});
items.css({
"position": "relative",
"margin-left": "25px"
});
console.log(items);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li data-company="Microsoft">Steve</li>
<li data-company="Google">Jobs</li>
<li data-company="Facebook">Michael</li>
<li data-company="Google">Richard</li>
<li data-company="Facebook">Tim</li>
</ul>
You could filter it:
var itemes = $('ul').find('li').filter(function(){
return $(this).data('company').match(/Microsoft|Google/);
});
-DEMO-
To handle case for LI without any data-company set, you should use:
var itemes = $('ul').find('li').filter(function(){
var data = $(this).data('company');
return data ? data.match(/Microsoft|Google/) : null;
});
You can also combine selectors:
var items = $("[data-company*='Microsoft'], [data-company*='Google']");
jsFiddle
You could do it like this:
var companies = ['Google', 'Microsoft', 'Waffle House'];
companies.forEach(function(company, index) {
companies[index] = "li[data-company='" + company + "']";
});
$('ul').find(companies.join(',')).css('background', 'red');