I'm trying to count the articles in the top row of the two boxes on the page.
The boxes are separate and I want the count to be like that too -
function calculateArticlesInRow() {
var articleInRow = 0;
$('.promotionWrapper').each(function() {
console.log($(this).prev().length);
if($(this).prev().length > 0) {
console.log($(this).offset().top + '='+ $(this).prev().offset().top);
if($(this).offset().top != $(this).prev().offset().top){
return false;
}
articleInRow++;
}
else {
articleInRow++;
}
});
$('.result1').html('No: of articles in a row = ' + articleInRow);
}
setTimeout(function(){
calculateArticlesInRow();
}, 3000);
The problem I'm having however, is that the script is counting the articles in both boxes when only the articles with a certain top offset should be counted.
I have found other questions like this, but the all seem to use only one box.
Any help would be appreciated.
Here is a fiddle so you can see what I'm trying to do: https://jsfiddle.net/JackofD/de31nojn/
Thanks in advance
I think you should count the .promotionWrapper articles for each .productWrapper section.
i've updated your fiddle.
var articleInRow = 0,
maxArtNo = 0;
// cycle for every .productWrapper
$('.productWrapper').each(function (index, el) {
articleInRow = 0
// cycle for every .promotionWrapper in this .productWrapper
$('.promotionWrapper', el).each(function (innerIndex, innerEl) {
//your code
});
//set the count to the max
if (articleInRow > maxArtNo) maxArtNo = articleInRow;
});
// rest of your code
Try something like this:
$('.contentWrapper').each(function(){
//finds how many articles in the current container
console.log($(this).find('.promotionWrapper').length);
});
But to get each container individually, maybe you should put a separate class on each section tag instead.
You are counting all the sections with "promotionWrapper" class. To count the 1st row only, you need to select its parent section first and then count children of that. Here is the code:
$('.productWrapper:first').children('.promotionWrapper').each(function () {
console.log($(this).prev().length);
if ($(this).prev().length > 0) {
console.log($(this).offset().top + '=' + $(this).prev().offset().top);
if ($(this).offset().top != $(this).prev().offset().top) {
return false;
}
articleInRow++;
} else {
articleInRow++;
}
});
Sorry, my bad. Didnt see the jsfiddle.
Here is a working solution independent of your code:
var articlesInRow = [];
$('.productWrapper').each(function (index) {
articlesInRow[index] = $(this).find('.promotionWrapper').length;
$('.result' + (index+1)).html('No: of articles in row' + (index + 1) + ' = ' + articlesInRow[index]);
});
which i added to your calculateArticlesInRow function.
Please see updated jsfiddle:
https://jsfiddle.net/de31nojn/15/
Related
So I have a container with a grid of items and I want to be able to detect hover between rows. Not the individual items.
Its important to remember that the number of items, in the container and per row, will change.
My container of items currently looks like this
<div class="container">
<div class="hover-placeholder"></div>
<div class="row">
<!-- Start : Items -->
<div class="col-md-3">...</div>
<div class="col-md-3">...</div>
<div class="col-md-3">...</div>
<div class="col-md-3">...</div>
...
<div class="col-md-3">...</div>
<!-- End : Items -->
</div>
</div>
Preferably I DO NOT want to put a placeholder element every 4th item. Mainly because on smaller screens the number of items per row will reduce. This is why in my example above I have a single placeholder outside the grid that I want to transform: translateY(..) to the position between the hovered rows.
This is what I have currently: https://jsfiddle.net/0t8c0h4m/
Its nowhere near the result I am after but I have got to the point where I am overthinking it and getting stuck.
Any help would be great!
UPDATE
The goal for this functionality is when the user hovers the negative space, the .hover-placeholder will translate to that position and become visible. And when clicked will add a permanent separator between the rows.
SUCCESS!
I have solved my issue! Thank you all for your help.
Here is my solution: https://jsfiddle.net/0t8c0h4m/9/
I think that you are complicating stuff too much if you are only looking for the hover effect between the elements and nothing else.
Updated:
var offsets;
function get_offsets() {
offsets = {};
$('.card').each(function() {
var $this = $(this);
var card_offset = $this.offset().top;
offsets[card_offset] = {
ele: $this
};
})
}
get_offsets();
function get_last_ele(mouse_location) {
var element;
var previous_key;
$.each(offsets, function(key, obj) {
if (key > mouse_location && previous_key > 0) {
element = offsets[previous_key].ele;
return false;
}
previous_key = key;
})
return element;
}
$('.container').mousemove(function(e) {
if ($(e.target).parents('.row').length == 0) {
var last_item_row = get_last_ele(e.pageY)
console.log(last_item_row.text())
}
});
JSFiddle: https://jsfiddle.net/0t8c0h4m/6/
I'm only providing the code that gets the last item on the row before the space you are hovering. From there you can append the line or transition the placeholder the way you like it.
Please try with following script
(function($) {
'use strict';
// Count items per row
function items_per_row($collection) {
var count = 0;
$collection.each(function() {
var $this = $(this);
if ($this.prev().length > 0) {
if ($this.position().top !== $this.prev().position().top) {
return false;
} else {
count++;
}
} else {
count++;
}
});
var last = count ? $collection.length % count : 0,
rows = count ? Math.round($collection.length / count) : 0;
if (last == 0) {
last = count;
}
return {
count: count,
last: last,
rows: rows
}
};
// On card hover, print current row
$('.card').mouseenter(function() {
var $card = $(this);
var item_count = items_per_row( $('.card') ),
index = $(this).index(),
current_row = Math.floor(index / item_count.count) + 1;
$('pre').text( $card.find('.inner').text() + ' is in row '+ current_row );
});
$('.card').mouseout(function(){
$('pre').text('');
});
})(jQuery);
So I have come up with a solution to show dividers between each row using CSS. I just have been overthinking this issue.
I have added a dividing element after each item and with css nth-child() I can show specific dividers at each break point.
I have also added the grouping functionality I was aiming for.
Updated example: https://jsfiddle.net/0t8c0h4m/9/
Below is the code I'm using. The top part $('div.pagination... works fine, I can alert(length) and it gives me the correct value of pages in the pagination section. The bottom part appears not to work. This is for a scraper that will open each page on a forum. If I leave the loop out of it it successfully retreaves the url for page here. The length -=2 is to remove the next/previous li from the total count.
$('div.pagination').each(function() {
var length = $(this).find('li').length;
length -= 2;
});
for (var i = 0; var <= length; i++) {
var pageToOpen = 'http://someWebsite.com/index/page:' + i;
alert(pageToOpen);
page.open(pageToOpen, function (status) {
if (status == 'success') {
logAuctions();
}
}});
}
Define your var length outside (before) the.each()
Using .lentgh method you might miss the real page indexes. So I would suggest to grab the real anchor hrefs.
FIDDLE DEMO
var pages = [];
// skipping the "Next" and "Last" get all A ahchors
$('div.pagination li').slice(0,-2).find('a').each(function(){
pages.push( $(this).attr('href') );
});
$.each(pages, function(i, v){
$('<div>'+ ("http://someWebsite.com"+v) +'</div>').appendTo('#output');
});
/* WILL RESULT IN:
http://someWebsite.com/auctions/index/page:2
http://someWebsite.com/auctions/index/page:3
http://someWebsite.com/auctions/index/page:4
*/
Looking for some help on how to write a function to filter out certain divs with certain classes.
Essentially I have thrown together a quick e-commerce example. There are lists of different filters, with values. There are then products. Each product div has a number of classes applied to it, e.g "green" or "adult" or "wool" - these are the filterable parameters.
Not being savvy at all with JS I'm trying to write something, but looking for some advice. Here is basically what I'm after:
Starts with displaying all
If user selects GREEN, all items that do not have GREEN attributed are display:none'd (with a fade transition
Rep #2 for any attribute checked
Notes: multiple attributes can be checked, when items are unchecked, everything needs to reappear.
Any help? I guess it's basically linking up the value of each checkbox to the class.
Not sure if there is a better way codewise to do this... data attributes maybe?
Working example of the code here (obviously no JS)
Updated your fiddle and added some jQuery to hide the divs where the classes don't match the selected checkboxes.
Demo: fiddle
JS is a bit verbose, you can refactor it further if you like:
$(document).ready(function() {
var allSelectedClasses;
allSelectedClasses = '';
$('input[type="checkbox"]').click(function(){
//ensure the correct classes are added to the running list
if(this.checked){
allSelectedClasses += '.' + $(this).val();
}else{
allSelectedClasses = allSelectedClasses.replace($(this).val(), '');
}
//format the list of classes
allSelectedClasses = allSelectedClasses.replace(' ', '');
allSelectedClasses = allSelectedClasses.replace('..', '.');
var selectedClasses;
var allSelected;
allSelected = '';
//format these for the jquery selector
selectedClasses = allSelectedClasses.split(".");
for(var i=0;i < selectedClasses.length;i++){
var item = selectedClasses[i];
if(item.length > 0){
if(allSelected.length == 0){
allSelected += '.' + item;
}else{
allSelected += ', .' + item;
}
}
}
//show all divs by default
$("div.prodGrid > div").show();
//hide the necessary ones, include the 2 top level divs to prevent them hiding as well
if(allSelected.length > 0){
$("div.prodGrid > div:not(" + allSelected + ")").hide();
}
});
});
I added a new class to your Colors ul. Hope that's okay.
Here's a crude version of a filtering function, it only takes colors into account so you have to modify it yourself to take everything into account but the basic outline is there.
It can be refactored massively! :)
Since you're using jQuery:
$('ul.colorFilter li input[type="checkbox"]').click(function(){
var checkedBoxes = $('ul.colorFilter li input[type="checkbox"]:checked');
var listOfClasses = [];
checkedBoxes.each(function(index, el){
listOfClasses.push(el.value);
});
if(listOfClasses.length >= 1){
$('div.prodGrid').children('div').hide();
for(var i = 0; i < listOfClasses.length; i++){
$('div.prodGrid > div.'+listOfClasses[i]).show();
}
} else {
$('div.prodGrid > div').show();
}
});
I made a fiddle as well:
http://jsfiddle.net/Z9ZVk/4/
Happy new year, everyone! I'm celebrating by working on learning jquery. I added some jQuery to my code below and managed to add some content and change some css with it. The getGroceries function is working fine and is doing what it's supposed to do. When the user finishes entering the groceries, the program (printGroceries) is supposed to print the list that the user entered. That portion is also working.... HOWEVER, when that happens, the program removes the header (My grocery list) and removes all styling.
What am I doing wrong?
EDITED CODE: Deleted full code and added the portion that I changed (commented the old).
function printGroceries(groceryItems) {
if (groceryItems.length > 1) {
$('grocery-list').html('<ol class="items" id="list-items">');
//document.write("<ol>");
for(x=0; x < groceryItems.length;x++){
groceryItems;
$('#list-items').prepend('<li>' + groceryItems[x] + '</li>');
//document.write("<li>" + groceryItems[x] + '</li>');
}
$('#grocery-list').append('</ol>');
//document.write("</ol>");
} else {
$('#grocery-list').prepend('<p>Sorry, your list is empty.</p>');
//document.write('<p>Sorry, your list is empty.</p>');
}
}
Problem: fiddle
Try this
function printGroceries(groceryItems) {
if (groceryItems.length > 0) {
$('#grocery-list').html('<ol class="items" id="list-items">');
//document.write("<ol>");
for(x=0; x < groceryItems.length;x++){
groceryItems;
$('#list-items').prepend('<li>' + groceryItems[x] + '</li>');
//document.write("<li>" + groceryItems[x] + '</li>');
}
$('#grocery-list').append('</ol>');
//document.write("</ol>");
} else {
$('#grocery-list').prepend('<p>Sorry, your list is empty.</p>');
//document.write('<p>Sorry, your list is empty.</p>');
}
}
You have missed few things as I suggested in the comments
1. The if condition should check groceryItems.length > 0
2. $('grocery-list') should be $('#grocery-list'), you are missing the id selector here
Solution: fiddle
Since you're using jQuery; here's a version that takes advantage of $.each(). Also, it's best to build out your string and append only once rather that append each item over and over.
function printGroceries(groceryItems) {
var listItems = '';
if (groceryItems.length > 0) {
$.each(groceryItems, function (i, item) {
listItems += '<li>' + item + '</li>';
});
$('#grocery-list').append('<ol class="items" id="list-items">'+listItems+'</ol>');
} else {
$('#grocery-list').prepend('<p>Sorry, your list is empty.</p>');
}
}
I'm trying to write a form builder where users can generate a signup form. I need to limit the amount of items that the user can create however they also need to delete the items.
Originally I had
var limit = 5;
var counter = 0;
if (counter == limit) {
However when the user deleted items the counter remained the same and so they couldnt replace the deleted form element with a new item. So what I want to do is count how many items are currently active. I tried to do this by giving each new element a class (.kid) and then counting the amount of divs with that class but it didnt work.
Could anyone point me in the right direction? This is what I have so far however it doesn't work.
var limit = 6;
var num = $('.kid').length;
function addAllInputs(divName, inputType){
if (num == limit) {
alert("You have all ready added 6 form items");
}
else {
var newdiv = document.createElement('div');
newdiv.setAttribute('id', 'child' + (counter + 1));
newdiv.setAttribute('class', 'kid' );
Cheers all!
You need to capture the current counter in a closure. Decrease the counter when the user deletes an item and increase it after an item is created. Your code sample doesn't reveal how you handle the deletion, but I'll try to illustrate what I mean with a small code snippet:
$(document).ready(function () {
var limit = 5;
var counter = $('.kid').length;
$('#triggers_delete').click(function () {
/* delete the item */
counter--;
});
$('#triggers_creation').click(function () {
if (counter == limit) {
alert('Limit reached');
return false;
}
/* somehow determine divName and inputType
and create the element */
addAllInputs(divName, inputType);
counter++;
});
});
function addAllInputs(divName, inputType) {
/* just create the item here */
}
Is there any reason an approach like this won't work? Every time you go to add a new DIV, the length of the current collection is examined to see if it meets or exceeds the limit. Of course, you may need to refine the scope of your selector if there could be other DIVs of the form with the same class ID.
var limit = 6;
function addAllInputs(divName, inputType){
if ( $('.kid').length >= limit ) {
alert("You have all ready added 6 form items");
}
else {
var newdiv = document.createElement('div');
newdiv.setAttribute('id', 'child' + (counter + 1));
newdiv.setAttribute('class', 'kid' );
}
Edit: Just a note, I am assuming that you are either removing the deleted items from the DOM or differentiating them from active items with a different class or attribute. Otherwise, the approach I suggested will return a count that includes the deleted items as well.
The only real issue is that your num variable is being defined outside of the function. It will get the number of .kid elements at the time the page loads and will not update. Simply move this line inside the function:
var limit = 6;
function addAllInputs(divName, inputType){
var num = $('.kid').length;
...
Try this
var limit = 6;
function addAllInputs(divName, inputType){
if ($('.kid').length == limit) {
alert("You have all ready added 6 form items");
}
else {
var newdiv = $('div', { 'id': 'child' + (counter + 1), 'class': 'kid' } );
$("inputContainerSelector").append(newdiv);
}