I'm trying to make a script to scroll down to the correct section.
This is a small piece of the html code:
<div class="page_sections sectionOne">
<div class="product_options">
<input />
</div>
</div>
<div class="page_sections sectionTwo">
<div class="product_options">
<input />
</div>
<div class="product_options">
<input />
</div>
<div class="product_options">
<input />
</div>
</div>
<div class="page_sections sectionThree">
<div class="product_options">
<input />
</div>
<div class="product_options">
<input />
</div>
</div>
The idea of the script is whenever someone clicks on an input(all selects and radio's) to go to the next product_options. If no product options is found then go to the next section.
I think im pretty close but can't seem to finish it. Can you help me out:
$(".page_sections :input").change(function(){
var next = $(this).closest(".page_sections").nextAll('.page_sections').first();
if ($(this).closest(".product_options").next('.product_options').length){
next = $(this).closest(".product_options").next('.product_options');
}
$('html, body').animate({
scrollTop: $(next).offset().top - 180
}, 1500);
});
I was really close. Made a typo with lenght -> length...
I made a typo. Thanks for #PatrickEvans for pointing me to that!
Related
Creating a simple "workout builder" where there's a list of exercises in one column with their own descriptions, sample videos, and "add button". When the "add button" is clicked, that specific exercise is moved over to another column. I could obviously give each add button its own ID and hardcode each thing, but I'm trying to do it a bit more elegantly.
I'm trying to write it as a for loop, where each button gets assigned its own event listener. But then, how do I make sure each button only affects a specific div? I'm using querySelectorAll, which I know also creates an array, but how do I make sure that addButton[1] only affects exercise[1] or addButton[45] only affects exercise [45] and so on and so forth.
HTML
<body>
<div class="header">
<h1 class="header-title">WORKOUT BUILDER</h1>
<img id="header-img" src="img/workoutheader.jpg">
</div>
<!-- This is the big list of exercises. -->
<div class="list-of-exercises">
<!-- This is an individual exercise. -->
<div class="exercise" id="power-clean">
<div class="exercise-name">
<h2 class="name" id="power-clean-name">Power Clean</h2>
</div>
<!-- Here's the add button for this specific exercise. As you can see I have a specific ID here where I could hardcore each button, but I'm looking for a more elegant solution. -->
<button class="add-button" id="add-button-power-clean">Add</button>
<!-- This is the rest of the exercise content, like a sample GIF, sets and reps, etc. -->
<div class="exercise-contents" id="power-clean-contents">
<iframe src="https://giphy.com/embed/c10FJ0dpZ5CEF03JTO" width="480" height="270" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p></p>
<div class="sets-and-reps-form" id="sets-and-reps-form-power-clean">
<label for="sets">Sets</label>
<input type="number" class="sets" id="sets-power-clean" fname="sets">
<br>
<label for="reps">Reps</label>
<input type="number" class="reps" id="reps-power-clean" fname="reps">
<input class="sets-and-reps-submit" id="sets-and-reps-submit-power-clean" type="submit" value="Submit">
</div>
</div>
</div>
<!-- Here's the start of the next exercise. -->
<div class="exercise" id="back-squat">
<div class="exercise-name">
<h2 class="name" id="back-squat-name">Back Squat</h2>
</div>
<button class="add-button" id="add-button-back-squat">Add</button>
<div class="exercise-contents" id="back-squat-contents">
<div class="tenor-gif-embed" data-postid="24035556" data-share-method="host" data-aspect-ratio="1.49533" data-width="100%">Workouts Squats GIFfrom Workouts GIFs</div> <script type="text/javascript" async src="https://tenor.com/embed.js"></script>
<div class="sets-and-reps-form" id="sets-and-reps-form-back-squat">
<label for="sets">Sets</label>
<input type="number" class="sets" id="sets-back-squat" fname="sets">
<br>
<label for="reps">Reps</label>
<input type="number" class="reps" id="reps-back-squat" fname="reps">
<input class="sets-and-reps-submit" id="sets-and-reps-submit-back-squat" type="submit" value="Submit">
</div>
</div>
</div>
</div>
<!-- This is the div where I want people to be able to "add" the different exercises. -->
<div class="exercise-builder">
<div class="final-readout">
<p id="intensity-score">Intensity Score: 0</p>
<p id="ETA">Estimated Time To Complete Workout: 0</p>
</div>
</div>
<script src="script.js" async defer></script>
</body>
Javascript
let moveToBuilder = function(){
let exerciseBuilder = document.querySelector(".exercise-builder");
let exercise = document.querySelectorAll(".exercise");
// So here I'm just using 0 as the array test value to get it working. But like how could I turn the 0 into something that pairs with the various Submit Button array values? So when I hit the "Power Clean" add button, it only adds Power Clean, etc.
exerciseBuilder.insertBefore(exercise[0], exerciseBuilder.firstChild);
}
for (var i = 0; i < addButton.length; i++) {
addButton[i].addEventListener('click', moveToBuilder, false);
}
Here's your JavaScript with a few tweaks. I've:
Added a little array exercises to allow the needed text to be picked up by index, which in turn is used to find the correct elements;
Used document.getElementById() twice to cleanly pick up elements by id (this is more robust in general that the querySelectorAll(): one weakness of that is that the numbering of the elements changes when they are re-ordered on the page;
Perhaps most importantly, I've added an arrow function to the event listener, which returns a different invocation of moveToBuilder() depending on the value of i. This effectively puts different event listeners on the different buttons, as you wanted; and
To make this work, the scope of the variable i had to be limited with a let declaration rather than var otherwise i = 2 at all material times (after the loop has finished).
let exercises = ["power-clean", "back-squat"]
let moveToBuilder = function(index){
let exerciseBuilder = document.querySelector(".exercise-builder");
let exercise = document.getElementById(exercises[index]);
// So here I'm just using 0 as the array test value to get it working. But like how could I turn the 0 into something that pairs with the various Submit Button array values? So when I hit the "Power Clean" add button, it only adds Power Clean, etc.
exerciseBuilder.appendChild(exercise);
}
for (let i = 0; i < exercises.length; i++) {
document.getElementById(`add-button-${exercises[i]}`).addEventListener('click', () => moveToBuilder(i), false);
}
<body>
<div class="header">
<h1 class="header-title">WORKOUT BUILDER</h1>
<img id="header-img" src="img/workoutheader.jpg">
</div>
<!-- This is the big list of exercises. -->
<div class="list-of-exercises">
<!-- This is an individual exercise. -->
<div class="exercise" id="power-clean">
<div class="exercise-name">
<h2 class="name" id="power-clean-name">Power Clean</h2>
</div>
<!-- Here's the add button for this specific exercise. As you can see I have a specific ID here where I could hardcore each button, but I'm looking for a more elegant solution. -->
<button class="add-button" id="add-button-power-clean">Add</button>
<!-- This is the rest of the exercise content, like a sample GIF, sets and reps, etc. -->
<div class="exercise-contents" id="power-clean-contents">
<iframe src="https://giphy.com/embed/c10FJ0dpZ5CEF03JTO" width="480" height="270" frameBorder="0" class="giphy-embed" allowFullScreen></iframe><p></p>
<div class="sets-and-reps-form" id="sets-and-reps-form-power-clean">
<label for="sets">Sets</label>
<input type="number" class="sets" id="sets-power-clean" fname="sets">
<br>
<label for="reps">Reps</label>
<input type="number" class="reps" id="reps-power-clean" fname="reps">
<input class="sets-and-reps-submit" id="sets-and-reps-submit-power-clean" type="submit" value="Submit">
</div>
</div>
</div>
<!-- Here's the start of the next exercise. -->
<div class="exercise" id="back-squat">
<div class="exercise-name">
<h2 class="name" id="back-squat-name">Back Squat</h2>
</div>
<button class="add-button" id="add-button-back-squat">Add</button>
<div class="exercise-contents" id="back-squat-contents">
<div class="tenor-gif-embed" data-postid="24035556" data-share-method="host" data-aspect-ratio="1.49533" data-width="100%">Workouts Squats GIFfrom Workouts GIFs</div> <script type="text/javascript" async src="https://tenor.com/embed.js"></script>
<div class="sets-and-reps-form" id="sets-and-reps-form-back-squat">
<label for="sets">Sets</label>
<input type="number" class="sets" id="sets-back-squat" fname="sets">
<br>
<label for="reps">Reps</label>
<input type="number" class="reps" id="reps-back-squat" fname="reps">
<input class="sets-and-reps-submit" id="sets-and-reps-submit-back-squat" type="submit" value="Submit">
</div>
</div>
</div>
</div>
<!-- This is the div where I want people to be able to "add" the different exercises. -->
<div class="exercise-builder">
<div class="final-readout">
<p id="intensity-score">Intensity Score: 0</p>
<p id="ETA">Estimated Time To Complete Workout: 0</p>
</div>
</div>
<script src="script.js" async defer></script>
</body>
I've been struggling to understand how to overcome this problem. I've been tasked to retrieve user input, and on keystroke see if user input matches any amount of .tags If not, hide the .thumb-display.
So far, I've been able to gather that I'll need to add/remove the classlist "hidden" as well use the event handler "input", however I don't quite understand how to use event handler "input" in this context as well as change event.
This is for homework so I'd much rather have an explanation for an answer, rather than just an answer so I can understand what I currently can't. Even a hint could be vital and set me on the right track! Rules are: no changing HTML and must use JavaScript.
Here is the HTML:
<form class="frm-filter">
<div class="frm-group">
<a class="reset hidden" href="#">Reset</a>
<input class="frm-control" type="text" id="filter" name="filter" placeholder="tag filter" />
</div>
</form>
</nav>
<section class="gallery">
<div class="row">
<h1>Gallery</h1>
</div>
<div class="row">
<div class="thumb-display">
<img src="img/thumbs/african_road_to_the_mountain.jpg" alt="african road to the mountain" />
<p class="tags">#africa #mountain #road</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_and_palms.jpg" alt="beach and palms" />
<p class="tags">#palmbeach #distantpeaks</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_road.jpg" alt="beach road" />
<p class="tags">#oceanbeach #mountainroad</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/calm_lake.jpg" alt="calm lake" />
<p class="tags">#lake #clearskies #onthewater</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/fall_bridge.jpg" alt="fall bridge" />
<p class="tags">#fallcolors #bridgecrossing #river</p>
</div>
</div>
</section>
You need to listen on input keyup event and retrieve value from input then check if that value matches any tags and show/hide `parentNode
document.addEventListener('DOMContentLoaded', () => {
const inputEl = document.getElementById('filter');
const tags = Array.from(document.querySelectorAll('.tags'));
inputEl.addEventListener('keyup', () => {
const value = inputEl.value;
tags.forEach(tag => {
if (tag.textContent.includes(value)) {
tag.parentNode.style.display = 'block'
} else {
tag.parentNode.style.display = 'none'
}
})
})
})
<form class="frm-filter">
<div class="frm-group">
<a class="reset hidden" href="#">Reset</a>
<input class="frm-control" type="text" id="filter" name="filter" placeholder="tag filter" />
</div>
</form>
<section class="gallery">
<div class="row">
<h1>Gallery</h1>
</div>
<div class="row">
<div class="thumb-display">
<img src="img/thumbs/african_road_to_the_mountain.jpg" alt="african road to the mountain" />
<p class="tags">#africa #mountain #road</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_and_palms.jpg" alt="beach and palms" />
<p class="tags">#palmbeach #distantpeaks</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/beach_road.jpg" alt="beach road" />
<p class="tags">#oceanbeach #mountainroad</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/calm_lake.jpg" alt="calm lake" />
<p class="tags">#lake #clearskies #onthewater</p>
</div>
<div class="thumb-display">
<img src="img/thumbs/fall_bridge.jpg" alt="fall bridge" />
<p class="tags">#fallcolors #bridgecrossing #river</p>
</div>
</div>
</section>
You need to get user input. So you need to listen for an event. Add Event Listener to the rescue. Which event, though? How about "change".
Ok, so you can get what they typed, good. Now you need to compare it to the tags. So it's time to find all of those. You can get all of the ".tags" with a querySelector. That will get you a list of nodes that you can loop through to collect the innerText. You can check if the innerText includes the input that the user typed. If it doesn't, then you find the closest ".thumb-display" and set a style attribute to hide it. If the input IS in the innerText, then you need to remove any style attribute that is hiding the closest parent.
Boom, done. Maybe, I didn't try it an I almost never get it right the first time. But it would be something along those lines.
Click works just on first div with id plus but other divs with the same id dont work. I dont know whats the problem... I dont get what the problem is. Please help. Thanks!
Here is the code...
Edited:
<div id="details">
<div id="detailHeader">
<div id="facultyTitle">sadasdas</div>
<div id="title">dsadasdasdas</div>
</div>
<div id="detailReference">
dodaj
<div id="refVote">
<div class="plus" glas="41">Good</div>
<div class="minus" glas="41">Bad</div>
</div>
<div id="referenceInfo">
01:40 PM 06.09.2014.
</div>
</div>
</div>
<div id="detailReference">
dodaj
<div id="refVote">
<div class="plus" glas="37">Good</div>
<div class="minus" glas="37">Bad</div>
</div>
<div id="referenceInfo">
01:38 PM 06.09.2014.
</div>
</div>
</div>
JavaScript
$(".plus").click( function() {
var ref=$(this).attr("glas");
alert(ref);
$.ajax({
url:"url is ok",
success:function(){
}
}
);
});
IDs should be unique. use same class instead of ids.Like this:
<div class="plus" glas="37">Good</div>
and then use:
$(".plus").click( function() {
var ref=$(this).attr("glas");
alert(ref);
$.ajax({
url:"url is ok",
success:function(){
}
}
);
$(".plus").click(...)
not
$("#plus").click(...)
There can and shall only be one item with a certain ID on the page. Use classes on those buttons instead.
Couple of issues. You have mismatched divs. This last div looks like its the culprit.
<div id="details">
<div id="detailHeader">
<div id="facultyTitle">sadasdas</div>
<div id="title">dsadasdasdas</div>
</div> <--this one
Your second issue is that you shouldnt have multiple ids that are the same on a page. Instead set it as a class with
<div class="plus"> Then reference them in jquery with
$(".plus").click( function()
I have to use class if you have more than one div. Try with .plus
Figured I would ask here because I can't seem to find an easy solution or a solution on here that fits my needs. The problem I'm having with my site at the moment is when dealing with slide animations and with timing of those animations.
So when a user clicks one of my navigation buttons there is a panel that slides out the content based on the button pressed. if you click another button it will slide that one previous div back up and slide down the new content panel.
The main problem I'm getting is either I get animation timing issues because the other one starts sliding as the other one is for some reason.
All my content panels are siblings to one another...so here's the jQuery I'm using....any suggestions would be greatly appreciated!
$('a.navBtn').click(function(){
var divName = this.name;
$.when(function(){
$("#"+divName).siblings().filter(":visible").slideUp("slow");
}).then(function(){
$("#"+divName).slideDown("slow");
})
});
<div id="services">
<div class="noise_overlay">
<div id="contact"><img src="i/contact.png" /></div>
<div id="linkedin"><img src="i/linkedin.png" /></div>
<div id="facebook"><img src="i/facebook.png" /></div>
<div id="twitter"><img src="i/twitter.png" /></div>
<div id="flickr"><img src="i/flickr.png" /></div>
</div>
</div>
<div id="serviceContent">
<div id="contactContent" class="contentPane mpHidden">
<div class="noise_overlay_300">
<div id="contactData">
<span>contact</span>
</div>
</div>
<div class="contentFooter"></div>
</div>
<div id="linkedinContent" class="contentPane mpHidden">
<div class="noise_overlay_300">
<div id="linkedinData" class="mpCenter">
</div>
</div>
<div class="contentFooter"><span></span></div>
</div>
<div id="facebookContent" class="contentPane mpHidden">
<div class="noise_overlay_300">
<div id="facebookData" class="mpCenter">
<span>facebook</span>
</div>
</div>
<div class="contentFooter"><span></span></div>
</div>
<div id="twitterContent" class="contentPane mpHidden">
<div class="noise_overlay_300">
<div id="twitterData" class="mpCenter">
<span>twitter</span>
</div>
</div>
<div class="contentFooter"><span></span></div>
</div>
<div id="flickrContent" class="contentPane mpHidden">
<div class="noise_overlay_300">
<div id="flickrData" class="mpCenter">
<span>flickr</span>
</div>
</div>
<div class="contentFooter"><span></span></div>
</div>
</div>
You need to chain your animation events so the slideDown doesn't happen until the slideUp is done:
http://api.jquery.com/slideUp/
$("#"+divName).siblings().filter(":visible").slideUp("slow", function() {
$("#"+divName).slideDown("slow");
});
Should be something like that.
I have made a simple jQuery snippet for you. The javascript:
$(function() {
$('a.navBtn').click(function(e) {
var pane = $(this).attr('name'),
switchPanes = function(name) {
if($('.contentPane:visible').attr('id') === name){
return;
}
if($('.contentPane:visible').length > 0){
$('.contentPane:visible').slideUp('fast', function() {
$('#' + name).slideDown('medium');
});
} else {
$('#' + name).slideDown('medium');
}
};
switchPanes(pane);
e.preventDefault();
});
});
Here's a working(?) version. I use the callback of the slideUP to call the slideDown.
http://jsfiddle.net/yazYF/
EDIT: Just like the Justin said, I just have some code to test with. :)
EDIT 2: Now with an initial pane visible
http://jsfiddle.net/yazYF/1/
EDIT 3: Initially nothing...
http://jsfiddle.net/yazYF/2/
I'd like for the page to open at a certain div halfway down the page, not at the top...
I have something like:
<div id="d1">
<div id="d2">
<div id="d3">
<div id="d4">
<div id="d5">
<div id="d6">
How can I get the page to open at #d4, instead of the top? (Besides adding #d4 to the end to the URL...)
I imagine there must be some easy way to do this, but I can't figure out how to go at searching for a solution! HTML, javascript? Any help is greatly appreciated.
<script>
function ScrollToElement(theElement){
var selectedPosX = 0;
var selectedPosY = 0;
while(theElement != null){
selectedPosX += theElement.offsetLeft;
selectedPosY += theElement.offsetTop;
theElement = theElement.offsetParent;
}
window.scrollTo(selectedPosX,selectedPosY);
}
</script>
http://radio.javaranch.com/pascarello/2005/01/09/1105293729000.html
Find div position using this
and then use the following javascript command:
window.scroll(0, DIV_POS); // horizontal and vertical scroll targets
EDIT: OOPS! didn't read the Except.... disregard!
Note to self, read the entire question before responding!
End EDIT
You could always use an HTML anchor tag
<a name="d1" />
<div id="d1">
<a name="d2" />
<div id="d2">
<a name="d3" />
<div id="d3">
<a name="d4" />
<div id="d4">
<a name="d5" />
<div id="d5">
<a name="d6" />
<div id="d6">
When you navigate to the page, you would include the anchor name in the url:
pagename.htm#d4
Make sure to close your div tags.
Good luck,
Patrick
You can use Javascript:
location.replace('#d4');