JSON - If Statement Troubleshooting - javascript

What is causing the if statement (totalViews === 0) to not function properly?
The statement should be displaying a span tag with in the "div.viewed" class. The span's inner text should read "0 people have viewed your post" if the "totalViews" equals 0 (no span tags to begin with). However, a span tag is not being inputted at all in to the "div.viewed" class.
The remaining if statements seem to be functioning properly.
A sample of the current code:
function checkViewers() {
$('div.viewed').each(function() {
//Base Variables
var viewer = $('span.user', this);
var totalViews = viewer.length;
var shortenViews = viewer.length -1;
var viewerCount = $('span', this);
if (totalViews === 0) {
$('div.viewed', this).append('<span> 0 people have viewed your post.</span>');
}
if (totalViews == 1) {
$('<span> has viewed your post.</span>').insertAfter(viewer.last());
}
if (totalViews == 2) {
$('<span> and </span>').insertAfter(viewer.first());
$('<span> have viewed your post.</span>').insertAfter(viewer.last());
}
if (totalViews >= 3) {
$('<span> and </span>').insertAfter(viewer.first());
$('<span class="user count"></span>').insertAfter(viewerCount.eq(1));
$('.count', this).html(shortenViews + ' more people');
$('<span> have viewed your post.</span>').insertAfter(viewer.last());
viewer.slice(1).hide();
}
});
}
View the current and complete Plunker.

Your problem is in your traversal. $('div.viewed', this) doesn't exist.
Using the context argument of $(selector,context) is the same as writing:
$(this).find('div.viewed'); //look for descendant of "this"
Change:
$('div.viewed').each(function() {
/* "this" is an instance of div class= viewed*/
/* look for a div WITHIN "this" with class=viewed" --BUT no such descendant*/
$('div.viewed', this).append(..;
});
TO
$('div.viewed').each(function() {
/* I'm already here as "this" */
$(this).append(..;
});
DEMO

$('div.viewed', this).append('<span> 0 people have viewed your post.</span>');
here $('div.viewed', this) will return an empty array,
instead you might have to do it like
$('div.viewed').append('<span> 0 people have viewed your post.</span>');

Related

How to combine two javascripts?

Would anyone be so kind as to advise me how to amend this JavaScript please? I'll admit I don't have much experience working with JavaScript and I've tried myself but ended up a bit lost.
To explain, WooCommerce outputs products on my site in .columns-3 and .columns-4, and assigns .first and .last classes accordingly.
If the site is loaded on mobile, the script below will remove the .first and .last tags, and re-assign them to display the products in two columns.
The script currently only targets .columns-3 within function defaultProductRows and function adjustProductRows. I need to also target .columns 4 within the same script, but I'm not sure how to go about adding it.
<script>
$(window).on('load resize', function (){
var windowWidth = $(window).width();
if(windowWidth < 753){ // this is my screen size break point for the rows
adjustProductRows(); // call the function to adjust add last and first classes
} else {
defaultProductRows(); // else if large screen size then get everything back to defalut
}
});
function defaultProductRows(){
var products = $('ul.products.columns-3 li.type-product');
products.each(function(idx, li) {
var product = $(li);
// remove all classes we added
$('ul.products li.adjusted-row.first').removeClass('adjusted-row first');
$('ul.products li.adjusted-row.last').removeClass('adjusted-row last');
if(idx == 0) { // make sure first li tag gets first class
product.addClass('first');
}
else if((idx+1) % 3 == 0) //this will make sure we have 3 rows by adding last classes after each 3 products
{
product.addClass('last');
}
else if(idx % 3 == 0)
{
product.addClass('first'); // make sure all products divided by 3 will have first class
}
else
{
console.log(idx); // just checking for the index
}
});
}
function adjustProductRows() {
var products = $('ul.products.columns-3 li.type-product');
products.each(function(idx, li) {
var product = $(li);
if(idx % 2 == 0) // we are even
{
product.addClass('adjusted-row first');
product.removeClass('last');
}
else // we are odd
{
product.addClass('adjusted-row last');
product.removeClass('first');
}
});
}</script>
Change your selector to include columns-4
From:
var products = $('ul.products.columns-3 li.type-product');
To:
var products = $('ul.products.columns-3 li.type-product, ul.products.columns-4 li.type-product');
This tells jQuery to select li.type-products that are part of either columns-3 or columns-4

jQuery breaking my fizzbuzz, why?

Trying to solve the fizzbuzz problem in javascript with a little html. I want to put the answers in a <ul> and display them on the page. To do this, I need to take the fizz-buzz's and somehow add them in a <li> element to the UL, with a prepend or append in jQuery. My code runs fine, until I add jQuery to the equation to prepend the <li>s into the html. I currently have the numbers/fizz-buzzes popping up with alerts.
I have tried putting in $(document).ready(function() {}, wrapping all javascript inside brackets. If I do, it breaks, even if there is 0 jQuery actually in the javascript section. Simply breaks, as if the page is never actually ready and thus the javascript will never run.
Assuming I can get any jQuery in to work, can I simply put jQuery statemments inside of my elseif statements?
example:
else if (n1 % 5 === 0) {
$("ul").prepend("<li>n1</li>")
}
Javascript:
var number = prompt("number?");
var num_int = parseInt(number);
var smack = new Array(num_int);
//populating array with numbers 1 through num_int
for (i = 0; i < smack.length; i++) {
smack[i] = i+1;
} //test again still working?
smack.forEach(function(n1) { //going through each array element, checking for fizz/buzz
if (n1 % 3 === 0 && n1 % 5 === 0) {
alert("fizz-buzz")
}
else if (n1 % 3 === 0) {
alert("fizz")
}
else if (n1 % 5 === 0) {
alert("buzz")
}
else {
alert(n1)
}
}); //end of forEach
HTML:
<hmtl>
<head>
<script src="scripts.js"></script>
<script src="jquery-1.11.2.js"></script>
</head>
<body>
<p>
<h1>Fizzbuzz</h1>
<ul id="hard">
<li>test</li>
</ul>
</p>
</body>
</html>
JSFiddle
Thanks in advance for any help! I'm sure this is a ridiculously easy question for anyone who has experience. I'm just getting into it, and while the math/logic section of fizzbuzz was pretty straightforward, getting it to display correctly is killing me.
You should load jquery before your script.js
Here's a demo
I added $('#hard').append
Changing the JQuery part to:
var number = prompt("number?");
var num_int = parseInt(number);
var smack = new Array(num_int);
//populating array with numbers 1 through num_int
for (i = 0; i < smack.length; i++) {
smack[i] = i+1;
} //test again still working?
smack.forEach(function(n1) { //going through each array element, checking for fizz/buzz
if (n1 % 3 === 0 && n1 % 5 === 0) {
$('#hard').append("<li>fizz-buzz</li>");
}
else if (n1 % 3 === 0) {
$('#hard').append("<li>fizz</li>");
}
else if (n1 % 5 === 0) {
$('#hard').append("<li>buzz</li>");
}
else {
$('#hard').append("<li>"+n1+"</li>");
}
}); //end of forEach
would help.
The changes here is inside the if conditions. You append your li to the ul each time and you will have your answers in the list.
Hope this helped.

Inputting JSON Data In Element's Containing Same ID - Troubleshooting

Currently I have JSON data that is being inputted/entered into all articles containing the ID #viewed. While the JSON data is showing that it is being inputted into all article's with the ID, the function checkViewers() is only functioning correctly for the first article ID #viewed.
Ideally, the checkViewers() function should make all #viewed IDs appear as the first article ID #viewed is currently appearing (e.g. First name Last name and Remaining Number of People have viewed this post.) However, the total number of people remaining is incorrect in the first article, as it is gathering all the repeated data. It should only be gathering the data once and totaling that number per article ID.
What is the best fix for this situation? I am guessing the checkViewers() function is gathering all the data on the page and only needs to be gathering the data from it's parent section?
A sample of the current code:
//Content Viewer Information
function checkViewers() {
//Base Variables
//var viewer = $('#viewed span.user');
//var totalViews = $('#viewed span.user').length;
//var shortenViews = $('#viewed span.user').length -1;
var viewer = $("#viewed span[class^='user']");
var totalViews = $("#viewed span[class^='user']").length;
var shortenViews = $("#viewed span[class^='user']").length -1;
if (totalViews === 0) {
($('#viewed').html('<span> 0 people have viewed your post.</span>'));
}
if (totalViews === 1) {
$('<span> has viewed your post.</span>').insertAfter(viewer.last());
}
if (totalViews === 2) {
$('<span> and </span>').insertAfter(viewer.first());
$('<span> have viewed your post.</span>').insertAfter(viewer.last());
}
if (totalViews >= 3) {
viewer.slice(1).hide();
$('<span> and </span>').insertAfter(viewer.first());
$('<span class="user count"></span>').insertAfter(viewer.eq(2));
$('.count').html(shortenViews + ' more people');
$('<span> have viewed your post.</span>').insertAfter(viewer.last());
}
}
The function is then being called with the updated content.
//Update Page With New Content
var viewerSection = $("article[id^='viewed']");
viewerSection.html(newViewers);
checkViewers();
Edits: I ended up changing the IDs #viewed to the Class .viewed, as IDs should be unique. However, I am still having the same problem as before.
View the current and complete code at Plunker.
Firstly, now you are correctly using classes, you shouldn't check the class attribute like this:
var viewerSection = $("div[class^='viewed']");
Just use the basic jQuery class selector:
var viewerSection = $("div.viewed");
You should also do the same for the other 3 selectors at the top of your script as you have commented out.
Now the main problem is that you are not restricting your checks in checkViewers to each individual item, so it is applying it globally.
You need to loop through each .viewed element and apply your logic to each. The jQuery selector method takes a second argument which is an element to search within for matches. As you are in a jQuery each() method, you can just pass this as the second argument:
function checkViewers() {
$('div.viewed').each(function() {
var viewer = $("span.user", this);
// no need to re-select, just work them out based on viewer
var totalViews = viewer.length;
var shortenViews = viewer.length -1;
if (totalViews === 0) {
$(this).html('<span>0 people have viewed your post.</span>');
}
else if (totalViews === 1) {
$(this).append('<span> has viewed your post.</span>');
}
else if (totalViews === 2) {
$('<span> and </span>').insertAfter(viewer.eq(0));
$(this).append($('<span> have viewed your post.</span>'));
}
else if (totalViews >= 3) {
viewer.slice(1).hide();
$('<span> and </span>').insertAfter(viewer.eq(0));
$('<span class="user count">' + shortenViews + ' more people</span>').insertAfter(viewer.eq(2));
$(this).append($('<span> have viewed your post.</span>'));
}
});
}
Updated Plunker

Javascript grid click to re-organize

I'm working on a project and have gotten stuck on reorganizing my grid via JQuery. I've broken the problem down into a simple fiddle: http://jsfiddle.net/tylerbuchea/QgAqV/
$('div').bind('click', function() {
var pitcher = $('.selected')[0];
var catcher = this;
if (catcher.offsetTop < pitcher.offsetTop || catcher.offsetLeft > pitcher.offsetLeft) {
$(pitcher).before(catcher);
console.log('before');
}
else
if (catcher.offsetTop > pitcher.offsetTop || catcher.offsetLeft < pitcher.offsetLeft) {
$(pitcher).after(catcher);
console.log('after');
}
});​
I want the "selected" div to move to clicked divs location with all other divs being scooted down (or up). This works fine, but if you try to move it more than one space... Well you'll see the problem. Maybe the .before and .after functions aren't what I should be using?
I've updated your code example with My Version:
$('div').bind('click', function() {
var $currentlySelected = $('.selected'),
$newlyClicked = $(this),
currentlySelectedIndex = $currentlySelected.index(),
newlyClickedIndex = $newlyClicked.index();
if (currentlySelectedIndex > newlyClickedIndex) {
$currentlySelected.insertBefore($newlyClicked);
console.log('is greater, so put it after');
} else {
$currentlySelected.insertAfter($newlyClicked);
console.log('is less, so put it after');
}
});​
Have a look at this and tell me if it's doing what you want. I changed your logic around a little bit. The first thing I did was instead of checking offsets, I'm using .index() which tells me the position of an element in relation to its siblings.
If the clicked elements index is less than the currently selected elements index, then I move the currently selected element to BEFORE the clicked element so it takes its place. If the index of the clicked element is more than the currently selected elements index, then I move the currently selected element to AFTER the clicked element so it takes its place.
In regards as to why your elements were moving one at a time, I'm not entirely sure, but my guess would be that you were moving raw DOM elements around at times, and not jQuery objects. If they had ID's perhaps it would have been different. In any case, by moving around jQuery objects, it's working as intended.
Let me know if this is what your looking for!
I'm not sure if I understood your cuestion, but think this is what you want:
$('div').bind('click', function() {
var pitcher = $('.selected')[0];
var catcher = this;
if (catcher.offsetTop < pitcher.offsetTop || catcher.offsetLeft > pitcher.offsetLeft) {
$(catcher).after(pitcher);
console.log('before');
}
else
if (catcher.offsetTop > pitcher.offsetTop || catcher.offsetLeft < pitcher.offsetLeft) {
$(catcher).before(pitcher);
console.log('after');
}
});​
Regards,
Romén
$('div').bind('click', function() {
var pitcher = $('.selected')[0];
var catcher = this;
if (catcher.offsetTop < pitcher.offsetTop || catcher.offsetLeft > pitcher.offsetLeft) {
$(catcher).after(pitcher);
console.log('before');
}
else
if (catcher.offsetTop > pitcher.offsetTop || catcher.offsetLeft < pitcher.offsetLeft) {
$(catcher).before(pitcher);
console.log('after');
}
});
You have inverted both the conditions and the use of the functions. Have a look here on how to use before()/after().
The code still does not work when you have multiple rows since there is a conceptual flow: you have to test if the catcher is before/after the pitcher in logical terms.
When a tile comes before another?
when it is on an upper row
OR
when it is on the same row AND it is on the left
I leave the rest to you as an exercise

Add a selected class to a list when scrolling past the offset of set of divs

I think I'm close, but I'm having trouble trying to finalize this. Basically when you scroll down to each image, the div containing that image's offset from the top of the window (-500 as a buffer) would add a .selected class to the list element on the left.
http://jsfiddle.net/H6RTs/ is my example
Here is the code where basically the magic happens (sort of):
$(window).bind('scroll', function() {
// What the current px is from vertical scroll
var scrollY = window.pageYOffset;
// They scrolled more than the original offset
if (scrollY > menuTop) {
if (menuClone.parent().length === 0) {
$('#js-current-products').each(function(index, value) {
var newIndex = index + 1;
var currentProduct = $('.js-current-product-' + newIndex).offset().top - 500;
if (scrollY > currentProduct) {
$('.js-product-' + newIndex).addClass('selected');
}
});
stickyDiv.addClass(posFixed).width(clonedWidth);
menuClone.after(stickyDiv.parent());
}
} else {
$('#js-product-menu li').first().removeClass('selected');
stickyDiv.removeClass(posFixed);
menuClone.remove();
}
});
It'll add the class to the first list item, but not the other ones (so I guess it keeps focusing on $('.js-current-product-1') instead of iterating through all of them (which would be 3).
What am I doing wrong?
2 things:
#EDIT - The way Zeta loop through is much cleaner :D#
1:
$('#js-current-products').each(function(index, value) {
var newIndex = index + 1;
var currentProduct = $('.js-current-product-' + newIndex).offset().top - 500;
if (scrollY > currentProduct) {
$('.js-product-' + newIndex).addClass('selected');
}
});
Your just looping through the container of the images, of which there is only one, so what you need to do is loop the the images themselves. One way would be to add the class prod to them when you loop through and give them an index, ie:
$('#js-current-products .js-current-product').each(function(index, value) {
var newIndex = index + 1;
$(this).removeClass('js-current-product').addClass('js-current-product-' + newIndex).addClass('prod');
});
#EDIT#
2:
You also need to remove the selected class when you scroll back up, this is easily done by adding an else to the test condition, ie:
if (scrollY > currentProduct) {
$('.js-product-' + newIndex).addClass('selected');
console.log(newIndex);
} else {
$('.js-product-' + newIndex).removeClass('selected');
}
I'm pretty sure that's all, take a look at the fiddle here: http://jsfiddle.net/H6RTs/3/
Cheers
Charlie
You only iterate over all elements which are identified by id="js-current-products". Only one element matches this selector. So
if (scrollY > menuTop) {
if (menuClone.parent().length === 0) {
$('#js-current-products').each(function(index, value) {
// matches only one product ....
should be
if (scrollY > menuTop) {
if (menuClone.parent().length === 0) {
$('#js-current-products div.border').each(function(index, value) {
// matches all products, but has to use div.border, since
// you changed your class names....
or something similar. Also you shouldn't change classnames to create unique ones for each element. They're class names, not identifiers.
$('#js-current-products .js-current-product').each(function(index, value) {
var newIndex = index + 1;
$(this).attr('id','js-current-product-' + newIndex);
});
If you don't abuse classes then you can also remove your .selected class very easily:
if (scrollY > currentProduct) {
$('#js-product-menu li').removeClass('selected');
$('#js-product-' + newIndex).addClass('selected');
}
Demonstration

Categories

Resources