I'm trying to create an hover event in an element with a nested a icon.
The problem is when the cursor touch the <i class="material-icons fav icons lov-icon lov-icon-color"> favorite</i> element because that tigger the event mouseout
How to keep the same event in a nested element ?
$(".fav-btn").mouseout((event) => {
let favButton = $(event.currentTarget);
let favIcon = $(event.currentTarget.children[0]);
console.log(favButton);
if (favButton.hasClass('fav-btn-selected') && favIcon.hasClass('lov-icon-color-selected')) {
favButton.removeClass('fav-btn-selected');
favIcon.removeClass('lov-icon-color-selected');
favButton.addClass('fav-btn');
favIcon.addClass('lov-icon-color');
}
});
$(".fav-btn").mouseenter((event) => {
let favButton = $(event.currentTarget);
let favIcon = $(event.currentTarget.children[0]);
console.log(favIcon);
if (favButton.hasClass('fav-btn') && favIcon.hasClass('lov-icon-color')) {
favButton.removeClass('fav-btn');
favIcon.removeClass('lov-icon-color');
favButton.addClass('fav-btn-selected');
favIcon.addClass('lov-icon-color-selected');
}
});
https://jsfiddle.net/4mLnckaw/3/
Since you're using jQuery, you can also use hover and toggleClass to do so.
Here's a demo:
$(".fav-btn").hover((event => {
let favButton = $(event.currentTarget);
let favIcon = $(event.currentTarget.children[0]);
favButton.toggleClass('fav-btn fav-btn-selected');
favIcon.toggleClass('lov-icon-color lov-icon-color-selected');
}));
.circle {
display: inline-block;
text-align: center;
width: 70px;
height: 70px;
-moz-border-radius: 50% !important;
-webkit-border-radius: 50% !important;
border-radius: 50%;
-webkit-box-shadow: -2px 3px 10px 0px rgba(0, 0, 0, 0.75);
-moz-box-shadow: -2px 3px 10px 0px rgba(0, 0, 0, 0.75);
box-shadow: -2px 3px 10px 0px rgba(0, 0, 0, 0.75);
}
.circle>.icons {
position: relative;
top: calc(50% - 10px);
/* 50% - 3/4 of icon height */
}
.fav-btn {
background-color: #FFFFFF;
}
.msg-btn {
background-color: #FFFFFF;
}
.lov-icon {
font-size: 25px;
}
.msg-icon {
font-size: 25px;
}
.lov-icon-color {
color: red;
}
.msg-icon-color {
color: green;
}
.fav-btn-selected {
background-color: #b61825;
}
.msg-btn-selected {
background-color: green;
}
.lov-icon-color-selected {
color: #FFFFFF;
}
.msg-icon-color-selected {
color: #FFFFFF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<a href="">
<div class="circle fav fav-btn m-2">
<i class="material-icons fav icons lov-icon lov-icon-color">favorite</i>
</div>
</a>
Use mouseenter and mouseleave events instead.
mouseleave and mouseout are similar but differ in that mouseleave does
not bubble and mouseout does. This means that mouseleave is fired when
the pointer has exited the element and all of its descendants, whereas
mouseout is fired when the pointer leaves the element or leaves one of
the element's descendants (even if the pointer is still within the
element).
const applyMouseEnterStlye = (button, icon) => {
button.removeClass('fav-btn');
button.addClass('fav-btn-selected');
icon.removeClass('lov-icon-color');
icon.addClass('lov-icon-color-selected');
};
const applyMouseLeaveStlye = (button, icon) => {
button.removeClass('fav-btn-selected');
button.addClass('fav-btn');
icon.removeClass('lov-icon-color-selected');
icon.addClass('lov-icon-color');
};
const toggleStyles = event => {
const button = $(event.target);
const icon = $(button.find('i'));
switch (event.type) {
case 'mouseenter':
applyMouseEnterStlye(button, icon);
break;
case 'mouseleave':
applyMouseLeaveStlye(button, icon);
break;
}
}
const circleEl = document.querySelector('.circle');
circleEl.addEventListener('mouseenter', toggleStyles);
circleEl.addEventListener('mouseleave', toggleStyles);
.circle {
display: inline-block;
text-align: center;
width: 70px;
height: 70px;
-moz-border-radius: 50% !important;
-webkit-border-radius: 50% !important;
border-radius: 50%;
-webkit-box-shadow: -2px 3px 10px 0px rgba(0, 0, 0, 0.75);
-moz-box-shadow: -2px 3px 10px 0px rgba(0, 0, 0, 0.75);
box-shadow: -2px 3px 10px 0px rgba(0, 0, 0, 0.75);
}
.circle>.icons {
position: relative;
top: calc(50% - 10px);
/* 50% - 3/4 of icon height */
}
.fav-btn {
background-color: #FFFFFF;
}
.msg-btn {
background-color: #FFFFFF;
}
.lov-icon {
font-size: 25px;
}
.msg-icon {
font-size: 25px;
}
.lov-icon-color {
color: red;
}
.msg-icon-color {
color: green;
}
.fav-btn-selected {
background-color: #b61825;
}
.msg-btn-selected {
background-color: green;
}
.lov-icon-color-selected {
color: #FFFFFF;
}
.msg-icon-color-selected {
color: #FFFFFF;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<a href="">
<div class="circle fav fav-btn m-2">
<i class="material-icons fav icons lov-icon lov-icon-color">favorite</i>
</div>
</a>
Related
I am working on a meme generator project, it's to practice DOM manipulation. So, I'm supposed to use vanilla JavaScript and no canvas. I'm having trouble finding answer with these parameters. I am almost done with the project, I just need to add text to the picture that they submitted.
I have tried using innerText and innerHTML they seem to just replace it. I've tried append child, similar to how I got the appendchild with the image, but I either get an error or replace the image.
I was pretty sure that I needed to add it add the picture with JavaScript then style it with CSS. Maybe just add a class with classList.
console.log('Currentfile: memegenerator');
let img = document.getElementsByTagName('img');
addEventListener('submit', function(e) {
e.preventDefault();
let UIurl = document.getElementById('picurl');
let memeToBe = UIurl.value;
let img = document.createElement('img');
img.setAttribute('src', memeToBe);
img.setAttribute('class', 'meme');
// append to the document with set attribute using said variable
let memeLocation = document.getElementById('location');
memeLocation.appendChild(img);
//url for pic test
//https://www.fillmurray.com/640/360
//add text to image
//get text values
let inputText = document.getElementById('text_top');
let textValue = inputText.value;
addEventListener('click', function(e) {
let clickedElement = e.target;
console.log(clickedElement);
let targetCheck = clickedElement.classList.contains("meme");
if (targetCheck) {
clickedElement.remove();
}
})
h1 {
color: navy;
}
.center {
text-align: center;
}
.main {
width: 50%;
margin: 0 auto;
background-color: lightblue;
border-radius: 0.5rem;
border: 0.08rem solid black;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
.meme {
width: 99%;
/* margin: 2 auto; */
justify-content: center;
background-color: lightblue;
border-radius: 0.5rem;
border: 0.08rem solid black;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
main:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}
meme:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}
body {
background-color: #f0feff;
}
.button {
float: right;
}
/* divider styles */
hr.rounded {
border-top: 2px solid #bbb;
border-radius: 5px;
width: 90%;
}
.border_lower {
border-bottom: 1px solid #bbb;
border-radius: 5px;
width: 90%;
}
/* form styles */
form {
width: 60%;
margin: 0 auto;
}
form input {
margin: 2px;
}
form label {
margin: 2px;
}
/* Container holding the image and the text */
.container {
position: relative;
text-align: center;
color: white;
}
/* Bottom left text */
.bottom-left {
position: absolute;
bottom: 8px;
left: 16px;
}
/* Top left text */
.location {
position: absolute;
top: 8px;
left: 16px;
}
<main class="main">
<h1 class="center">MEME GENERATOR!</h1>
<hr class="rounded" />
<form action="#" class="form">
<label for="text_top">Text Upper:</label>
<input type="text" name="text_top" id="text_top" /><br />
<label for="text_lower">Text Lower:</label>
<input type="text" name="text_lower" id="text_lower" /><br />
<label for="picturl">Picture:</label>
<input type="url" name="picurl" id="picurl" /><br /><br /><br />
<input class="button " type="submit" value="Add Meme:" /><br />
<hr />
</form>
<div id="location"></div>
<hr class="border_lower" />
<p class="center"><small>Thanks for visiting!</small></p>
</main>
Since this isn't about saving the images but just for display purposes, I got it working.
The main problem that you were having is your approach seemed to focus more on the javascript side of things but missed out on the CSS part of it.
There are multiple ways to put images behind text, the most common two are:
Setting the images as a background image on the parent element (ie div) then just setting the text within that element
Using CSS to absolute position the text on the image and use z-index to layer them
For my answer I chose #2.
Besides misc code clean ups, the main function that I did was:
I created a div, and gave it a class of meme
I added the image to that div
I added the top and bottom text to their own divs and append those to the meme div
Using CSS, I positioned the top and bottom text above the image
A few other things, when adding an eventListeners unless it is absolutely needed, I recommend tying them to a specific element and not just the document (or nothing at all which I believe is document anyway). By applying it to the document, any click will be processed, but by tying it to the element, only clicks on that element will be processed.
console.log('Currentfile: memegenerator');
let img = document.getElementsByTagName('img');
let form = document.querySelector('form');
form.addEventListener('submit', function(e) {
e.preventDefault();
let meme = document.createElement("div");
let top_text = document.createElement("div");
let bottom_text = document.createElement("div");
let img = document.createElement("img");
let btn = document.createElement("button");
btn.setAttribute("type","button");
img.src = document.getElementById('picurl').value;
top_text.classList.add("top_text");
top_text.innerHTML = document.getElementById('text_top').value;
bottom_text.classList.add("bottom_text");
bottom_text.innerHTML = document.getElementById('text_lower').value;
btn.innerHTML = "REMOVE";
meme.classList.add("meme");
meme.appendChild(top_text);
meme.appendChild(bottom_text);
meme.appendChild(img);
meme.appendChild(btn);
let memeLocation = document.getElementById('location');
memeLocation.appendChild(meme);
document.getElementById('picurl').value = "";
document.getElementById('text_top').value = "";
document.getElementById('text_lower').value = "";
btn.addEventListener('click', function(e) {
meme.remove();
})
});
h1 {
color: navy;
}
.center {
text-align: center;
}
.main {
width: 50%;
margin: 0 auto;
background-color: lightblue;
border-radius: 0.5rem;
border: 0.08rem solid black;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
.meme {
width: 99%;
/* margin: 2 auto; */
justify-content: center;
border-radius: 0.5rem;
border: 0.08rem solid black;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
position:relative;
}
.top_text{
position:absolute;
top:10px;
left:30px;
color:#ffffff;
z-index:3
}
.bottom_text{
position:absolute;
bottom:20px;
left:30px;
color:#ffffff;
z-index:3
}
.meme img{
max-width:100%;
z-index:2
}
main:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}
meme:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}
body {
background-color: #f0feff;
}
.button {
float: right;
}
/* divider styles */
hr.rounded {
border-top: 2px solid #bbb;
border-radius: 5px;
width: 90%;
}
.border_lower {
border-bottom: 1px solid #bbb;
border-radius: 5px;
width: 90%;
}
/* form styles */
form {
width: 60%;
margin: 0 auto;
}
form input {
margin: 2px;
}
form label {
margin: 2px;
}
/* Container holding the image and the text */
.container {
position: relative;
text-align: center;
color: white;
}
/* Bottom left text */
.bottom-left {
position: absolute;
bottom: 8px;
left: 16px;
}
/* Top left text */
.location {
position: absolute;
top: 8px;
left: 16px;
}
<main class="main">
<h1 class="center">MEME GENERATOR!</h1>
<hr class="rounded" />
<form action="#" class="form">
<label for="text_top">Text Upper:</label>
<input type="text" name="text_top" id="text_top" /><br />
<label for="text_lower">Text Lower:</label>
<input type="text" name="text_lower" id="text_lower" /><br />
<label for="picturl">Picture:</label>
<input type="url" name="picurl" value="https://www.fillmurray.com/640/360" id="picurl" /><br /><br /><br />
<input type="submit" value="Add Meme:" /><br />
<hr />
</form>
<div id="location"></div>
<hr class="border_lower" />
<p class="center"><small>Thanks for visiting!</small></p>
</main>
https://codepen.io/matthewbert86/pen/pogdEvB
http://beer-food.surge.sh/
I am working on a little search app. It pulls up the beer pairing results based on what food you type in. My problem is that after I get results once, it wont clear out, and the same results stay up for anything I try to enter after that. Ive been messing with it for a long time and no luck. Any suggestions?
// Step 1 - assign elements from HTML and assign it to javascript variables
const btnSearch = document.getElementById('btnSearch');
const txtSearch = document.getElementById('food');
const resultArea = document.getElementById('result');
// This is where we will store out output as its process
let out = "";
// an onclick function runs when the button is clicked
btnSearch.onclick = function() {
// this returns the user input from the searchbar
var searchTerm = txtSearch.value;
const url = `https://api.punkapi.com/v2/beers?food=${searchTerm}`
console.log(url);
// fetch will go to the url
fetch(url)
.then(function(data) {
// return jsonObject from the url
return data.json();
})
.then(function(jsonObject) {
console.log(jsonObject);
for (beer in jsonObject) {
const beerInfo = new Array(jsonObject[beer].name, jsonObject[beer].tagline, jsonObject[beer].description, jsonObject[beer].image_url)
beerOut(beerInfo);
}
resultArea.innerHTML = out;
})
.catch(function(e) {
console.log("Error: " + e);
});
}
// This function we will use logic to take the array from beerOut and display it in HTML using template literals
function beerOut(beer) {
console.log(beer);
out += `<div class="beer">
<div class="beerImage"><img src="${beer[3]}"/></div>
<div class="beerText">
<h2>${beer[0]}</h2>
<h3>${beer[1]}</h3>
<p><em>${beer[2]}</em></p>
</div><!--beerText-->
</div><!--beer-->
`
//This will go back to the resultArea.innerHTML = out; to display on the main page
}
#food {
width: 50%;
margin: 0 25%;
border: 3px solid black;
border-radius: 5px;
background-color: white;
-webkit-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
display: flex;
text-align: center;
}
.text-input,
.text-input--underbar {
font: inherit;
vertical-align: top;
-moz-osx-font-smoothing: grayscale;
letter-spacing: 0;
box-shadow: none;
padding: 20px;
width: auto;
height: 31px;
border: none;
margin: 0;
outline: 0;
}
#container {
margin: 5px;
}
#btnSearch {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
font-size: 30px;
padding: 10px 10px;
text-align: center;
margin: 0 auto;
}
.beer {
border: 1px solid black;
margin: 5px;
margin-bottom: 15px;
padding: 10px;
border-radius: 5px;
background-color: white;
-webkit-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
display: flex;
justify-content: space-between;
}
.beerImage {
padding: 30px;
width: 50px;
/*order: 1;*/
}
.beerImage img {
width: 60px;
}
.beerText {
width: 85%;
padding: 20px;
}
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.css">
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
<script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<ons-page>
<ons-toolbar>
<div class="center">Beer & Food Pairings</div>
</ons-toolbar>
<section id="container">
<p>
<ons-input id="food" modifier="underbar" placeholder="enter a food to pair">
</ons-input>
</p>
<p>
<ons-button modifier="medium" id="btnSearch">Search</ons-button>
</p>
<div id="result"></div>
</section>
</ons-page>
You saved the out
Here I clear the potential containers and add a random to the url to make sure it is not cached
btnSearch.onclick = function() {
out = "";
I search for "ale" and get result and "lager" and get none
// Step 1 - assign elements from HTML and assign it to javascript variables
const btnSearch = document.getElementById('btnSearch');
const txtSearch = document.getElementById('food');
const resultArea = document.getElementById('result');
// This is where we will store out output as its process
let out = "";
// an onclick function runs when the button is clicked
btnSearch.onclick = function() {
out = "";
resultArea.innerHTML = "Please wait...";
jsonObject = ""
// this returns the user input from the searchbar
var searchTerm = txtSearch.value;
const url = `https://api.punkapi.com/v2/beers?food=${searchTerm}&rdn=${new Date().getTime()}`
console.log(url);
// fetch will go to the url
fetch(url)
.then(function(data) {
// return jsonObject from the url
return data.json();
})
.then(function(jsonObject) {
console.log(jsonObject);
for (beer in jsonObject) {
const beerInfo = new Array(jsonObject[beer].name, jsonObject[beer].tagline, jsonObject[beer].description, jsonObject[beer].image_url)
beerOut(beerInfo);
}
resultArea.innerHTML = out;
})
.catch(function(e) {
console.log("Error: " + e);
});
}
// This function we will use logic to take the array from beerOut and display it in HTML using template literals
function beerOut(beer) {
console.log(beer);
out += `<div class="beer">
<div class="beerImage"><img src="${beer[3]}"/></div>
<div class="beerText">
<h2>${beer[0]}</h2>
<h3>${beer[1]}</h3>
<p><em>${beer[2]}</em></p>
</div><!--beerText-->
</div><!--beer-->
`
//This will go back to the resultArea.innerHTML = out; to display on the main page
}
#food {
width: 50%;
margin: 0 25%;
border: 3px solid black;
border-radius: 5px;
background-color: white;
-webkit-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
display: flex;
text-align: center;
}
.text-input,
.text-input--underbar {
font: inherit;
vertical-align: top;
-moz-osx-font-smoothing: grayscale;
letter-spacing: 0;
box-shadow: none;
padding: 20px;
width: auto;
height: 31px;
border: none;
margin: 0;
outline: 0;
}
#container {
margin: 5px;
}
#btnSearch {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
font-size: 30px;
padding: 10px 10px;
text-align: center;
margin: 0 auto;
}
.beer {
border: 1px solid black;
margin: 5px;
margin-bottom: 15px;
padding: 10px;
border-radius: 5px;
background-color: white;
-webkit-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
display: flex;
justify-content: space-between;
}
.beerImage {
padding: 30px;
width: 50px;
/*order: 1;*/
}
.beerImage img {
width: 60px;
}
.beerText {
width: 85%;
padding: 20px;
}
<!doctype html>
<html>
<head>
<title>Search</title>
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.css">
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
<script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
</head>
<body>
<ons-page>
<ons-toolbar>
<div class="center">Beer & Food Pairings</div>
</ons-toolbar>
<section id="container">
<p>
<ons-input id="food" modifier="underbar" placeholder="enter a food to pair">
</ons-input>
</p>
<p>
<ons-button modifier="medium" id="btnSearch">Search</ons-button>
</p>
<div id="result"></div>
</section>
</ons-page>
Simpler version - I fixed your missing image
function beerOut(jsonObject) {
return jsonObject.map(item => {
const {name, tagline, description, image_url} = item;
return `<div class="beer">
<div class="beerImage"><img src="${image_url || 'https://i.ya-webdesign.com/images/wine-bottle-silhouette-png-14.png'}"/></div>
<div class="beerText">
<h2>${name}</h2>
<h3>${tagline}</h3>
<p><em>${description}</em></p>
</div><!--beerText-->
</div><!--beer-->
`;
})
}
// Step 1 - assign elements from HTML and assign it to javascript variables
const btnSearch = document.getElementById('btnSearch');
const txtSearch = document.getElementById('food');
const resultArea = document.getElementById('result');
// This is where we will store out output as its process
// an onclick function runs when the button is clicked
btnSearch.addEventListener("click",function() {
resultArea.innerHTML = "Please wait...";
// this returns the user input from the searchbar
var searchTerm = txtSearch.value;
const url = `https://api.punkapi.com/v2/beers?food=${searchTerm}&rdn=${new Date().getTime()}`;
console.log(url);
// fetch will go to the url
fetch(url)
.then(function(data) {
return data.json();
})
.then(function(jsonObject) {
resultArea.innerHTML = beerOut(jsonObject);
})
.catch(function(e) {
console.log("Error: " + e);
});
})
// This function we will use logic to take the array from beerOut and display it in HTML using template literals
function beerOut(jsonObject) {
return jsonObject.map(item => {
const {name, tagline, description, image_url} = item;
return `<div class="beer">
<div class="beerImage"><img src="${image_url || 'https://i.ya-webdesign.com/images/wine-bottle-silhouette-png-14.png'}"/></div>
<div class="beerText">
<h2>${name}</h2>
<h3>${tagline}</h3>
<p><em>${description}</em></p>
</div><!--beerText-->
</div><!--beer-->
`;
})
}
#food {
width: 50%;
margin: 0 25%;
border: 3px solid black;
border-radius: 5px;
background-color: white;
-webkit-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
display: flex;
text-align: center;
}
.text-input,
.text-input--underbar {
font: inherit;
vertical-align: top;
-moz-osx-font-smoothing: grayscale;
letter-spacing: 0;
box-shadow: none;
padding: 20px;
width: auto;
height: 31px;
border: none;
margin: 0;
outline: 0;
}
#container {
margin: 5px;
}
#btnSearch {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
font-size: 30px;
padding: 10px 10px;
text-align: center;
margin: 0 auto;
}
.beer {
border: 1px solid black;
margin: 5px;
margin-bottom: 15px;
padding: 10px;
border-radius: 5px;
background-color: white;
-webkit-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
box-shadow: 10px 13px 30px -19px rgba(0, 0, 0, 0.5);
display: flex;
justify-content: space-between;
}
.beerImage {
padding: 30px;
width: 50px;
/*order: 1;*/
}
.beerImage img {
width: 60px;
}
.beerText {
width: 85%;
padding: 20px;
}
<!doctype html>
<html>
<head>
<title>Search</title>
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsenui.css">
<link rel="stylesheet" href="https://unpkg.com/onsenui/css/onsen-css-components.min.css">
<script src="https://unpkg.com/onsenui/js/onsenui.min.js"></script>
</head>
<body>
<ons-page>
<ons-toolbar>
<div class="center">Beer & Food Pairings</div>
</ons-toolbar>
<section id="container">
<p>
<ons-input id="food" modifier="underbar" placeholder="enter a food to pair">
</ons-input>
</p>
<p>
<ons-button modifier="medium" id="btnSearch">Search</ons-button>
</p>
<div id="result"></div>
</section>
</ons-page>
I'm trying to be able to search for text inside the listed tasks and display right away as soon as a user types in the input box. I got a snippet of code from w3schools and tried to work it into my current JS file but can't seem to get it to work. Perhaps someone can get me on the right track and tell me what I did wrong.
//Define UI Variables
const form = document.querySelector('#task-form');
const taskList = document.querySelector('.task-list');
const clearTaskButton = document.querySelector('.clear-tasks-btn');
const taskFilter = document.querySelector('#task-filter');
const inputBox = document.querySelector('#input-box');
const addTaskButton = document.querySelector('.add-task-btn');
// Load event listeners
loadEventListeners();
// Function to load event listeners
function loadEventListeners() {
form.addEventListener('submit', addTask);
taskList.addEventListener('click', removeTask);
clearTaskButton.addEventListener('click', clearTasks);
taskFilter.addEventListener('oninput', filterTasks);
}
//Add Task
function addTask(e) {
if (inputBox.value === '') {
alert('Please add a task!');
}
//Create li element
const liTag = document.createElement('li');
liTag.className = 'task-item';
//Append input from input box into li element
liTag.appendChild(document.createTextNode(inputBox.value));
// Create new link element with a class of "delete-item"
const linkTag = document.createElement('a');
linkTag.className = 'delete-item';
// Add icon HTML
linkTag.innerHTML = '<i class="fas fa-times"></i>';
// Append link to li
liTag.appendChild(linkTag);
// Append li to ul
taskList.appendChild(liTag);
// Clear input
inputBox.value = '';
e.preventDefault();
}
//Remove Tasks
function removeTask(e) {
if (e.target.parentElement.classList.contains('delete-item')) {
e.target.parentNode.parentNode.remove();
}
}
//Clear Tasks
function clearTasks(e) {
//Alert if there are no tasks (li) inside the task list (ul)
if (taskList.childNodes.length < 1) {
alert('No tasks to clear!');
}
else {
taskList.innerHTML = '';
}
}
//Filter Tasks
function filterTasks(e) {
var filter, liTag, a, i, txtValue;
filter = taskFilter.value.toUpperCase();
liTag = taskList.getElementsByTagName('li');
for (i = 0; i < liTag.length; i++) {
a = liTag[i].getElementsByTagName("a")[0];
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
liTag[i].style.display = "";
} else {
liTag[i].style.display = "none";
}
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Lato', sans-serif;
}
/* ====HEADING==== */
h1 {
font-size: 1.2rem;
font-weight: 400;
margin-bottom: 20px;
text-transform: uppercase;
letter-spacing: 4px;
}
h2 {
font-size: 1.2rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 4px;
margin-bottom: 5px;
}
h3 {
font-size: 14px;
font-weight: 400;
color: #808080;
margin-bottom: 10px;
}
.grid {
display: flex;
flex-direction: column;
margin-top: 10px;
}
.add-task,
.tasks {
width: 75%;
padding: 15px 15px;
}
/* Styles for smaller screens BEGIN */
#media only screen and (max-width: 600px) {
.add-task,
.tasks {
width: 90%;
}
}
/* Styles for smaller screens END */
.add-task,
.tasks {
margin: auto;
border: 0.5px solid #E6E6E6;
-webkit-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
-moz-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
margin-bottom: 20px;
}
#input-box,
#task-filter {
margin-bottom: 20px;
width: 100%;
background: transparent;
border: none;
border-bottom: 1px solid #9E9E9E;
}
::-webkit-input-placeholder { /* WebKit, Blink, Edge */
color: black;
}
/* ====BUTTONS==== */
.add-task-btn,
.clear-tasks-btn {
padding: 10px 20px;
border: 0;
color: white;
text-transform: uppercase;
text-decoration: none;
font-size: 1rem;
}
.add-task-btn {
background: #00A081;
border: 0px solid #000000;
-webkit-appearance: none;
}
.clear-tasks-btn {
background: black;
}
/* ====LIST OF TASKS==== */
.tasks {
background: white;
margin: 10px auto;
padding-bottom: 20px;
-webkit-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
-moz-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
}
.task-list {
list-style-type: none;
width: 100%;
margin-bottom: 20px;
}
.task-list li {
border: 1px solid #E0E0E0;
padding: 10px 20px 10px 20px;
display: flex;
justify-content: space-between;
}
/* ===REMOVE TOP BORDER OF SECOND - FIFTH LI */
.task-list li:nth-child(n+2):nth-child(-n+5) {
border-top: 0px;
}
/* ===ICONS=== */
.fas:hover {
color: #26A69A;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Task List</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP"
crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Lato:400,700" rel="stylesheet">
<link rel="stylesheet" href="assets/css/tasklist.css" </head> <body>
<div class="grid">
<div class="add-task">
<h1>Task List</h1>
<form id="task-form">
<label for="input">New Task</label>
<input type="text" name="input" id="input-box">
<input type="submit" value="Add Task" class="add-task-btn">
</form>
</div>
<div class="tasks">
<h2>Tasks</h2>
<form id="insert-form">
<input type="text" name="insert" placeholder="Search for tasks.." id="task-filter">
</form>
<ul class="task-list"></ul>
Clear Tasks
</div>
</div>
<script src="assets/js/tasklist.js"></script>
</body>
</html>
Just replace this code taskFilter.addEventListener('oninput', filterTasks);
to this one taskFilter.addEventListener('keyup', filterTasks);, please do refer here for the list of available events for DOM in Javascript.
The event name is "input", not "oninput".
Also your filter is wrong, the text is inside the <li> instead of <a>.
you can check the event name list here https://developer.mozilla.org/en-US/docs/Web/Events
//Define UI Variables
const form = document.querySelector('#task-form');
const taskList = document.querySelector('.task-list');
const clearTaskButton = document.querySelector('.clear-tasks-btn');
const taskFilter = document.querySelector('#task-filter');
const inputBox = document.querySelector('#input-box');
const addTaskButton = document.querySelector('.add-task-btn');
// Load event listeners
loadEventListeners();
// Function to load event listeners
function loadEventListeners() {
form.addEventListener('submit', addTask);
taskList.addEventListener('click', removeTask);
clearTaskButton.addEventListener('click', clearTasks);
taskFilter.addEventListener('input', filterTasks);
}
//Add Task
function addTask(e) {
if (inputBox.value === '') {
alert('Please add a task!');
}
//Create li element
const liTag = document.createElement('li');
liTag.className = 'task-item';
//Append input from input box into li element
liTag.appendChild(document.createTextNode(inputBox.value));
// Create new link element with a class of "delete-item"
const linkTag = document.createElement('a');
linkTag.className = 'delete-item';
// Add icon HTML
linkTag.innerHTML = '<i class="fas fa-times"></i>';
// Append link to li
liTag.appendChild(linkTag);
// Append li to ul
taskList.appendChild(liTag);
// Clear input
inputBox.value = '';
e.preventDefault();
}
//Remove Tasks
function removeTask(e) {
if (e.target.parentElement.classList.contains('delete-item')) {
e.target.parentNode.parentNode.remove();
}
}
//Clear Tasks
function clearTasks(e) {
//Alert if there are no tasks (li) inside the task list (ul)
if (taskList.childNodes.length < 1) {
alert('No tasks to clear!');
}
else {
taskList.innerHTML = '';
}
}
//Filter Tasks
function filterTasks(e) {
var filter, liTag, a, i, txtValue;
filter = taskFilter.value.toUpperCase();
liTag = taskList.getElementsByTagName('li');
for (i = 0; i < liTag.length; i++) {
txtValue = liTag[i].textContent || liTag[i].innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
liTag[i].style.display = "";
} else {
liTag[i].style.display = "none";
}
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Lato', sans-serif;
}
/* ====HEADING==== */
h1 {
font-size: 1.2rem;
font-weight: 400;
margin-bottom: 20px;
text-transform: uppercase;
letter-spacing: 4px;
}
h2 {
font-size: 1.2rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 4px;
margin-bottom: 5px;
}
h3 {
font-size: 14px;
font-weight: 400;
color: #808080;
margin-bottom: 10px;
}
.grid {
display: flex;
flex-direction: column;
margin-top: 10px;
}
.add-task,
.tasks {
width: 75%;
padding: 15px 15px;
}
/* Styles for smaller screens BEGIN */
#media only screen and (max-width: 600px) {
.add-task,
.tasks {
width: 90%;
}
}
/* Styles for smaller screens END */
.add-task,
.tasks {
margin: auto;
border: 0.5px solid #E6E6E6;
-webkit-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
-moz-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
margin-bottom: 20px;
}
#input-box,
#task-filter {
margin-bottom: 20px;
width: 100%;
background: transparent;
border: none;
border-bottom: 1px solid #9E9E9E;
}
::-webkit-input-placeholder { /* WebKit, Blink, Edge */
color: black;
}
/* ====BUTTONS==== */
.add-task-btn,
.clear-tasks-btn {
padding: 10px 20px;
border: 0;
color: white;
text-transform: uppercase;
text-decoration: none;
font-size: 1rem;
}
.add-task-btn {
background: #00A081;
border: 0px solid #000000;
-webkit-appearance: none;
}
.clear-tasks-btn {
background: black;
}
/* ====LIST OF TASKS==== */
.tasks {
background: white;
margin: 10px auto;
padding-bottom: 20px;
-webkit-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
-moz-box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.15);
}
.task-list {
list-style-type: none;
width: 100%;
margin-bottom: 20px;
}
.task-list li {
border: 1px solid #E0E0E0;
padding: 10px 20px 10px 20px;
display: flex;
justify-content: space-between;
}
/* ===REMOVE TOP BORDER OF SECOND - FIFTH LI */
.task-list li:nth-child(n+2):nth-child(-n+5) {
border-top: 0px;
}
/* ===ICONS=== */
.fas:hover {
color: #26A69A;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Task List</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP"
crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css?family=Lato:400,700" rel="stylesheet">
<link rel="stylesheet" href="assets/css/tasklist.css" </head> <body>
<div class="grid">
<div class="add-task">
<h1>Task List</h1>
<form id="task-form">
<label for="input">New Task</label>
<input type="text" name="input" id="input-box">
<input type="submit" value="Add Task" class="add-task-btn">
</form>
</div>
<div class="tasks">
<h2>Tasks</h2>
<form id="insert-form">
<input type="text" name="insert" placeholder="Search for tasks.." id="task-filter">
</form>
<ul class="task-list"></ul>
Clear Tasks
</div>
</div>
<script src="assets/js/tasklist.js"></script>
</body>
</html>
I made a form control which uses as its container (see the Yes/No toggler below)
Here's the code for that:
<span class="toggle">
<i>Yes</i>
<i>No</i>
<input type="hidden" name="toggle-value" value="0">
</span>
My CSS isn't relevant to the question, but it's included for comprehension of my control:
.toggle { width:auto; height: 20px; display: inline-block; position: relative; cursor: pointer; vertical-align: middle; padding: 0; margin-right: 27px; color: white !important;}
.toggle i { display: block; padding: 0 12px; width: 100%; height: 100%; -webkit-border-radius: 12px; -moz-border-radius: 12px; border-radius: 12px; text-align: center; font: 11px/20px Arial !important; text-transform: uppercase; }
.toggle i:first-child { -moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) inset; box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5) inset; background-color: #73B9FF; }
.toggle i:last-child { -moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5) inset; box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5) inset; background-color: #cc0000; position: relative; top: -20px; z-index: -1; }
.toggle.on i:first-child { z-index: 1; } /* they overlap but on click they switch who gets to be on top. */
.toggle.on i:last-child { z-index: -1; }
.toggle.off i:first-child { z-index: -1; }
.toggle.off i:last-child { z-index: 1; }
.toggle.off i:last-child:before { content: " "; display:block; position:absolute; left:1px; top:1px; text-indent: -9999px; width: 18px; height: 18px; -webkit-border-radius: 11px; -moz-border-radius: 11px; border-radius: 11px; z-index: 1; background-color: #fff; } /* circle */
.toggle.on i:first-child:after { content: " "; display:block; position:absolute; right:-23px; top:1px; text-indent: -9999px; width: 18px; height: 18px; -webkit-border-radius: 11px; -moz-border-radius: 11px; border-radius: 11px; z-index: 1; background-color: #fff; } /* circle */
and the JS that makes it all work:
.on('click', '.toggle', function(){
var input = $(this).next('input');
if(input.val() == 1) {
$(this).removeClass('on').addClass('off');
input.val(0).change();
} else {
$(this).removeClass('off').addClass('on');
input.val(1).change();
}
}
The problem is that I'm using this all over my application for data-entry. Have you ever wanted to NOT use the mouse when you're entering a lot of data? Yeah, me too. So you hit TAB and a toggle like this should respond to the spacebar. But instead, since it's just a element, it is skipped altogether.
I'm hoping someone can help me solve the question of "how the heck do I make this a tab stop AND be in the correct order"?
==============
EDIT: HERE IS MY UPDATED JQUERY CODE CONTAINING THE SOLUTION:
$('.toggle').click(function(){
var input = $(this).next('input');
if(input.val() == 1) {
$(this).removeClass('on').addClass('off');
input.val(0).change();
} else {
$(this).removeClass('off').addClass('on');
input.val(1).change();
}
}).focus(function() {
$(this).bind('keydown', 'space', function(e){
$(this).trigger('click')
e.preventDefault();
});
}).blur(function() {
$(this).unbind('keydown');
}).attr('tabIndex', 0);
Try setting your tabindex to 0, on the non-anchor elements you would like to make "tabbable". For example tabindex="0". This way, you won't mess with the tabbing order, or have to throw tabindexs all over the place.
Look into the html attribute tabindex. Basically you should be able to set tabindex on each input you want to focusable via the tab key. Start the first one a 1 and just count upwards for each input. If you also want to take an input out of focusing via the tab key set the tabindex to -1.
<style>
.moveAble {
position: absolute;
display:none;
}
a:hover + div.moveAble {
display: block;
}
.moveAble .qtip {
background-color: #FFF;
background-color: rgba(255,255,255,.95);
border-color: #ccc;
padding: 10px;
-moz-box-shadow: 0 1px 4px rgba(0,0,0,0.2);
-webkit-box-shadow: 0 1px 4px rgba(0,0,0,0.2);
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
}
.qtip-default {
border-width: 1px;
border-style: solid;
border-color: #f1d031;
background-color: #ffffa3;
color: #555;
}
.qtip, .qtip {
max-width: 280px;
min-width: 50px;
font-size: 10.5px;
line-height: 12px;
direction: ltr;
}
#nytmm .qtip-content {
border-color: #999;
color: #000;
padding: 4px 7px;
text-align: center;
}
.qtip-content {
position: relative;
padding: 5px 9px;
overflow: hidden;
text-align: left;
word-wrap: break-word;
}
.moveAble .qtip-content h5 {
font: 300 20px/22px "nyt-cheltenham",Georgia,"Times New Roman",serif;
color: #000;
margin: 0;
}
.moveAble .qtip-content h6 {
font: 300 13px/16px 'nyt-franklin',Arial,Helvetica,sans-serif;
margin: 0;
}
</style>
<img src="http://s.jeff.io/img/gifts.png" />
<div class="moveAble">
<div id="qtip-0" class="qtip qtip-default qtip-pos-tr" style="z-index: 15001;">
<div class="qtip-content" id="qtip-0-content">
<h5>Dining Gifts »</h5>
<h6>Pug Muddlers</h6>
</div>
</div>
</div>
<script>
$(document).ready(function(){
var $moveable = $('.moveAble');
$(document).mousemove(function(e){
$('.moveAble').css({'top': e.pageY,'left': e.pageX-(e.pageX/2)});
});
});
</script>
The code above is working but when I move mouse pointer over the image in that div, it is flickering too much. I don't know why it is happening. What should be the change in the code that make it work properly?
DEMO Here
This is how you should have done it. Demo :http://jsfiddle.net/wUAGP/468/
Note adding 'left' : e.pageX+20 makes it even more smoother. Play around.
So, check out a cool .gif I made for you all. Interactive isn't it?
This is because of the gap between the .moveAble and the cursor, so they don't clash.
$(document).ready(function() {
$(document).hover(
//Mouse-over
function(e) {
$(this).mousemove(function(e) {
$('.moveAble').css({
'position' : 'absolute',
'top' : e.pageY,
'left' : e.pageX+20
}).show();
});
},
//Mouse-out
function() {
$('.moveAble').fadeOut(1300);
}
);
}, 'a img' );
All you need to do is change 'left': e.pageX - (e.pageX/2) to just a static number like 10 or 5.
Pretty Demo :)
Javascript:
$(document).ready(function () {
var $moveable = $('.moveAble');
$(document).on({
mouseenter: function () {
$moveable.show();
$(this).on('mousemove', function (evt) {
var e = evt || window.event;
$moveable.css({
top: e.pageY,
left: e.pageX + 5
});
});
},
mouseleave: function () {
$moveable.hide();
}
}, 'a img');
});
CSS (cleaned up and optimized for you):
.qtip {
max-width: 280px;
min-width: 50px;
font-size: 10.5px;
line-height: 12px;
direction: ltr;
background-color: #FFF;
background-color: rgba(255, 255, 255, .95);
border-color: #ccc;
padding: 10px;
-moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
-webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
.qtip-default {
border-width: 1px;
border-style: solid;
border-color: #f1d031;
background-color: #ffffa3;
color: #555;
}
.qtip-content {
border-color: #999;
color: #000;
position: relative;
padding: 5px 9px;
overflow: hidden;
text-align: left;
word-wrap: break-word;
}
.qtip-content h5 {
font: 300 20px/22px"nyt-cheltenham", Georgia, "Times New Roman", serif;
color: #000;
margin: 0;
}
.qtip-content h6 {
font: 300 13px/16px'nyt-franklin', Arial, Helvetica, sans-serif;
margin: 0;
}
HTML (added inline CSS for hiding and position):
<img src="http://s.jeff.io/img/gifts.png" />
<div class="moveAble" style="display: none;position: absolute;">
<div id="qtip-0" class="qtip qtip-default qtip-pos-tr" style="z-index: 15001;">
<div class="qtip-content" id="qtip-0-content">
<h5>Dining Gifts »</h5>
<h6>Pug Muddlers</h6>
</div>
</div>
</div>
PS - use updated jQuery to avoid possible deprecation/removed components in the future.
Please add some margin between mouse pointer and moveable div, because when mouse inter within moveable div, a:hover not works and moveable div display become "none".
$(document).ready(function(){
var $moveable = $('.moveAble');
$(document).mousemove(function(e){
$moveable.css({'top': e.pageY + 5,'left': e.pageX + 5});
});
});