back and forth between nodes in vanilla javascript - javascript

I'm expanding a site (menright.com) that displays about fifty years of photos. This link goes to the first photo page: (https://menright.com/pages/photoPages/photos-1967.php). Each photo is followed by a caption, and there is a button that allows the viewer to see a longer description that replaces the caption. The button isn't working here but allows you to see what I'm talking about.
To implement this I have an img (the button) inside of a p tag (the caption). Clicking the button substitutes the longer description drawn from the alt and the title in a second img (the picture) immediately above the caption.
I can't use IDs since there are many captions and pictures on each page.
Here is the HTML skeleton of the significant parts of the problem:
<img alt='long description' title='location image taken' />
<p class='the caption'> <img class='get long description button' /> </p>
I'm thinking I have to find the node of the target (the button), track its parent (the caption), and then get the alt and title from something like a previousSibling (the picture) and use the innerHTML of the parent (the caption) to display the long description.
Am I correct in this assumption, or is there another way to do this? And if this is the technique I need to use, how do I do it? I'm totally new to using nodes in my vanilla Javascript, and I don't want to add JSquery or other libraries to my pages.
This is my first post here, though I've used the site for years. Thanks for any help you might provide!

I'm thinking I have to find the node of the target (the button), track its parent (the caption), and then get the alt and title from something like a previousSibling (the picture) and use the innerHTML of the parent (the caption) to display the long description.
Am I correct in this assumption, or is there another way to do this?
If you stick to that structure, yes, that's what you'd do (probably previousElementSibling so you don't have to worry about intervening Text nodes), and setting textContent rather than innerHTML unless you want < and & in the text to be interpreted as HTML. You'd probably do it via event delegation on whatever container has all of these in it (body, if there's nothing nearer):
theContainer.addEventListener("click", event => {
const btn = event.target.closest(".get.long.description.button");
if (btn && theContainer.contains(btn)) {
const p = btn.parentElement;
const alt = p.previousElementSibling?.alt;
if (alt) {
p.textContent = alt; // `textContent` assuming you don't have tags
}
}
});
But if you can wrap all of that in an element:
<div class="wrapper">
<img alt='long description' title='location image taken' />
<p class='the caption'>
<img class='get long description button' />
</p>
</div>
...you can make it more robust:
theContainer.addEventListener("click", event => {
const wrapper = event.target.closest(".container");
if (wrapper && theContainer.contains(wrapper)) {
const p = wrapper.querySelector(".the.caption");
const alt = wrapper.querySelector(".location.image.taken")?.alt;
if (alt) {
p.textContent = alt; // `textContent` assuming you don't have tags
}
}
});
That doesn't rely on the exact relationship between the elements, just that they're all in the same container, so you can move them around as the page design evolves without changing your code.

Related

Getting hidden text field with url to update image on hover jQuery

I'm testing out some jQuery and want to update a image when hovering over a specific div or link block.
So what i was trying to do is when hovering over .test-block get the hidden text with the url and update it on .large-image-2. It can't seem to get the specific text on hover.
This is the code i have come up with:
$('.test-block').on('onmouseenter', function() {
let myUrl = $(this).find('.display-hidden').text();
$('.url').text(myUrl);
});
Im testing on this page: https://jquery-testing.webflow.io/update-image the three bottom div's and bottom picture on right is what i want to use.
Thanks in advance!
There are a few issues with your example. Mainly the way you register the event handler.
For jQuery the correct way would be $(target).on('mouseenter') - Ommit the on... part for the event you want to register when doing it through jQuery.
I would probably implement the functionality you're looking for in a less specific way and with simpler handles like the following:
$(function () {
let divs = $('[data-image-target][data-image-url]');
divs.on('mouseenter', function () {
let that = $(this)
const target = that.data('image-target')
const url = that.data('image-url')
$(target).attr('src', url);
})
divs.first().trigger('mouseenter')
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div
data-image-target="#my-target-image"
data-image-url="https://dummyimage.com/600x400/000/fff&text=one">
Hover One
</div>
<div
data-image-target="#my-target-image"
data-image-url="https://dummyimage.com/600x400/000/fff&text=two">
Hover Two
</div>
<div
data-image-target="#my-target-image"
data-image-url="https://dummyimage.com/600x400/000/fff&text=three">
Hover Three
</div>
<img id="my-target-image">
Explanation:
Data attributes:
Two data attributes are getting used in my example: data-image-target and data-image-url.
Using data attributes on the elements you want the event to be fired on will make your script a bit more robust and less prone to errors, since the event registration is bound to the two attributes being present using attribute selectors for the jQuery selector $([data-image-target][data-image-url]) instead of arbitrary classnames and/or ids.
The data-image-target should have a CSS selector that points to the <img> element(s) you wish to switch the src url on, while the data-image-url should hold the url of the image you want to switch to.
The code above could even replace your existing functionality for the top 3 images on your page.
This code worked
$(function () {
let divs = $('[data-image-target][data-image-url]');
divs.on('mouseenter', function () {
let that = $(this);
const target = that.data('image-target');
const url = that.data('image-url');
$(target).attr('src', url);
});
});
Thanks to Morten for providing. With Webflow i also had to do Command + Shift + O to turn off responsiveness to the image. (when on image settings)
Attributes:
Name: data-image-target
Value: #my-target-image
And
Name: data-image-url
Value: (image url, in my case Webflow: https://uploads-ssl.webflow.com/something)
These two attributes to each hover element.
Name: id
Value: my-target-image
This to the image element to show images. (if Webflow; "my-target-image" goes in the ID field in element settings.

JS: Add link dynamically to all elements of certain class

I work in a system where we have these elements representing a part of an audio clip, and a timeline for the audio that is browsable (click around to play different parts). However, the elements representing the parts of the audio clip does not actually link to the parts of the audio.. (so no "click this to play this part").
I have deducted that it is possible to link to a specific part of the call via for example: http://thelink.com/timeline?startms=%221600326183999%22. And that the elements all have an attribute called "startms", for example:
<div class="segment-item" startms="1600326183999"></div>
Is there any way I could loop through all the elements in the page with the class "segment-item" and add a href="" with the value of their individual "startms" value to the link (http://thelink.com/timeline?startms=%22TheValueHere%22).
Then finally, since I cannot build an addon to my browser for this, would it be possible to make a snipped which can be pasted into the console for easy use when I need it? Any other suggestions to making such a thing be easily accessible for usage without making or using an addon for chrome?
If you want to add the link to the element, you should add it like that
const elements = document.getElementsByClassName("segment-item")
for (element of elements) {
const a = document.createElement("a")
a.href = `http://thelink.com/timeline?startms=%22${element.getAttribute("startms")}%22`
a.innerText = "LINK NAME"
element.appendChild(a)
}
Adding a link based on element properties goes like this
const elements = document.getElementsByClassName("segment-item")
for (element of elements) {
element.innerHTML = `<a href="http://thelink.com/timeline?startms=%22${element.getAttribute("startms")}%22">
Link name
</a>`
}

How to change h1 tittle when clicked/make the section centered

I'm working on some simple questions as practice for my exam, but most of the questions don't have any answers for me to check if I don't know. There is one I'm really unsure about, so I thaught I'd check here. The question is:
Suppose we have an HTML document that contains these two lines:
<Body>
<H1 title = "When this is clicked, the section changes"> Title </ h1>
<P id = "first" title = "When this is clicked, the title is centered"> First section: Original version. </ P>
</ Body>
Type the code that would change the look of this page so that:
• When you click on the h1 title, the section changes from "First section: Original Version" to "First section: modified version ".
• When you click on the section, the position of the title changes and gets centered.
Hope someone can help learn me this so I have an answer if something similar shows up on my exam:)
var h1 = document.querySelector('h1');
var first = document.querySelector('#first');
h1.addEventListener('click', function() {
first.innerText = 'First section: modified version.';
});
first.addEventListener('click', function() {
h1.style.textAlign = 'center';
});
As others have mentioned, you should be able to find everything on Google. But to help you out, this is what the answer should be:
var heading = document.getElementsByTagName("h1")[0];
var section = document.getElementById("first");
heading.addEventListener("click", function() {
section.innerText = "First section: modified version";
});
section.addEventListener("click", function() {
heading.setAttribute("style", "text-align: center");
});
<h1 title="When this is clicked, the section changes">Title</h1>
<p id="first" title="When this is clicked, the title is centered">First section: Original version.</p>
Is this what you are looking for?
$(document).on("click", "h1", function() {
$(this).css("text-align", "center");
})
p, h1 {
text-align: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1 title="When this is clicked, the section changes"> Title </h1>
<p id="first" title="When this is clicked, the title is centered"> First section: Original version. </p>
First of all Please correct your html markup to standards and add some javascript code. Check below snippet:
$(document).on('click', 'h1', function(){
$('#first').text('First section: Modified version.');
});
$(document).on('click', '#first', function(){
$('h1').css('text-align','center');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<h1 title = "When this is clicked, the section changes"> Title </h1>
<P id = "first" title = "When this is clicked, the title is centered"> First section: Original version. </ P>
</body>
I really have no idea why you're being downvoted here. From what I gather you've tried your best on all your assigned questions and this one happened to stump you...
Anyways.. this question has a few different problems that need to be solved for you to complete the question. I'm going to try to break these down into the components, and then explain the pieces that help us get to where you want to be.
Question 1
Thinking through this a bit, here are the following steps to solve your problem.
Find a way to "listen" for a "click event" on the <h1> element.
Find a way to change the text within the <p> element to the desired text when the <h1> element is clicked.
There are some substeps buried in this but this should get us started.
To solve this issue, we'll need to find a way to select elements on a page. A Google search yields a few methods to do this in vanilla JS based solely on the code you've given.
Query Selectors: document.querySelector and document.querySelectorAll
Tag selectors: document.getElementsByTagName
There are many others as well, but using only the code that you've supplied, and assuming we're not allowed to add class attributes or anything, we'll roll with the above choices.
The selectors above all return HTML "nodes" from the page. You can think of a HTML nodes as objects that make up an HTML page. They have all sorts of properties and we can perform many operations on them.
Your best bet is to use the first suggestion, document.querySelector because it returns a single HTML node based on the passed selector. Be careful though. If we had more than one of the same element, it would only return the first which isn't at all useful.
Here's some documentation you can read and a few examples to help you understand how it works.
document.querySelector documentation
So now we have a way of selecting the <h1> element on the page.
document.querySelector(h1);
Now, we need a way to listen for events. A search of "listening for events in vanilla JS" would bring you to the addEventListener method, which allows us to listen for events on a given HTML element.
eventListener documentation
Now we can put these two together and we have an <h1> element that listens for events. I'm going to skip ahead a bit and fill in the function so we have.
let title = document.querySelector('h1');
title.addEventListener('click', function() {
alert('I just clicked the title');
});
If you plug that in and click the title, you'll see a modal pop up indicating that you clicked the title. One step down.
Now, we have to find a way to change the "text content" of the <p> element to the desired text. To do this, we first need to select the <p> element and store it in a variable. You now know how to do this so I'll leave you to it.
Now that we have the reference to the node we want to modify, we need to change a property of that node related to the text. A Google search of this will return a few different properties, but I'm going to nudge you in the right direction and let you know you want the elem.textContent property.
Putting this all together, here's the code I have that works and satisfies your requirements for the first question.
let headerTxt = document.querySelector('h1');
let sectionTxt = document.querySelector('p');
headerTxt.addEventListener('click', function() {
sectionTxt.textContent = 'First section: modified version';
});
Question 2
Some similarities from the first question here. We need to...
Select both the <h1> and <p> elements on the page (DONE)
add a click event listener to the <p> element that centers the <h1> element.
We can skip the first piece since we did that in question 1. I'm also going to skip adding an event listener to the <p> since we did something similar to that in the first question.
After adding the event listener, we need a way to change the text-alignment of some text in an HTML element.
A Google search brings us to the textAlign CSS property which we can modify using JS.
textAlign
Putting this all together, here's the complete solution
let headerTxt = document.querySelector('h1');
let sectionTxt = document.querySelector('p');
headerTxt.addEventListener('click', function() {
sectionTxt.textContent = 'First section: modified version';
});
sectionTxt.addEventListener('click', function() {
headerTxt.style.textAlign = 'center';
});
<body>
<h1 title = "When this is clicked, the section changes"> Title </h1>
<p id = "first" title = "When this is clicked, the title is centered"> First section: Original version. </p>
</body>
Hope this helps man. One takeaway of advice I have for you is get used to searching and get used to reading documentation. I'm a beginner too and I've figured that out quickly lol.
Good luck!

Change Dynamic Link Text In Javascript

I currently have a slideshow run with HTMl CSS and JS at the moment for the navigation buttons below the slideshow it is just placing numbers instead of text. Is there a way to grab the images title and use it or custom text for each slide link. Below i included the Javascript that makes the navigation buttons and adds the text. If you need anything else just let me know.
If i can just specify text in this JS file that would work too.
Also if it may help im using Kickstart HTML Template.
Link to view it http://bliskdesigns.com/clients/timbr/
var items = $(this).find('li');
wrap.append('<ul class="slideshow-buttons"></ul>');
items.each(function(index){
wrap.find('.slideshow-buttons')
.append('<li>'+(index+2)+'</li>');
});
It's difficult to give you a concise answer with what you've provided, however:
Assuming that in the code you've provided:
items is an array containing each slide in your slideshow;
That each element in items contains an img;
That the text that you want to appear in the slideshow nav is the title attribute of each img;
That the unordered list being built by wrap is the navigation;
That the text you want to change is the numeral within the anchor of each item injected into wrap.
Here's a potential answer:
// put all slides into 'items'
var items = $(this).find('li');
// append the wrap element with an unordered list
wrap.append('<ul class="slideshow-buttons"></ul>');
// loop over each item
items.each(function(index){
// grab the title attribute of the img child of this instance of items
var titleText = $(this).find('img').attr('title');
// push a new <li> into 'wrap'
wrap.find('.slideshow-buttons').append('<li>'+titleText+'</li>');
});
This should just be a direct replacement for wherever in your project the code you've included above came from.
As I say: I can't promise that this will work without a lot more information, but in theory it will. Make sure that each of your images has a title:
<img src="/link/to/image.kpg" alt="alternative text" title="text you want to appear in the slider navigation" >
Alternatively, you can use the text in the image's alt tag instead by changing this line from above:
// grab the alt attribute of the img child of this instance of items
var titleText = $(this).find('img').attr('alt');
In the list items you can add the text that you want to display instead of numbers, as shown below.
<li data-displayText="Timber Mart"> <img src="http://i.imgur.com/4XKIENA.png" width="920" /> </li>
Then in above code you can use the text instead of index, as shown below.
wrap.find('.slideshow-buttons')
.append('<li>'+$(items[index]).attr("data-displayText")+'</li>');

Javascript show/hide - I don't want it to hide the entire element

This is probably a fairly easy question, but I'm new to JavaScript and jquery....
I have a website with a basic show/hide toggle. The show/hide function I'm using is here:
http://andylangton.co.uk/articles/javascript/jquery-show-hide-multiple-elements/
So here's my question..... I would really like the first 5-10 words of the toggled section to always be visible. Is there some way I can change it so that it doesn't hide the entire element, but hides all but the first few words of the element?
Here's a screenshot of what I would like it to do:
http://answers.alchemycs.com/mobile/images/capture.jpg
There are many different implementation possibilities:
You can divide the contents up into the first part and the second part (two separate spans or divs inside your main object) and hide only the child object that represents the second part, not hide the parent object.
Rather than hide the object at all, you can set its height to only show the first part (with overflow: hidden)
Change the contents of the main object to only have the first part as the contents (requires you to maintain the full contents somewhere else so you can restore it when expanded again).
Here's a working example of option 1: http://jsfiddle.net/jfriend00/CTzsP/.
You'd need to either:
Put in a span/etc. after the first n words, and only hide that part, or
Change the viewable region, or
Replace or toggle the span/etc. with the "collapsed" view.
The last is a bit more customizable; using two separate elements allows trivial games to be played (showing an image, for example, like a little curly arrow) without modifying adding/removing DOM elements.
I tend towards the last because it's simple and obvious, but that's a personal preference, and really isn't as true as it used to be.
You can do some plugin authoring,I did a sample demo here ,based on your screenshot
<div class="toggle">ShowHide</div>
<div class="content">some content some content some content some content some content <br/> some content some content some content </div>
<div class="toggle">ShowHide</div>
<div class="content">some content some content some content some content some content <br/> some content some content some content </div>
here is javascript/jquery code
jQuery.fn.myToggle = function(selector, count) {
var methods = {
toggle: function(selector, count) {
if ($(selector).is(':visible')) {
var span = $('<span>');
span.text($(selector).text().substr(0, count) + "...");
span.insertAfter($(selector));
$(selector).hide();
}
else {
$(selector).show();
$(selector).next('span').hide();
}
}
};
$(this).each(function() {
methods.toggle($(this).next(selector), count);
$(this).click(function(evt) {
methods.toggle($(this).next(selector), count);
});
});
};
$(function() {
$('.toggle').myToggle('.content', 3);
});
Here is a solution using css properties only instead of mangling the dom.
http://jsfiddle.net/AYre3/4/
Now if you want some sort of animation happening as well you'll probably need to do a bit of measurement along the way.

Categories