Showing messages based on scroll position - javascript

I am trying to create a page where there is an avatar in the bottom right hand corner of the screen and when a user scrolls past certain elements on the page, the avatar brings up a popup that gives some brief user feedback based on the point that he is passing.
I have no idea the best way to go about this, I am thinking there will be an ID attached to the scroll point and when that point is scrolled past a tooltip or something will appear for a brief amount of time until the user scrolls past said ID.
Any help would be much appreciated

It changes the #message's content by scrolling across sections (.section) in the page and identifying which one is visible on viewport. Complete code on the link below:
https://jsfiddle.net/hw475zeL/
Markup:
<div class="container">
<h1>Custom message on scrolling</h1>
<div id="section-1" class="section">
<h2>Section 1</h2>
</div>
<div id="section-2" class="section">
<h2>Section 2</h2>
</div>
<div id="section-3" class="section" data-message="Showing section 3">
<h2>Section 3</h2>
</div>
<div id="section-4" class="section" data-message="Showing section 4">
<h2>Section 4</h2>
</div>
<div id="section-5" class="section" data-message="Showing section 5">
<h2>Section 5</h2>
</div>
<div id="section-6" class="section">
<h2>Section 6</h2>
</div>
</div>
<div id="message" style="visibility: hidden; opacity: 0;">Teste</div>
JavaScript:
var sections = document.querySelectorAll('.section');
var message = document.querySelector('#message');
document.onscroll = function(event) {
for (var section of sections) {
if (elementInViewport(section) && section.hasAttribute('data-message')) {
message.innerText = section.getAttribute('data-message');
message.style.visibility = 'visible';
message.style.opacity = 1;
break;
}
message.style.visibility = 'hidden';
message.style.opacity = 0;
}
}
And the elementInViewport() function from this answer:
https://stackoverflow.com/a/125106/5862990

If you set every element as a row and then use
<div class="row" onmouseover="avatarscript">
<div class="row" onmouseover="avatarscript2">
in avatarscripts use jquery or javascript to change to the appropriate avatar-text.

you can use scroll event listner.
// what should we do when scrolling occurs
var runOnScroll = function(evt) {
// not the most exciting thing, but a thing nonetheless
console.log(evt.target);
};
// and then make each element do something on scroll
elements.forEach(function(element) {
window.addEventListener("scroll", runOnScroll, {passive: true});
});

Related

The problem is when I click on the link in the Navbar it doesn't go to its section

I am trying to make a dynamic navbar and when I click on the link it goes to its specific section and I used the following code:
//scroll to section when click on nav links
li_links.addEventListener('click', e => {
e.preventDefault();
section.scrollIntoView()
});
Why when I click on the link it goes to the end of the page and not to the specified section?
This is the code:
const Ul = document.querySelector('ul');
const sections = document.querySelectorAll('section');
for(section of sections) {
//create li:
const li_items = document.createElement("li");
//create new anchor elements:
const li_links = document.createElement("a");
//give anchor elements a hyperlinks:
const IdAttribute = section.getAttribute('id');
li_links.setAttribute('href', IdAttribute);
//get the names of the sections:
const navData = section.getAttribute("data-nav");
const text = document.createTextNode(navData);
//give the navbar style :
li_links.classList.add("menu__link");
Ul.appendChild(li_items);
li_items.appendChild(li_links);
li_links.appendChild(text);
//scroll to section when click on nav links
li_links.addEventListener('click', e => {
e.preventDefault();
section.scrollIntoView()
});
}
//end of the navbar.
HTML Code:
<header id="hdr" class="page__header">
<nav class="navbar__menu">
<!-- Navigation starts as empty UL that will be populated with JS -->
<ul id="navbar__list"></ul>
</nav>
</header>
<main>
<header class="main__hero">
<h1>Landing Page </h1>
</header>
<section id="section1" data-nav="Section 1" class="your-active-class">
<div class="landing__container">
<h2>Section 1</h2>
<p></p>
<p></p>
</div>
</section>
<section id="section2" data-nav="Section 2">
<div class="landing__container">
<h2>Section 2</h2>
<p></p>
<p></p>
</div>
</section>
<section id="section3" data-nav="Section 3">
<div class="landing__container">
<h2>Section 3</h2>
<p></p>
<p></p>
</div>
</section>
<section id="section4" data-nav="Section 4">
<div class="landing__container">
<h2>Section 4</h2>
<p></p>
<p></p>
</div>
</section>
code on codepen:
CodePen
Use const or let to declare a block scoped variable
for(const section of sections) {
Otherwise the section is in the function scope, and it is re-assigned for each iteration of the loop. So when the events happen they will point to the last value of section.
Read https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#description

How do I hide a section when I show a different section?

Basically I want one section to be shown at first as the home page. When I click on a link, I want that section to be shown, but everything else hidden, and so on. Every time I click a link, I only want the clicked on link's section to be shown.
I am close, but stuck. Here is my HTML:
About Me
Contact
<div class="container-fluid">
<div class="container about showing">
<h2>About Me</h2>
</div>
</div>
<div class="container-fluid">
<div class="container about showing">
<h2>Contact</h2>
</div>
</div>
And here is my script:
$(document).ready(function() {
$('.about').hide();
$('.contact').hide();
$('.showing').show();
$('#contact').on('click', function(e) {
e.preventDefault();
$('div').removeClass('showing');
$('.contact').addClass('showing');
if ($('div').hasClass('showing')) {
$('div').show();
} else {
$('div').hide();
}
});
});
So it shows the 'About Me' section right away and everything else is hidden. When I click the 'Contact' link it removes the 'showing' class from all my 'div's and adds the 'showing' class to my contact section. I then check to see if the 'div' has the 'showing' class, if it does I have it show the 'div' otherwise I want it to hide it.
However, when I click on the Contact link, it does show the Contact section, but it does not hide the About Me section. I know this is a long post, I am just trying to make sure I explain everything correctly. Any help is greatly appreciated!
I would strongly suggest you use data fields and common classes to make it generic.
var $pages = $('.container');
$('.menu').on('click', function(e){
//remove showing from all containers
$pages.removeClass('showing');
//put it on the container with the matching class of the data target
$pages.filter('.'+ $(e.target).data('target')).addClass('showing');
});
.container {
display: none;
}
.container.showing {
display: unset;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
About Me
Contact
Other
<div class="container-fluid">
<div class="container home showing">
<h2>Home</h2>
</div>
</div>
<div class="container-fluid">
<div class="container about">
<h2>About Me</h2>
</div>
</div>
<div class="container-fluid">
<div class="container contact">
<h2>Contact</h2>
</div>
</div>
<div class="container-fluid">
<div class="container other">
<h2>Other</h2>
</div>
</div>
Here's a few things you can optimize:
$(document).ready(function() {
$('.about, .contact').hide(); //put both of them in single selector
$('.showing').show(); //this shows the only element that has "showing
$('#contact, #about').on('click', function(e) {
e.preventDefault();
var self = $(this); //reference to the object being clicked
var target = $("." + self.attr('id'));
//removes "showing" class from all others and hides them
$(".container").not(target).removeClass("showing").hide();
//adds "showing" class to the new current item
target.addClass("showing").show();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
About Me
Contact
<div class="container-fluid">
<div class="container about showing">
<h2>About Me</h2>
</div>
</div>
<div class="container-fluid">
<div class="container contact"> <!--you don't want that "showing" class here!-->
<h2>Contact</h2>
</div>
</div>

How can I use JQuery to create an efficient method for Next and Prev buttons to show/hide Sections of a single HTML Page?

I have a single HTML file comprised of several sections and I need to be able to display one Section at a time. Each section will have Next and Previous buttons at the bottom which will show the next Section and hide the section currently in focus.
Originally I was using a very simple method to achieve achieve this:
<section id="Page1" class="page" style="display:none">
<p>Content of page 1</p>
<h3><span onclick="show('Page2');">Next</span></h3>
</section>
<section id="Page2" class="page" style="display:none">
<p>Content of page 2</p>
<h3><span onclick="show('Page1');">Previous</span></h3>
<h3><span onclick="show('Page3');">Next</span></h3>
</section>
<section id="Page3" class="page" style="display:none">
<p>Content of page 3</p>
<h3><span onclick="show('Page2');">Previous</span></h3>
</section>
However, since the number of Sections will fluctuate, and the very first and last section will always have the same content, I want to make it easy for the person using this HTML template to simply delete all unneeded sections in between without having to update the IDs targeted by the Prev/Next button code.
Here's my Fiddle: Next Previous Button Fiddle
I started some JQuery that ALMOST works (beneath the //Next Prev Buttons comment). I'm using :focus, which means it's only targeting the Span that contains the button, but I can't figure out the selector for the button's parent Section tag.
Thanks in advance for your time. :)
The :focus selector won't select your <span> because it isn't a typically "tabbable" element. Since the <span> is the element that was clicked to trigger your click handler, you can access it through this (or $(this) if you want the jQuery version).
$.next only searches siblings of the selected element. Since the next section isn't a sibling of your <span>, $.next won't find it. You'll need to find the parent <section> with $.closest('section') and move to the next section from there.
You're using $(this).hide();, which only hides the clicked element. Again, use $(this).closest('section') to find the entire section and hide that.
With the click handlers defined in your JavaScript, you don't need the onclick attributes in your HTML. Remove them.
Putting it all together:
$('.pageNext').on('click', function showNext() {
// cache DOM lookups when possible
const $currentSection = $(this).closest('section');
$currentSection.next('section').show();
$currentSection.hide();
});
$('.pagePrev').on('click', function showPrev() {
const $currentSection = $(this).closest('section');
$currentSection.prev('section').show();
$currentSection.hide();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="Page1" class="page" style="">
<p>Content of page 1</p>
<h3><span class="pageNext">Next</span></h3>
</section>
<section id="Page2" class="page" style="display:none">
<p>Content of page 2</p>
<h3><span class="pagePrev">Previous</span></h3>
<h3><span class="pageNext">Next</span></h3>
</section>
<section id="Page3" class="page" style="display:none">
<p>Content of page 3</p>
<h3><span class="pagePrev">Previous</span></h3>
<h3><span class="pageNext">Next</span></h3>
</section>
<section id="Page4" class="page" style="display:none">
<p>Content of page 4</p>
<h3><span class="pagePrev">Previous</span></h3>
<h3><span class="pageNext">Next</span></h3>
</section>
<section id="Page5" class="page" style="display:none">
<p>Content of page 5</p>
<h3><span class="pagePrev">Previous</span></h3>
<h3><span class="pageNext">Next</span></h3>
</section>
<section id="Page6" class="page" style="display:none">
<p>Content of page 6</p>
<h3><span class="pagePrev">Previous</span></h3>
<h3><span class="pageNext">Next</span></h3>
</section>
<section id="Page7" class="page" style="display:none">
<p>Content of page 7</p>
<h3><span class="pagePrev">Previous</span></h3>
</section>
This also translates easily, if more verbosely, to vanilla JavaScript:
// $('.pageNext').on('click', function showNext() {
document.querySelectorAll('.pageNext').forEach(element => {
element.addEventListener('click', function showNext(event) {
// const $currentSection = $(this).closest('section');
const currentSection = event.target.closest('section');
// $currentSection.next('section').show();
// (not a direct translation but it works since you don't have
// non-section siblings)
currentSection.nextElementSibling.style.display = 'block';
// or previousElementSibling for $.prev
// $currentSection.hide();
currentSection.style.display = 'none';
});
});
Change your functions to this:
//Next Prev Buttons
$('.pageNext').on('click', function showNext(){
//$(":focus").next('section').show();
$(this).parent().parent().hide();
$(this).parent().parent().next().show();
});
$('.pagePrev').on('click', function showPrev(){
//$(":focus").next('section').show();
$(this).parent().parent().hide();
$(this).parent().parent().prev().show();
});

Change "selected" on scroll in page

I've been trying to get the automatic update on my navbar but i cant get it to work.
Here is my code: http://pastebin.com/YTHaBD0i
<div id="header">
<ul class="nav-list">
<li class="download selected">Download</li>
<li class="features">Features</li>
<li class="method">Method</li>
<li class="purchase">Purchase</li>
</ul>
</div>
<div id="footer">yey productions © 2016</div>
<div id="fullpage">
<div class="section " id="section0">
<div class="intro">
<h1>Download</h1>
<p>Lorem Ipsum</p>
</div>
</div>
<div class="section" id="section1">
<div class="slide" id="slide1">
<div class="intro">
<h1>Features</h1>
<p>Cheese.</p>
</div>
</div>
<div class="slide" id="slide2">
<h1>Cheese2</h1>
</div>
</div>
<div class="section" id="section2">
<div class="intro">
<h1>Yey</h1>
</div>
</div>
<div class="section" id="section3">
<div class="intro">
<h1>Yey2</h1>
</div>
</div>
</div>
Help would be much appreciated!
Greetz,
Assuming you are using jQuery, you will need a function that fires every time you scroll.
From there, you need to detect which elements are in view.
Once you know which elements are in view, clear any currently active elements with the .selected class, then choose which one you want to be .selected and add the .selected class.
Edit for more detail:
Below is a pure JavaScript solution, which I found here. This should be close to a drop-in solution!:
(function() {
'use strict';
var section = document.querySelectorAll(".section");
var sections = {};
var i = 0;
Array.prototype.forEach.call(section, function(e) {
sections[e.id] = e.offsetTop;
});
window.onscroll = function() {
var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
for (i in sections) {
if (sections[i] <= scrollPosition) {
document.querySelector('.selected').setAttribute('class', ' ');
document.querySelector('a[href*=' + i + ']').setAttribute('class', 'selected');
}
}
};
})();

Javascript and jQuery to make divs into a tab based content page

I recently had a 30 min test for a job application using only Javascript with jQuery. Didn't have to be styled well or anything. I created a very basic "30 min" page with Javascript and jQuery which I thought was "ok".. I just wanted to get some feedback if there was a more efficient/better way of doing this? as it turned out, I didn't get the job.. always learning, and also the job was quite a way from where I live.
Anyway, the original HTML page given was as follows, and after that is my humble attempt to turn the basic HTML into a tab based content page - again within 30 mins.
<html>
<head>
<!-- stylesheet, javascript, etc. here -->
</head>
<body>
<h1>My Page</h1>
<h2 class="subheading">The first section</h2>
<div class="content">
<p>Lorem ipsum...</p>
</div>
<h2 class="subheading">The second section</h2>
<div class="content">
<img src="/some_image" alt="Image" title="Image"></img>
<p>Some other text</p>
</div>
<h2 class="subheading">The third section</h2>
<div class="content">
And some more text here
</div>
<div class="footer">
This is at the foot of the page
</div>
</body>
</html>
Ok, so my humble attempt is as follows:
<html>
<head>
<title>Test JS page</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<style type="text/css">
#tabs
{
width:457px;
height:60px;
}
#tab1, #tab2, #tab3
{
width:150px;
border:1px solid #ccc;
}
#tab1
{
float:left;
}
#tab3, #tab2
{
float:right;
}
#tab2_content, #tab3_content
{
display:none;
}
.clear
{
clear:both;
}
#content
{
height:300px;
}
</style>
<script type="text/javascript">
$(document).ready(function () {
$('#tab1_link').click(function (e) {
e.preventDefault();
clearContent();
$('#tab1_content').show();
});
$('#tab2_link').click(function (e) {
e.preventDefault();
clearContent();
$('#tab2_content').show();
});
$('#tab3_link').click(function (e) {
e.preventDefault();
clearContent();
$('#tab3_content').show();
});
});
function clearContent() {
$("div[id*='_content']").each(function() {
$(this).hide();
});
}
</script>
</head>
<body>
<h1>My Page</h1>
<div id="tabs">
<div id="tab1"><a id="tab1_link" class="subheading">The first section</a></div>
<div id="tab2"><a id="tab2_link" class="subheading">The second section</a></div>
<div id="tab3"><a id="tab3_link" class="subheading">The third section</a></div>
</div>
<div class="clear">
</div>
<div id="content">
<div id="tab1_content" class="content">
<p>Lorem ipsum...</p>
</div>
<div id="tab2_content" class="content">
<img src="/some_image" alt="Image" title="Image"></img>
<p>Some other text</p>
</div>
<div id="tab3_content" class="content">
And some more text here
</div>
</div>
<div class="footer">
This is at the foot of the page
</div>
</body>
</html>
So as you can see, not pretty for sure.. the stylesheet was inline as is the script, however this was meant to be a test to show if you knew Javascript/jQuery enough to perform the tasks.. I figured it wasn't great, but not too bad either..
I would be grateful for any feedback on other ways to achieve the desired result.. again it doesn't have to be pretty, just functional.. and of course all within 30 mins..
Thanks!
<div id="tabs">
<ul>
<li>The First Section</li>
<li>The Second Section</li>
<li>The Third Section</li>
</ul>
<div id="tabs-1" class="content">
<p>Lorem ipsum...</p>
</div>
<div id="tabs-2" class="content">
<img src="/some_image" alt="Image" title="Image"></img>
</div>
<div id="tabs-3" class="content">
<p>Some other text</p>
</div>
</div>
<script>
$(function() {
$("#tabs").tabs();
});
</script>
http://jqueryui.com/demos/tabs/
Without knowing something about the company you were taking the test for its hard to say what they were looking for.
In general employers are not looking for perfect code but how you approach the problem. For example you could say that they were looking to see if you would follow their instructions blindly or stick to convention and good practices of adding external style/script references or just clean, standard compliant, concise code.
I am a complete novice so please don't take anything I say too seriously but I would of attempted to create some reusable concise code which would/could be reused and expanded very quickly and easily while being maintenance friendly (Just because its a text doesn't mean that you can forget about these things).
Just doing this very rough and off the top of my head but something like this:
$('#tab-menu').click(function(e) {
e.preventDefault();
clearContent();
$(this).show();
});
If it was for a company that were involved with mobile devices you would probably want to bind the events so you get the same functionality.
Something that I have always done is provided an assumptions document even just if its in notepad. Its always looked upon positively as it shows you are stopping and thinking about what you have to do instead of going gun ho.
Overall I think you did a good job! You have a great attitude and just learn from experiences like these, improve and get better! Today's juniors will be tomorrows experts! if we work hard enough
you don't need jQuery UI for this.
demo http://jsbin.com/atogil/2/edit
HTML
<div class="tabs">
<nav class="tab-btns">
tab btn 1
tab btn 2
tab btn 3
tab btn 4
</nav>
<div class="tab-contents">
<div id="tab1">tab content 1</div>
<div id="tab2">tab content 2</div>
<div id="tab3">tab content 3</div>
<div id="tab4">tab content 4</div>
</div>
</div>
JS
$.fn.myTabs = function(settings){
return this.each(function() {
/*
save cached version of the first elements inside the containers.
by calling the first elements of each container you are not limitng
the plugin user to any specific class or elememt.
*/
var btns = $(settings.nav, this).children(),
tabs = $(settings.tabs, this).children();
/*
we relying on the order of the elements as the conection between
the buttons and the tabs notice that .each() get the index of the btn..
we are useinf it to find the current tab.
*/
btns.each(function(index){
var btn = $(this),
tab = tabs.eq(index);
btn.click(function (e){
/* prevent unnesscry work by checking
if the button clicked is already active */
if(btn.is('.active')) return false;
/* notice that first filter to find the last 'active'
button before we remove the 'active' class otherwise it
remove the class for every button.
unnesscry work prevented again */
btns.filter('.active').removeClass('active');
/* hide previus tab.. */
tabs.filter(':visible').hide();
btn.addClass('active');
tab.show();
return false;
});
});
// emulate click on the first tab button;
btns.first().click();
});
};
and call your script like this;
$(function() {
$('.tabs').myTabs({
// container of navigation inside '.tabs'
nav : '.tab-btns',
// container of contents inside '.tabs'
tabs : '.tab-contents'
});
});

Categories

Resources