Showing text depending on what Icon I have hovered over dynamically - javascript

so I finished a coding bootcamp a little while ago and I'm still pretty novice to Javascript. I'm having issues finding a solution to creating dynamic code. Basically I have an email Icon under every employee on the team and when hovering over the icon I want it to show their email. I can hard code this but we have multiple team pages with a different amount of employees on them.
<div class="member">
<img class="member-img" src="/assets/images/signage/example.png" alt="">
<h5 class="member-details">example</h5>
<img onmouseover="showEmail()" onmouseleave="hideEmail()" class="email-icon" id="emailIcon2" src="/assets/images/email-asset-128-fix.png" alt="">
<h5 class="email-txt" id="emailTxt">example#email.com</h5>
</div>
Specifically on this page I have 3 other of these divs for each team member. I have put both the Icons and Email texts h5s into arrays with the code below.
const allIcons = [];
$('.email-icon').each(function() {
allIcons.push(this);
});
console.log(allIcons);
const allEmails = [];
$('.email-txt').each(function() {
allEmails.push(this);
})
console.log(allEmails);
Being newer to Javascript I'm struggling to figure out what I should do here and I can't find a similar solution to this online. I want it be when I hover over Icon 1 it shows Email 1 and so forth, same goes for onmouseleave I just want to hide the h5 again. My css for the email-text is below.
.email-txt {
color: #474747;
margin: 0;
padding: 3px;
transform: translateY(-260%);
border-style: solid;
border-radius: 5px;
border-color: #474747;
background-color: darkgray;
color: black;
display: none;
}
I've tried this solution Change Color of Icon When Hovering Over Adjacent Text With jQuery
I don't know if I'm just not doing it right or what but can't get it to work.
Feel free to judge my code too, the more advice the better :). Thanks!

Assuming that the email addresses are in an array, all you need to do is generate a new image with its title attribute set to the email address for each array entry:
["1#2.com", "3#4.com", "4#5.com", "5#6.com"].forEach(function(item){
let link = document.createElement("a"); // Create dynamic anchor
link.href = "mailto:" + item; // Set link to go to array item
let img = document.createElement("img"); // Create dynamic image
img.alt = item; // Set the required alt attribute
img.src = "https://illustoon.com/photo/dl/2751.png"; // Set image source
img.title = item; // Set the tooltip for the image to the array item
link.append(img); // Put the image in the anchor
document.body.append(link); // Put the anchor on the page
});
img { width: 30px; }
<p>Hover over each icon to see the email address
NOTES:
Don't store HTML elements in an array - - they are already in the DOM so there's no reason to maintain a second list of them. Just store the data you want to work with in the array.
Don't use headings (<h1>...<h6>) because of how the text is styled by the browser. Headings are to define document structure and are essential for those who use assistive technologies (like screen readers) to browse the web. An <h5> would only ever be used to sub-divide an existing <h4> section. And an <h4> should only be used to sub-divide an <h3> section, and so on.
You are using JQuery in your code. While there's nothing inherently wrong with JQuery, it's widely overused to solve simple coding scenarios. Your situation here is very simple and really doesn't warrant JQuery. Learn JavaScript very well before learning JavaScript libraries and frameworks.

You could use CSS to handle the hovering effect, when possible CSS is preferrable over JS to handle these scenarios:
const employees = [{
email: "member1#email.com",
img: "👮"
}, {
email: "member2#email.com",
img: "👷"
}, {
email: "member3#email.com",
img: "💂"
}, {
email: "member4#email.com",
img: "🕵"
}]
employees.forEach(d => {
const html = ` <div class="member">
<div class="member-img">${d.img} </>
<h5 class="member-details">${d.email.match(/.*(?=#)/)}</h5>
<div class="email-icon">✉️<h5 class="email-txt" id="emailTxt">${d.email}</h5></div>
</div>`
root.innerHTML += html
})
#root {
display: flex;
justify-content: center;
}
.member {
display: flex;
flex-direction: column;
align-items: center;
}
.email-icon {
position: relative;
font-size: 3rem;
cursor: pointer;
}
.email-txt {
display: none;
position: absolute;
top: 0;
left: 0;
transform: translateX(-50%);
}
.email-icon:hover .email-txt {
display: block;
}
<div id="root"></div>

Related

How can I figure out what size an HTML Element will be? (tween size as element added)

I'm pretty sure this is currently infeasable.
I have an animation that involves an element moving from an absolute position to an inline one. For reasons, I can not know how the container is sized, nor how the element I'm animating is sized.
What I need to know is what the size of the HTML Element will be after the transformation, without any jittery drawing.
This makes the problem very difficult (likely undoable) because I have no way to know if adding the element will resize the parent, or resize the element itself.
What I need is a means of looking into the future.
const byId = (id) => document.getElementById(id);
#container {
height: 3em;
min-width: 50%;
background: teal;
}
#mystery {
background: purple;
}
<div id="container">
<div id="mystery">Some Text</div>
</div>
<button onClick='byId("mystery").style.position = "relative"'>Position Relative</button>
<button onClick='byId("mystery").style.position = "absolute"'>Position Absolute</button>
Currently, these are the only solutions I can imagine (they're all absurd):
Clone the entire webpage HTML, make the clone have opacity: 0; pointer-events: none and render what the future will be secretly.
Capture the paint data of the current page (basically screenshot), overlay that while secretly modifying the page, get my future, revert, and remove the screenshot overlay.
Similar to number 2, is there a way to ❄️freeze❄️ rendering of a page for 3-4 frames?
I remember seeing a "sizing worker" something-or-rather a long time ago. Couldn't find any information on it now, but it seems like it might be useful?
You can simply change the property, measure the sizes you want and then change the property back. JS is fast enough to do it all between renderings, as long as you keep it all in the same thread. Have you tried that at all?
Asker Edit:
Here's the code to prove it works.
function byId(id){ return document.getElementById(id); }
const tweenyEl = byId("tweeny");
function appendTweeny() {
tweenyEl.style.opacity = "1";
const startingWidth = tweenyEl.clientWidth + "px"
tweenyEl.style.position = "relative";
const targetWidth = tweenyEl.clientWidth + "px";
console.log(startingWidth, targetWidth);
tweenyEl.style.width = startingWidth;
requestAnimationFrame(() =>
requestAnimationFrame(() =>
tweenyEl.style.width = targetWidth
)
);
}
function resetTweeny() {
tweenyEl.style.position = "";
tweenyEl.style.width = "";
tweenyEl.style.opacity = "0.1";
}
#container {
display: inline-block;
height: 3em;
min-width: 150px;
background: teal;
}
#tweeny {
font-family: arial;
color: white;
position: absolute;
background: purple;
transition: all 0.5s ease;
opacity: 0.1;
}
<div id="container">
<div id="tweeny">I'm Tweeny</div>
</div>
<br>
<button onClick='appendTweeny()'>Append Tweeny</button>
<button onClick='resetTweeny()'>Reset Tweeny</button>
I would suggest cloning the page into an iframe and then positioning the iframe off the screen.
<iframe style="width:100vw;height:100vh;left:-101vw;positionabsolute"><iframe>
Also bear in mind that the user can zoom in-and-out at will! Different browsers might render the same thing in different ways. You really don't know how big an element will be until it does so.
I don't know if you can get anywhere by specifying display: none; ... whether or not the browser would bother to make these calculations for an object that isn't visible.
You can clone on the fly an element with same transformation with delay 0 and then calculate it's width and height, then do what you want with your actual element it's still animating

Dynamically Display Multiple Currency Prices for Different Locales On Same Page

I am trying to display different prices for a single product on a generic /eu/ webpage. The prices are fixed so I am hoping this can be done using a simple query but I am very new to JS/JQuery.
Currently the price is displayed in div with the class price-block
and users can toggle their locale with a data-locale="{country code}" div.
Using these two IDs, can I create a script that says e.g. data-locale="UK" then price is £1000?
I think I need to be looking into "if this selected, var equals this value" solutions - any help much appreciated.
Here's one way of achieving it by using a simple key/val object for locale/price respectively:
$(function() {
var prices = {
"UK": "£1000",
"US": "$1500",
"DE": "€1250"
}
$("[data-locale]").click(function() {
var locale = $(this).attr("data-locale");
// ensure the locale value is valid
if (prices[locale]) {
$(".price-block").text(prices[locale]);
} else {
$(".price-block").text("Invalid locale: " + locale);
}
})
})
[data-locale] {
border: 2px solid;
cursor: pointer;
display: inline-block;
padding: 5px;
}
.price-block {
font-size: 20px;
margin-top: 10px;
}
<div class="locale-block">
<div data-locale="UK">UK</div>
<div data-locale="US">US</div>
<div data-locale="DE">DE</div>
</div>
<div class="price-block"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Dynamic mouseenter

I appended a few divs with inside img tags. Every tag has own unique id = "theImg"+i where "i" is number. I want to mouseover on specific img and show the content of span (which also have specific id with number). Here is my code so far but not working.
var j;
document.onmouseover = function(r) {
console.log(r.target.id);
j = r.target.id;
}
$(document).on({
mouseover: function(e){
$("span").show();
},
mouseleave: function(e){
$("span").hide();
}
}, "img#"+j);
If you have a span after every img, maybe it's a good idea to not use JavaScript at all? ;-)
You could use :hover pseudoclass in CSS, making your thing always work reliably.
Consider the following example:
img + span {
display: none;
}
img:hover + span {
display: block;
}
/*/ Optional styles /*/
div {
position: relative;
float: left;
}
div img + span {
position: absolute;
color: #fff;
background: #27ae60;
border: solid 1px #2ecc71;
border-radius: 50px;
z-index: 1;
bottom: 1em;
width: 80%;
left: 50%;
margin-left: -43%;
padding: 2% 3%;
text-align: center;
}
<div>
<img src="https://placehold.it/400x200">
<span>This is an image of a gray rectangle!</span>
</div>
<div>
<img src="https://placehold.it/200x200">
<span>This is an image of a gray square!</span>
</div>
<div>
<img src="https://placekitten.com/g/400/200">
<span>This is an image of a cute kitten inside a rectangle!</span>
</div>
<div>
<img src="https://placekitten.com/g/200/200">
<span>This is an image of even cuter kitten inside a square!</span>
</div>
So the issue is that you are trying to set your handler on a dynamic selector ("img#"+j) but this will not work. For one thing, that equation will be evaluated only once, on page load, when j is undefined.
So you want to do this instead:
target only img tags for your mouse over... Better yet, give your special images all the same css class so you can attach the event handlers only to those. That will be more efficient.
When an image is moused over or out of, grab it's id attribute, extract the number from it, then use that to build a selector for the appropriate span to show.
var get_span_from_image = function(image) {
var image_id = image.attr("id");
var matches = image_id.match(/theImg(\d+)/);
if(matches) return $("theSpan" + matches[1]);
return $(); // nothing found, return an empty jQuery selection
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Note: There are better ways to "link" two nodes together, but this is just to answer your question with the current structure you have.
UPDATE: Some ideas to link two nodes together
So instead of trying to extract a number from an id attribute, a better way would be to tell either one of the image or span about it's sibling. You could output your html like this, for instance:
<img id="theImg1" data-target="theSpan1" class="hoverable" src="..."/>
....
<span id="theSpan1">...</span>
Of course now your ideas could be anything - you don't have to use numbered values or anything.
Then your hover code becomes quite simply:
var get_span_from_image = function(image) {
var span_id = image.data("target");
return $("#" + span_id);
};
$("img").hover(
function() { // mouse over
get_span_from_image($(this)).show();
},
function() { // mouse out
get_span_from_image($(this)).hide();
}
);
Hope this helps!

Gallery. Display divs corresponding to clicked <li> item. Javascript

I'm trying to build a basic gallery which displays a large image [div] depending on which image is clicked. The thumbnail images are stored in a basic unordered list.
I'm a javascript noob, I could use getElementById to change display class etc but I'd prefer not to have a separate function for each image, of which they're may be 100 or so.
Is there a way to call the same function to display a different div depending on which image is clicked [a larger version of that image]?
So:
If img1 is clicked display divA,
If img2 is clicked display divB,
If img3 is clicked display divC...
Many thanks.
The event passed to the onclick method has a target parameter, which refers to the element that was clicked.
Please post your code, preferably in a working JsFiddle, to get a more targeted answer.
Here is a general example of what you want to achieve:
document.onclick = function(e) {
// e.target is the img that was clicked, display the corresponding div
// Get the image number from the id
var number = e.target.id.substr(3)
// Display the corresponding div
document.getElementById('div' + number).style.visibility = 'visible';
}
Please note that the last line will most likely be different in your implementation - I don't know how you are displaying these divs.
You could try as follows
Assign id to all images in such a manner when they will be clicked we
could generate the corresponding div's id with some logical
manipulation.
Such as
images would have id like img_divA,img_divB and when they will be clicked , get there id and do some stuff like substring and you will get divA , divB and so on .. Finally show that by javascript ..
You could do something like this. Here actually a function is created per clickable dom element, but they are programmatically created. I use the num attribute to make the correspondence between the images to show and the images to click but there is many other (good) ways to do it.
// retrieve the divs to be clicked
var toClicks = document.querySelectorAll(".img-to-click");
[].forEach.call(toClicks, function(node){
// retrieve the target image
var num = node.getAttribute("num");
var target = document.querySelector(".img-to-show[num=\"" + num + "\"]");
// create the click listener on this particular dom element
// (one of the image to click)
node.addEventListener('click', function(){
// hide any currently displayed image
var current = document.querySelector(".img-to-show.shown");
if(current) current.classList.remove("shown");
// set the new current
target.classList.add("shown");
});
});
#to-display {
position: relative;
width: 100%;
height: 50px;
}
#to-click {
position: relative;
margin-top: 20px;
}
.img-to-show {
position: absolute;
width: 100%;
height: 100%;
display: none;
}
.img-to-show.shown {
display: block;
}
.img-to-click{
display: inline-block;
background-color: gray;
width: 50px;
color:white;
text-align: center;
line-height: 50px;
vertical-align: middle;
height: 50px;
cursor:pointer;
}
<div id="to-display">
<div class="img-to-show" num="1" style="background-color:blue;"></div>
<div class="img-to-show" num="2" style="background-color:red;"></div>
</div>
<div id="to-click">
<div class="img-to-click" num="1">1</div>
<div class="img-to-click" num="2">2</div>
</div>

How can I set text to be copied to clipboard when image is copied?

I am building a web page and have run into something that would be nice to be able to do; set text to be copied to the clipboard when someone tries to copy an image, probably the same as the alt text. Is there any way with javascript/html that this can be done? If so, please explain.
Thanks for any help!
Edit: Basically, I want to let my users highlight the image, press control-c, and then have the alt text stored in their clipboard.
This is possible as Twitch.tv does this when copying emote images in chat. The trick is to use the copy event.
const parent = document.getElementById('parent');
parent.addEventListener('copy', event => {
let selection = document.getSelection(),
range = selection.getRangeAt(0),
contents = range.cloneContents(),
copiedText = '';
for (let node of contents.childNodes.values()) {
if (node.nodeType === 3) {
// text node
copiedText += node.textContent;
} else if (node.nodeType === 1 && node.nodeName === 'IMG') {
copiedText += node.dataset.copyText;
}
}
event.clipboardData.setData('text/plain', copiedText);
event.preventDefault();
console.log(`Text copied: '${copiedText}'`);
});
#parent {
display: flex;
flex-direction: row;
align-content: center;
align-items: center;
flex-grow: 0;
}
#parent,
#pasteHere {
padding: 0.5rem;
border: 1px solid black;
}
.icon {
width: 32px;
}
#pasteHere {
margin-top: 1rem;
background: #E7E7E7;
}
<p>Copy the line below:</p>
<div id="parent">
Some text <img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.svg?v=f13ebeedfa9e" class="icon" data-copy-text="foo" /> some more text <img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.svg?v=f13ebeedfa9e"
class="icon" data-copy-text="bar" />
</div>
<div id="pasteHere" contenteditable>Paste here!</div>
add attribute alt="text" to your image
example:
<img alt="🇫🇷" src="https://twemoji.maxcdn.com/v/14.0.2/72x72/1f1eb-1f1f7.png">
I don't think you can. If you could hook keyboard events through the browser, that'd be a tremendous security issue. You could capture keystrokes and send them to a web service in a few lines of code, which would ruin some lives pretty easily.
You may be able to detect a mouse down event using onmousedown by attaching it to the image in some fashion and store that alt-text in a hidden field or cookie and DoSomething() from there.
I've seen services such as tynt do something like this. 2065880 Javascript: Hijack Copy? talks about the techniques, as does 1203082 Injecting text when content is copied from Web Page

Categories