Fade In Divs One After the Other on Page Load With jQuery - javascript

I know that this question has been asked many times before:
Javascript: Fade In images on page load; one after the other?
Fade in divs one after another
jQuery .fadeIn() on page load?
But I've tried all of the suggested techniques and none of them worked. I'm trying to get three lines of text (the words are wrapped in divs), to appear one after the other when the page loads. Here is what I have:
HTML:
<div class="row"><!--second row-->
<div class="col-lg-12 center">
<div id="tagline-wrapper">
<div class="center-text hidden1">Responsive</div>
<div class="between-lines">
<div class="line"></div>
<div class="clean hidden2">Clean</div>
<div class="line"></div>
</div>
<div class="center-text hidden3">Powerful</div>
</div>
</div>
</div><!--end row-->
CSS:
.center {
text-align: center;
display: flex;
color: #ffffff;
font-family: 'proxima_nova_ltsemibold';
text-transform: uppercase;
font-size: 52px;
}
#tagline-wrapper {
margin-top: 150px;
margin-left: auto;
margin-right: auto;
}
.center-text {
text-align: center;
font-family: 'proxima_nova_ltsemibold';
font-size: 52px;
text-transform: uppercase;
color: #ffffff;
}
.between-lines {
display: flex;
align-items: center;
}
.line {
border-bottom: 2px solid #ffffff;
display: block;
flex-grow: 1;
height: 0;
}
.clean {
padding: 0 1.5rem;
text-align: center;
font-family: 'proxima_nova_ltsemibold';
font-size: 52px;
text-transform: uppercase;
color: #ffffff;
}
/*hide elements initially*/
.hidden1 {
display: none;
}
.hidden2 {
display: none;
}
.hidden3 {
display: none;
}
JavaScript
$(document).ready(function(){
var elements = [ 'hidden1, hidden2, hidden3' ];
for (var i = 0; i < elements.length; i++) {
setTimeout(function() {
elements[i].style.opacity = 1;
}, 1250 * i);
}
});
The above is the JS technique that was suggested in the first linked article.
JSFiddle attempt with the first technique here: https://jsfiddle.net/b184reyv/1/
JSFiddle attempt with the second technique here: https://jsfiddle.net/b184reyv/2/
JSFiddle attempt with the third technique here: https://jsfiddle.net/4w7kxLxf/
Thank you.

So there are a handful of issues here that I'll try to document for you:
1. for loops in JavaScript often scope a bit unexpectedly. You can read here for a great explanation of them. In your example, using i in a setTimeout would result in the last iteration of the loop being grabbed each time, as i is declared globally.
2. You're modifying the opacity of your hidden elements, but their original state is display: none;. An item with display: none; will never be shown, regardless of opacity. Instead of display: none;, use opacity: 0; You can also add a transition: opacity 1s to make them fade-in instead of just "appear".
3. Your array is not syntactically correct. Each item should be within quotes and split with a comma, whereas yours is currently one large string with commas in it.
var elements = ['hidden1', 'hidden2', 'hidden3'];
4. You're using .style on each item in the elements array, but they are simply strings. At no point to you convert these strings into elements, so trying to use .style will throw an error. You'll need to implement them into a selector.
Putting all of this information together, you may be looking for something like this instead. See the comments in the JavaScript for explanation.
var elements = ['hidden1', 'hidden2', 'hidden3'];
for (let i = 0; i < elements.length; i++) {
var thisElement = $("." + elements[i]); //Get the current element based on class
fadeInElement(thisElement, i); //Call our "Fade in" function
}
function fadeInElement(elem, time) { //Fade-in function that takes the element to fade-in, and the time it should wait
setTimeout(function() {
elem.css("opacity", "1"); //Set our element's opacity to 1
}, 1250 * time); //Set the time it should wait
}
body {
background-color: black;
}
.center {
text-align: center;
display: flex;
color: #ffffff;
font-family: 'proxima_nova_ltsemibold';
text-transform: uppercase;
font-size: 52px;
}
#tagline-wrapper {
margin-top: 150px;
margin-left: auto;
margin-right: auto;
}
.center-text {
text-align: center;
font-family: 'proxima_nova_ltsemibold';
font-size: 52px;
text-transform: uppercase;
color: #ffffff;
}
.between-lines {
display: flex;
align-items: center;
}
.line {
border-bottom: 2px solid #ffffff;
display: block;
flex-grow: 1;
height: 0;
}
.clean {
padding: 0 1.5rem;
text-align: center;
font-family: 'proxima_nova_ltsemibold';
font-size: 52px;
text-transform: uppercase;
color: #ffffff;
}
/*hide elements initially*/
.hidden1, .hidden2, .hidden3 {
opacity: 0;
transition: opacity 1s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<!--second row-->
<div class="col-lg-12 center">
<div id="tagline-wrapper">
<div class="center-text hidden1">Responsive</div>
<div class="between-lines">
<div class="line"></div>
<div class="clean hidden2">Clean</div>
<div class="line"></div>
</div>
<div class="center-text hidden3">Powerful</div>
</div>
</div>
</div>
<!--end row-->

Oh so here my custom answer for what I understand of your problem :)
$(window).load(function() {
var $word1 = $(".word1");
var $word2 = $(".word2");
var $word3 = $(".word3");
$word1.fadeIn(1000, function() {
$word2.fadeIn(1000, function() {
$word3.fadeIn(1000);
});
});
});
.word {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="word word1">
this
</div>
<div class="word word2">
is
</div>
<div class="word word3">
working
</div>

Related

Can I create actions based on HTML elements to show and hide divs with javascript?

Novice -
I am building a page in a TinyMCE wysiwyg and want to be able to show and hide divs when a link/button is clicked. The way things are structured, it appears I can't add javascript into the html section, so I am identifying the links with javascript.
From examples I was able to create the following code, which toggles a single div when clicking on any button marked with the toggleLink class. Is there a good way to target individual elements to show 1 div and hide the rest? I think getElementById might be heading in the right direction, but I am not sure how to apply the eventListeners individually
var togg = document.getElementsByClassName("toggleLink");
var i;
for (i = 0; i < togg.length; i++) {
togg[i].addEventListener("click", function() {
this.classList.toggle("active");
var openDiv = document.getElementById("myDIV1");
if (openDiv.style.display === "none"){
openDiv.style.display = "block";
} else {
openDiv.style.display = "none";
}
});
}
.demoLinks {
background-color: #fff;
height: 200px;
width: 15%;
font-size: 14pt;
color: #ffffff;
background-color: #3156f3;
padding: 20px 0px 20px 20px;
font-family: 'Lato', sans-serif;
float: left;
position: sticky; top: 100px;
}
.demoLinks p {
margin-bottom: 2px;
padding-left: 15px;
color: #ffffff;
}
.demoLinks p a {
color: #ffffff;
}
.toggleLink {
color: #ffffff;
cursor:pointer;
}
.demoVideos {
background-color: #fff;
width: 75%;
padding: 0px 0px 20px 20px;
font-family: 'Lato', sans-serif;
float: right;"
}
<div>
<div class="demoLinks">
<p style="margin-bottom: 8px; color: #ffffff; font-weight: bold;">Products:</p>
<p><a class="toggleLink">This Link</a></p>
<p><a class="toggleLink"> ThatLink</a></p>
</div>
<div class="demoVideos">
<div id="myDIV1" style="display: block;">
<p style="margin-bottom: 0.25em;"><span style="font-family: 'Lato', sans-serif; color: #2b28bc; margin-bottom: 0.5em;"><strong><span style="font-size: 24pt;">Product Demo 1</span></strong></span></p>
<div style="height:585px; width:1034px; background-color:#333333;"></div>
</div>
<div id="myDIV2" style="display: none;">
<p style="margin-bottom: 0.25em;"><span style="font-family: 'Lato', sans-serif; color: #2b28bc; margin-bottom: 0.5em;"><strong><span style="font-size: 24pt;">Product Demo 2</span></strong></span></p>
<div style="height:585px; width:1034px; background-color:#333333;"></div>
</div>
</div>
</div>
Thanks for any assistance!
You can correlate your links with your targets using a suffix on the 'id' property. So, for instance, you can give your first link an id of 'link1', which you can then relate to 'myDIV1' by replacing the text 'link' with 'myDIV'. And the same logic then for all link-div associations.
Once you have that, you should know that the function you pass to an event listener accepts a parameter which is the event that ultimately calls it. You can use this to get the id of the link that was clicked (e.target.id);
With that you can show the target div you're interested in, and hide the rest.
Below is a very simplified version of your code, along with my recommended logic. I should let you know that querySelectorAll has similar purposes to getElement(s)By..., but lets you select using css selectors. Also, the syntax 'test ? trueResult : falseResult' can be replaced by an if/then statement if you desire.
var links = document.querySelectorAll('.toggleLink');
var demos = document.querySelectorAll('.demoVideos > div');
for (var l = 0; l < links.length; l++) {
links[l].addEventListener("click", function(e) {
var linkDivId = e.target.id;
var targetDivId = linkDivId.replace('link', 'myDIV');
for (var d = 0; d < demos.length; d++)
demos[d].style.display = demos[d].id == targetDivId ? 'block' : 'none';
});
}
<div class="demoLinks">
<a id='link1' class="toggleLink">Demo 1 Link</a><br/>
<a id='link2' class="toggleLink">Demo 2 Link</a>
</div>
<br/>
<div class="demoVideos">
<div id="myDIV1" style="display: none;">
Product Demo 1
</div>
<div id="myDIV2" style="display: none;">
Product Demo 2
</div>
</div>
First off, forgive me a bit I took some liberties with your markup and CSS to make it easier for me to visualize the task at hand - toggle of visibility.
Rather than use an element id, I would suggest a class but here, I put in a data-linktarget on each of the links so you can simply put a selector in there and use either an id, class or whatever you choose which should give your task some flexibility.
Next, I used a hidden class to toggle the visibility of the target - this can be done several ways but I used this to help make intent clear. I also toggle the "active" class but did not do anything with it other than facilities what you had started.
Rather than a complex set of event handlers on multiple id's, I used a class to target the toggleLink class.
I made the code somewhat simple but enough to illustrate what it is doing.
function handleEvent(event) {
let videos = document.querySelector(".demo-videos");
let hideMe = videos.querySelectorAll(".demo-thing:not(.hidden)");
hideMe.forEach(function(el) {
el.classList.toggle("hidden", true);
el.classList.toggle("active", false);
});
let vSelected = videos.querySelector(this.dataset.linktarget);
vSelected.classList.toggle("hidden", false);
vSelected.classList.toggle("active", true);
}
Array.prototype.filter.call(document.getElementsByClassName("toggleLink"), function(testElement) {
testElement.addEventListener("click", handleEvent);
});
.hidden {
display: none;
}
.demo-container {
font-family: 'Lato', sans-serif;
}
.demoLinks {
height: 200px;
width: 15%;
font-size: 14pt;
background-color: #3156f3;
padding: 20px 0px 20px 20px;
float: left;
position: sticky;
top: 100px;
font-weight: bold;
}
.demo-links-title-text {
font-size: 1.2em;
color: #FFFF00;
}
.demoLinks .demo-link {
margin-bottom: 8px;
font-weight: bold;
margin-bottom: 2px;
padding-left: 15px;
}
.toggleLink {
color: #FFFF88;
cursor: pointer;
}
.demo-videos {
background-color: #fff;
width: 75%;
padding: 0px 0px 20px 20px;
float: right;
}
.demo-videos .header-part {
margin-bottom: 0.25em;
}
.demo-videos .header-part .header-part-text {
color: #2b28bc;
margin-bottom: 0.5em;
font-size: 24pt;
font-weight: bold;
/* put back <strong> tags if desired instead */
}
.demo-videos .block-part {
height: 585px;
width: 1034px;
background-color: #333333;
color: cyan;
}
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Lato&display=swap" rel="stylesheet">
<div class="demo-container">
<div class="demoLinks">
<p class="demo-links-title-text">Products:</p>
<p class="demo-link"><a class="toggleLink" data-linktarget="#myDIV1" href="#">This Link</a></p>
<p class="demo-link"><a class="toggleLink" data-linktarget=".demo-thing:nth-child(2)" href="#">ThatLink</a></p>
<p class="demo-link"><a class="toggleLink" data-linktarget=".demo-thing:nth-child(3)" href="#">That new Link</a></p>
</div>
<div class="demo-videos">
<div id="myDIV1" class="demo-thing active">
<p class="header-part"><span class="header-part-text"><span>Product Demo 1</span></span>
</p>
<div class="block-part">I am first</div>
</div>
<div id="myDIV2" class="demo-thing hidden">
<p class="header-part"><span class="header-part-text"><span>Product Demo 2</span></span>
</p>
<div class="block-part">Happy Day</div>
</div>
<div id="another-id" class="demo-thing hidden">
<p class="header-part"><span class="header-part-text"><span>Product Demo New</span></span>
</p>
<div class="block-part">Wonderful news</div>
</div>
</div>
</div>

How to show multiple tabbed content sections?

I have a website with three sections containing tabbed areas. I had an older version of this which worked fine, and showed all sections correctly at all times, however as I was changing to a new layout the tabbed sections stopped functioning, I then changed them to some new code and ended up preferring this instead. I then noticed that my content would only show in one section at a time, so some sections do not show up when the page is loaded, unless the tab link is active/clicked.
I recall finding a way to fix this before but I've looked online and can't find anything, and didn't save a version of my old JS code to refer back to. I was hoping someone could help me remember why this happens and how to fix it.
I should note that I have unique IDs for my code and I have not reflected this in my code, as I had that issue the first time round. The unique IDs do not help fix the issue unfortunately.
function openPage(pageName, elmnt, color) {
// Hide all elements with class="tabcontent" by default */
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Remove the background color of all tablinks/buttons
tablinks = document.getElementsByClassName("tablink");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].style.backgroundColor = "";
}
// Show the specific tab content
document.getElementById(pageName).style.display = "block";
// Add the specific color to the button used to open the tab content
elmnt.style.backgroundColor = color;
}
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
h3 {
font-size: 15px;
word-spacing: 2px;
font-weight: 100;
letter-spacing: 1px;
text-transform: uppercase;
font-family: 'IBM Plex Mono', sans-serif;
}
h2 {
font-size: 40px;
color: white;
word-spacing: 2px;
margin-bottom: 15px;
font-weight: 700;
letter-spacing: 1px;
font-family: 'IBM Plex Serif', sans-serif;
}
p {
font-weight: 300;
font-size: 15px;
color: white;
text-align: justify;
line-height: 1.5;
}
.new-section__black {
padding: 5%;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
position: relative;
transition: .5s ease;
background-color: #000;
height: 100%;
}
/* Style tab links */
.tablink {
float: left;
outline: none;
cursor: pointer;
margin: 0 1%;
padding: 5px 5px;
font-size: 17px;
width: 10%;
}
.link-black {
background-color: #fff;
color: #000;
border: 1px solid #000;
}
.link-white {
background-color: #000;
color: #fff;
}
.tablink:first-of-type {
margin-left: 5%;
}
.tablink:last-of-type {
margin-right: 5%;
}
.link-black:active,
.link-black:hover {
background-color: #000;
color: #fff;
box-shadow: 2px 2px 10px #555;
}
.link-white:active,
.link-white:hover {
background-color: #fff;
color: #000;
}
/* Style the tab content (and add height:100% for full page content) */
.tabcontent {
width: 100%;
display: none;
margin-top: 1%;
padding: 100px 20px;
height: 100%;
}
.content-black {
color: #000;
}
.content-white {
color: #fff;
}
.tabcontent .col:first-of-type {
margin-left: 0;
}
#defaultOpen {
display: block;
}
<section class="card new-section__black new_section">
<button class="tablink link-white" onclick="openPage('Tab1', this)" id="defaultOpen">
<h3>Tab1</h3>
</button>
<button class="tablink link-white" onclick="openPage('Tab2', this)">
<h3>Tab2</h3>
</button>
<button class="tablink link-white" onclick="openPage('Tab3', this)">
<h3>Tab3</h3>
</button>
<button class="tablink link-white" onclick="openPage('Tab4', this)">
<h3>Tab4</h3>
</button>
<div id="Tab1" class="tabcontent content-white">
<div class="col span-2-of-2">
<h2>Tab1</h2>
<p>Text</p>
</div>
</div>
<div id="Tab2" class="tabcontent content-white">
<div class="col span-2-of-2">
<h2>Tab2</h2>
<p>Text</p>
</div>
</div>
<div id="Tab3" class="tabcontent content-white">
<div class="col span-2-of-2">
<h2>Tab3</h2>
<p>Text</p>
</div>
</div>
<div id="Tab4" class="tabcontent content-white">
<div class="col span-2-of-2">
<h2>Tab4</h2>
<p>Text</p>
</div>
</div>
</section>
Here is a CodePen example of what I have.
If you have multiple sets of "tabs" on the page, you need to scope your interactions to that specific <section>.
function openPage(pageName, elmnt, color) {
// Get the parent node, make all DOM selections based on this
var section = elmnt.parentElement;
// Hide all elements with class="tabcontent" by default */
var i, tabcontent, tablinks;
tabcontent = section.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Remove the background color of all tablinks/buttons
tablinks = section.getElementsByClassName("tablink");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].style.backgroundColor = "";
}
// Show the specific tab content
section.getElementById(pageName).style.display = "block";
// Add the specific color to the button used to open the tab content
elmnt.style.backgroundColor = color;
}
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
Also, you repeat element id values everywhere, this is not proper HTML and will lead to unexpected behavior. Each id should be unique. (you currently have multiple "defaultOpen" elements, you have multiple "Tab1", "Tab2", etc... rename them with no repeated values)

Create a custom drop down menu and place dataset value in input

I'm trying to create a custom drop down menu, using HTML, CSS and Vanilla Javascript.
I've managed to get the menu to appear when the user clicks on the the "from" input field, however when I try and click on an option, it wont let you add the value stored in the "code" dataset.
I did get it to work by using setTimeout method, however it is a bit hit and miss sometimes and doesn't seem like a good solution.
Is there an alternative way to get it to work?
function app() {
var messages = document.querySelector(".messages");
var inputFrom = document.querySelector(".input-from");
var inputTo = document.querySelector(".input-to");
var nearestContainer = document.querySelector(".nearest-container");
inputFrom.addEventListener("focus", inputToFocusIn, false);
function inputToFocusIn(e) {
messages.innerHTML = "focusin event triggered on input-from";
// add class
inputFrom.classList.add("input-from--focusin");
nearestContainer.classList.add("nearest-container--active");
// remove class
inputFrom.classList.remove("input-from--focusout");
nearestContainer.classList.remove("nearest-container--hidden");
}
inputFrom.addEventListener("focusout", inputToFocusOut, false);
function inputToFocusOut(e) {
messages.innerHTML = "focusout event triggered on input-from";
// add class
inputFrom.classList.remove("input-from--focusin");
nearestContainer.classList.remove("nearest-container--active");
// remove class
inputFrom.classList.add("input-from--focusout");
nearestContainer.classList.add("nearest-container--hidden");
}
var nearestStations = document.querySelectorAll(".nearest-station");
// add event listener to buttons
for(var nearestStation of nearestStations) {
nearestStation.addEventListener("click", addToInputFrom, false);
}
function addToInputFrom(e) {
inputFrom.classList.add("input-from--focusout");
nearestContainer.classList.add("nearest-container--hidden");
inputFrom.classList.remove("input-from--focusin")
nearestContainer.classList.remove("nearest-container--active")
var targetDataset = e.currentTarget.dataset.code;
messages.innerHTML = "station added to input from field"
inputFrom.value = "";
inputFrom.value = targetDataset;
}
var switchButton = document.querySelector(".button-switch");
switchButton.addEventListener("click", clickSwitch, false);
function clickSwitch(e) {
var inputFromValue = inputFrom.value;
var inputToValue = inputTo.value;
inputFrom.value = inputToValue;
inputTo.value = inputFromValue;
}
}
window.onload = app();
/* stylesheet */
body {
font-family: "GRAPHIK";
font-style: normal;
font-weight: 400;
font-size: 16px;
color: #242424;
}
* {
box-sizing: border-box;
outline: none;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-color: #FF4136;
}
.search-container {
display: flex;
flex-direction: column;
flex-shrink: 0;
width: 300px;
padding: 10px;
background-color: #FFF;
border-radius: 10px;
}
.form-container {
display: flex;
flex-direction: row;
width: 100%;
}
.input-container {
width: 100%;
}
.input {
width: 100%;
border: none;
border-radius: 10px;
background-color: #f1f1f1;
padding: 10px;
}
.input-from {
margin-bottom: 5px;
}
.input-from--focusout {
border-radius: 10px;
}
.input-from--focusin {
border-radius: 10px 10px 0 0;
}
.input-to {
margin-bottom: 5px;
}
.switch-container {
margin-bottom: 5px;
}
.button {
border: none;
background-color: transparent;
}
.button-switch {
height: 100%;
width: 38px;
margin-left: 5px;
background-color: #f1f1f1;
border-radius: 10px;
background-image: url(../assets/images/switch.svg);
background-position: center;
background-size: 20px;
background-repeat: no-repeat;
}
.button-switch:hover {
background-image: url(../assets/images/switch-hover.svg);
}
.button-search {
padding: 10px;
background-color: #2ECC40;
color: #FFF;
border-radius: 10px;
width: 100%;
transition: background-color 0.5s ease;
}
.button-search:hover {
background-color: #33e147;
}
.input-container-to {
position: relative;
}
.nearest-container {
position: absolute;
top: 38px;
background-color: #f1f1f1;
padding: 5px;
border-radius: 0 0 10px 10px;
width: 100%;
z-index: 100;
}
.messages {
width: 300px;
background-color: #FFF;
padding: 5px;
border-radius: 10px;
text-align: center;
margin-bottom: 5px;
font-size: 10px;
}
.finding, .show-more {
width: 100%;
font-size: 10px;
font-style: italic;
margin: 0;
padding: 5px;
}
.show-more {
text-align: center;
}
.nearest-station {
font-size: 10px;
padding: 5px;
border-radius: 10px;
}
.nearest-container--hidden {
display: none;
}
.nearest-station--active {
display: flex;
}
.nearest-station:hover {
background-color: #FFF;
cursor: pointer;
}
.logo {
margin-right: 5px;
}
.nr-logo {
width: 15px;
}
.station-distance {
font-style: italic;
float: right;
}
<div class="container">
<div class="messages">messages here</div>
<div class="search-container">
<div class="form-container">
<div class="input-container">
<div class="input-container-to">
<input type="text" class="input input-from" placeholder="From">
<div class="nearest-container nearest-container--hidden">
<div class="stations-container">
<p class="finding">Finding stations closest to you...</p>
<!-- stations here-->
<div class="nearest-station" data-code="Leigh-on-Sea">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Leigh-on-Sea</span>
<span class="station-distance">0.6km</span>
</div>
<div class="nearest-station" data-code="Chalkwell">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Chalkwell</span>
<span class="station-distance">1.5km</span>
</div>
<div class="nearest-station" data-code="Westcliff">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Westcliff</span>
<span class="station-distance">2.7km</span>
</div>
<div class="nearest-station" data-code="Southend Central">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Southend Central</span>
<span class="station-distance">3.6km</span>
</div>
<div class="nearest-station" data-code="Southend Victoria">
<span class="logo"><img class="nr-logo" src="assets/images/nr-logo.svg"></span>
<span class="station-name">Southend Victoria</span>
<span class="station-distance">3.8km</span>
</div>
</div>
<div class="stations-show-more">
<!--
<p class="show-more">Show more stations</p> -->
</div>
</div>
</div>
<div class="input-container-to">
<input type="text" class="input input-to" placeholder="To">
</div>
</div>
<div class="switch-container">
<input type="button" class="button button-switch">
</div>
</div>
<div class="button-search-container">
<input type="button" class="button button-search" value="Search">
</div>
</div>
</div>
Using setTimeout in the inputToFocusOut() function is indeed the correct way to obtain the desired effect: hiding of the menu must be delayed so that a click on a menu item will register and its callback will fire. There should be nothing hit and miss about it, just set the delay at a reasonable value, say 300ms, and remove the hiding of the menu from the addToInputFrom() callback. Actually, you can remove all of the latter function's class-toggling calls, as they are redundant there and may interfere. The menu will be shown/hidden by virtue of inputFrom gaining/losing focus.
BTW, why are you using focusout and not blur?
Using focusout event here
inputFrom.addEventListener("focusout", inputToFocusOut, false);
is not right. Because it will be triggered before click event.
When the function inputToFocusOut is executed the .nearest-container becomes hidden:
nearestContainer.classList.add("nearest-container--hidden");
and that's why click event for it and all of its child nodes (we are interested in .nearest-station elements) won't be triggered. Instead of focusout, use mousedown event. With blur event it won't work.

Looking for ways to refactor my jQuery code for a div toggle I created

I wrote some code with three things in mind:
Highlighting a selection's border using 'on click'.
Selecting one item will remove the highlight from the other item.
The ability to deselect each item on click.
I've managed to get everything working for the most part, but I don't particularly like how complex the code is for the radial dot that appears when one item is selected.
Below is an example of what I'm talking about, particularly I'm looking for ways to refactor the code below into something a little more legible (shorter).
$(this).children('.radial').children().toggleClass('checked').parents('.itembox')
.siblings().children('.radial').children().removeClass('checked');
Here's a working example for more context (line 10):
var raceInternet = false;
var racePhone = false;
var raceTv = false;
$(function() {
var $targetDiv = $('#race-internet > .itembox');
var $radialDot = $('.radial > .center-dot');
$targetDiv.on('click', function() {
$(this).toggleClass('user-selected').siblings().removeClass('user-selected');
//Is it possible to refactor Line 10?
$(this).children('.radial').children().toggleClass('checked').parents('.itembox').siblings().children('.radial').children().removeClass('checked');
if ($targetDiv.is('.user-selected')) {
raceInternet = true;
} else {
raceInternet = false;
}
})
})
.itembox-container {
display: flex;
}
.boxes-2 {
width: calc((100% - 25px)/2);
margin: 10px;
padding: 10px;
}
.itembox {
position: relative;
display: inline-block;
border: 5px solid #e8e8e8;
border-radius: 10px;
cursor: pointer;
}
.user-selected {
border: 5px solid #E16E5B;
}
.itembox h4 {
color: #22ddc0;
font-weight: 700;
}
span.price {
display: inline-block;
font-weight: 400;
float: right;
color: #22ddc0;
}
.itembox > ul {
list-style: none;
}
.itembox > ul > li {
line-height: 3;
}
.radial {
position: absolute;
float: right;
height: 35px;
width: 35px;
padding: 2px;
border: 5px solid #e8e8e8;
border-radius: 50%;
top: 43%;
right: 10px;
}
.center-dot {
display: none;
position: relative;
height: 21px;
width: 21px;
background-color: #E16E5B;
border-radius: 50%;
}
.checked {
display: block;
}
.prime-aux:first-of-type {
top: 150px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="container">
<!-- Primary Content Container -->
<div class="prime-aux">
<div id="race-internet" class="itembox-container">
<div class="itembox boxes-2">
<h4>Gigabit Internet <span class="price">$60/mo</span></h4>
<ul>
<li>1,000 Mbps</li>
<li>No data caps</li>
</ul>
<div class="radial">
<div class="center-dot"></div>
</div>
</div>
<div class="itembox boxes-2">
<h4>Basic Internet <span class="price">$25/mo</span></h4>
<ul>
<li>25 Mbps</li>
<li>No data caps</li>
</ul>
<div class="radial">
<div class="center-dot"></div>
</div>
</div>
</div>
</div>
</section>
<!-- Primary Content Container End -->
View on JS Fiddle
You can eliminate a lot of your jQuery by just leveraging CSS. Typically, if I want to toggle a feature, I have it either display: block; or display: none; based upon a CSS selector. Then, I just use jQuery to toggle the parent element's class name. So for example:
.item.selected .checkmark {
display: block;
}
.item .checkmark {
display: none;
}
$('.item').click(function(){ $(this).toggleClass('selected') });
JSFiddle

Dot leaders with picture background

So I'm building a website for a restaurant and I'm in a pickle. I'm trying to create the menu there. The idea is to align the food name to the left, the price to the right and fill the gap between them with dots. Like this
Hamburger ............................................ $ 4.00
XXL Hamburger .................................... $ 4.00
Milkshake .............................................. $ 4.00
I found a couple of solutions, which only work if you have a background with one color and no texture. The idea was to fill the whole line with dots and set the name/price background span with the same color as the site background, so the dots wouldn't show. But I have a picture for the background.
I'm not going to post my code here, because it wouldn't really matter or help.
Is it even possible? Doesn't have to be css only, might as well be done with JavaScript.
I am kinda late, but you can quite easily do it with a radial-gradient:
.col {
display: inline-block;
vertical-align: top;
}
.names span {
width: 200px;
display: flex;
}
.prices span {
display: block;
text-align:right;
}
.names span:after {
content: "";
display: inline-block;
height: 1em;
flex-grow: 1;
background: radial-gradient(black 25%, transparent 25%) scroll repeat-x bottom left/5px 5px;
}
<div class='names col'>
<span>Hamburger</span>
<span>Hot Dogs</span>
<span>Superman Hamburger</span>
</div>
<div class='prices col'>
<span>$1.00</span>
<span>$0.50</span>
<span>$400.00</span>
</div>
JSFiddle Demo
It's easy to do with some simple javascript and css, here's a fiddle: jsfiddle
The key is to set the width of the div that holds the dots to the width of the column minus the width of the food name minus the width of the price, and to make sure there are more than enough dots to cover the distance, and to set overflow: hidden for the dot div.
$(".menu-row").each(function(index, element) {
var menuRowWidth = $(element).width();
var foodItemWidth = $(element).children('.food-item').width();
var priceWidth = $(element).children('.price').width();
var $dotFiller = $(element).children('.dot-filler');
var dotFillerWidth = menuRowWidth - foodItemWidth - priceWidth;
$dotFiller.width(dotFillerWidth + "px");
});
Then float the item and dot div left, the price right, all within a set width column. It's also important that overflow: hidden is set for the dots, because when we set the width of that div in javascript we want all extra dots to just be cut off. The CSS:
.food-item {
float: left
}
.dot-filler {
overflow: hidden;
width: 0;
float: left;
}
.price {
float: right;
}
.menu-row {
width: 400px;
}
Then structure your html as follows:
<div class="menu-row">
<div class="food-item">Steak</div>
<div class="dot-filler">............................................................................................</div>
<div class="price">$18.00</div>
</div>
<div class="menu-row">
<div class="food-item">Hamburger</div>
<div class="dot-filler">............................................................................................</div>
<div class="price">$8.00</div>
</div>
You can use a wrapper to set a fix width of your Name + Dots.
The css will look like this:
.wrapper {
width: 300px;
overflow: hidden;
display: inline-block;;
white-space: nowrap;
}
The HTML like this:
<div>
<ul class="noDisc">
<li>
<div class="wrapper">
<span>HAMBURGER </span>
<span>...............................................................</span>
</div>
<span>$ 40.00</span>
</li>
<li>
<div class="wrapper">
<span>FRIED CHIKEN </span>
<span>...............................................................</span>
</div>
<span>$ 13.00</span>
</li>
<li>
<div class="wrapper">
<span>STEAK ON A STICK </span>
<span>...............................................................</span>
</div>
<span>$ 99.00</span>
</li>
</ul>
</div>
Live sample:
fiddle
Use display:table; and display: table-cell; for the divs inside the list-elements and border-bottom: Xpx dotted black; for the dots.
ul{
margin: 0;
padding: 0;
}
ul li{
display: table;
width: 100%;
}
ul li div {
display: table-cell;
}
ul li div.food {
padding-right: 5px;
}
ul li div.dots {
border-bottom: 1px dotted #000;
width: 100%;
position: relative;
top: -4px;
}
ul li div.price {
padding-left: 5px;
}
<ul>
<li>
<div class="food">Spaghetti</div>
<div class="dots"> </div>
<div class="price">10.00$</div>
</li>
<li>
<div class="food">Spaghetti</div>
<div class="dots"></div>
<div class="price">10.00$</div>
</li>
<li>
<div class="food">Spaghetti</div>
<div class="dots"></div>
<div class="price">10.00$</div>
</li>
</ul>
Thanks. I used what you had here and improved on it. This code is meant for woocommerce product items, but can be edited for whatever you need. $containerElement is the element you are measuring the width of.
/**
* dotFiller
* adds dynamic dot leaders between product title and count element (<mark>)
* #return void
*/
var dotFiller = function(){
var $containerElement = $('ul.products li.product.has-children h2'),
df = '<div class="df">.....................................................................</div>';
$containerElement.each(function(i,el){
var $el = $(el),
w = $el.width(),
mw = $el.find('mark').width(),
tw = $el.find('span').width(),
dfw = (w - mw - tw) - 24;
// if its not there, lets add it
if (!$(el).has('.df').length){
$el.find('span').after(df);
}
$el.find('.df').css('width',dfw + "px");
});
};
dotFiller();
With this code, you can update/ recalculate on resize like so :
$('window').on('resize',function(){ dotFiller(); });
And here is my css for the internal elements:
mark {
background-color: transparent;
color: $secondary;
display: inline-block; float: right;
font-weight: normal;
}
div.df {
overflow: hidden;
display: inline-block;
margin-left: 10px;
position: relative;
top: 2px;
font-weight: normal;
opacity: 0.8;
}
I hope this helps someone!
Use a div that has a flex spacer with a border-bottom to achieve easy leader dots... The flex layout seems to be the most elegant solution. No pseudo-elements, or left and right block display, etc... Very simple...
HTML
<div class="list-item">
<div class="header-row">
<h4>Menu</h4>
</div>
<br>
<div class="list-item-row">
<div class="left">Hamburger</div>
<div class="dots"></div>
<div class="right">$5.00</div>
</div>
<div class="list-item-row">
<div class="left">Hamburger (XXL)</div>
<div class="dots"></div>
<div class="right">$7.50</div>
</div>
<div class="list-item-row">
<div class="left">Milkshake</div>
<div class="dots"></div>
<div class="right">$3.50</div>
</div>
<div class="list-item-row">
<div class="left">Pickle</div>
<div class="dots"></div>
<div class="right">Free</div>
</div>
</div>
CSS
#import url("https://fonts.googleapis.com/css?family=Lato|Montserrat:400,700|Roboto:400,700");
* {
margin: 0;
padding: 0;
}
button {
font-family: "Roboto";
font-size: 16px;
padding: 5px;
border-radius: 3px;
border: solid #424242 1px;
}
.list-item {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
margin: 20px;
font-family: "Lato";
background: #f0f0f0;
padding: 10px;
border: solid #e0e0e0 1px;
}
.list-item-row,
.header-row {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
.left,
.right {
font-family: "Roboto";
}
.right {
color: blue;
}
}
.dots {
flex: 1 0 0;
border-bottom: dotted 2px #b0b0b0;
margin-left: 1em;
margin-right: 1em;
}
See Codepen here => https://codepen.io/anon/pen/vVZmxB

Categories