I want to run a generic javascript function with an element, sometimes multiple elements in the same HTML document. It seems to me the easiest way is to call the function from inside a DOM element. OK here's the problem. "this" refers the window element and I have seen how scope works for functions using "this" but I don't see how to get "this" to refer to an element.
I could do getElementById but I want a fairly generic javascript and not have to come up with unique IDs everytime I want to use it. getElementsByClasses may be a workaround but it just seems there should be an easier way to do this without relying on id's or classes.
The HTML
</HEAD>
<BODY>
<div id="content">
<div class="linksbox">
<a href="https://www.corponline.org" target="_blank">
<div class="linkicon">
<img src="asislink.jpg">
</div>
</a>
<div class="linkblurb">
<h2>National</h2>
<p>Description of link</p>
</div>
<script>valignimg();</script>
</div>
</div> <!-- End content -->
</BODY>
</HTML>
The javascript. It's dh and ih that I need to pass to the function.
function valignimg() {
dh = /* div element */
ih = /* image (child element) */
topmargin = (dh.offsetHeight - ih.offsetHeight)/2;
return topmargin;
}
If you're not calling it from one of the elements (i.e. via event handler), you're going to have to use a selector of some kind, either ID or class as you highlighted, or name or tag name if that can work, or some combination. Somewhere along the way it will need to be specified. In even though you weren't keen on using class, that's likely your best option so I've highlighted it in this first example.
//warning - this event isn't supported on some older browsers like IE8
document.addEventListener("DOMContentLoaded", function(event) {
valignAll();
});
function valignimg(dh) {
//Only added the IDs for this purpose, not using them to select elements so there's no functional requirement for them.
console.log(dh.id);
//This supposes that you know the image tag you want is always the first img element among dh's children.
ih = dh.getElementsByTagName('img')[0];
console.log(ih.alt);
var topmargin = (dh.offsetHeight - ih.offsetHeight) / 2;
console.log('dh.offsetHeight = ' + dh.offsetHeight);
console.log('ih.offsetHeight = ' + ih.offsetHeight);
console.log('topmargin = ' + topmargin);
ih.style.marginTop = topmargin + "px";
console.log('ih.style.marginTop = ' + ih.style.marginTop);
}
function valignAll(){
var linkIcons = document.getElementsByClassName('linkicon');
for(i = 0;i < linkIcons.length;i++){
valignimg(linkIcons[i]);
}
}
<BODY>
<div id="content">
<div class="linksbox">
<a href="https://www.corponline.org" target="_blank">
<div id="icon1" class="linkicon">
<img alt="img1" src="http://placehold.it/20x20">
</div>
</a>
<div class="linkblurb">
<h2>National</h2>
<p>Description of link</p>
</div>
<a href="https://www.corponline.org" target="_blank">
<div id="icon2" class="linkicon">
<img alt="img2" src="http://placehold.it/21x20">
</div>
</a>
<div class="linkblurb">
<h2>National</h2>
<p>Description of link</p>
</div>
<a href="https://www.corponline.org" target="_blank">
<div id="icon3" class="linkicon">
<img alt="img3" src="http://placehold.it/22x20">
</div>
</a>
<div class="linkblurb">
<h2>National</h2>
<p>Description of link</p>
</div>
</div>
</div>
<!-- End content -->
</BODY>
You can see, although my usage is pretty rudimentary, I've used getElementsByTagName as well, calling from a parent element other than document. The IDs I've added aren't used for locating anything, I'm just using them so that when I log to console you can see which element it really is, the same as with my horrendous misuse of the alt attribute on the images.
If you know that your only image elements on the page are the ones you're acting on, then maybe starting with document.getElementsByTagName('img') is the approach for you, and then get the div with the .parentNode property. This would remove the reliance on classes, but if you add other img tags to the page then you'd need some way to identify from each one whether it's once you want to run your align function against or not. The img tags you want to access have a common ancestor or parent that no other img tags do. I've added another snippet below that shows this. And you could combine these two approaches with a nest loop to get all img tags within multiple divs that all share a class, for example.
//warning - this event isn't supported on some older browsers like IE8
document.addEventListener("DOMContentLoaded", function(event) {
valignAll();
});
function valignimg(ih) {
//Only added the IDs for this purpose, not using them to select elements so there's no functional requirement for them.
console.log(ih.alt);
//This supposes that you know the image tag you want is always the first img element among dh's children.
dh = ih.parentNode;
console.log(dh.id);
var topmargin = (dh.offsetHeight - ih.offsetHeight) / 2;
console.log('dh.offsetHeight = ' + dh.offsetHeight);
console.log('ih.offsetHeight = ' + ih.offsetHeight);
console.log('topmargin = ' + topmargin);
ih.style.marginTop = topmargin + "px";
console.log('ih.style.marginTop = ' + ih.style.marginTop);
}
function valignAll(){
//if they're the only img tags on the page,
//document.getElementsByTagName('img'); will work fine.
//lets assume they aren't.
var images = document.getElementsByClassName('linksbox')[0].getElementsByTagName('img');
//I can grab the comment parent/ancestor by whatever means available, and then grab just its decendants by tag name.
alert(images);
for(i = 0;i < images.length;i++){
valignimg(images[i]);
}
}
<BODY>
<div id="content">
<img src="http://placehold.it/240x20"><< Some sort of header logo
<div class="linksbox">
<a href="https://www.corponline.org" target="_blank">
<div id="icon1" class="linkicon">
<img alt="img1" src="http://placehold.it/20x20">
</div>
</a>
<div class="linkblurb">
<h2>National</h2>
<p>Description of link</p>
</div>
<a href="https://www.corponline.org" target="_blank">
<div id="icon2" class="linkicon">
<img alt="img2" src="http://placehold.it/21x20">
</div>
</a>
<div class="linkblurb">
<h2>National</h2>
<p>Description of link</p>
</div>
<a href="https://www.corponline.org" target="_blank">
<div id="icon3" class="linkicon">
<img alt="img3" src="http://placehold.it/22x20">
</div>
</a>
<div class="linkblurb">
<h2>National</h2>
<p>Description of link</p>
</div>
</div>
</div>
Sponsor Logos or Site Certs in the footer
<img src="http://placehold.it/20x20"><img src="http://placehold.it/20x20"><img src="http://placehold.it/20x20">
<!-- End content -->
</BODY>
Related
I wrote a function that dynamically creates a webpage for me based on a json database.
Now I want to add 2 functions:
If you click the like img (its got the id button) the like counter should increase on the webpage by 1. Pretty easy just a on(click) with jQuery variable++ and then .text(variable)
A sort function - based on the likes one item received, you should be able to sort it (most liked div first, 2nd, 3rd....
I can write it for each individually with individual variables when I give all the like buttons and outputs a separate id but I wanted to make it dynamic so if you add new data to json file it dynamically works with the like and sort function.
The likes are not saved anywhere for now.
Since sitting on it for 3h and google so much and so much stackoverflow I think I overloaded my brain with different stuff and now nothing seems to work ^^
function filmInsert(insert) {
$.each(film, function(i, data) { //.each statt loop
let box =
`<div class="boxwrapper">
<div class="imgbox">
<img src="${data.img}" alt="${data.titel}">
</div>
<div class="textbox">
<h3>${data.titel}</h3>
<p>${data.beschreibung}</p>
<p> <a id="button${data.id}">
<img src="img/budspencer_official.png"> Like
</a>
<span class="output${data.id}">${data.likes}</span>
</p>
</div>
</div>`;
insert.append(box);
});
}
I've added a container element for the boxwrapper items as I assume you have one and as it's better to have one instead of just adding the sorted items to the body of the HTML document.
$(document).on("click", ".textbox a", function() {
let likes = parseInt($(this).closest(".textbox").find("span").text());
$(this).closest(".textbox").find("span").text(likes + 1);
});
$("#sort").on("click", function() {
let divs = $(".boxwrapper")
let sorted = divs.sort(function(a, b) {
return $(a).find("span").text() < $(b).find("span").text() ? 1 : -1;
});
$(".container").html(sorted);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="boxwrapper">
<div class="imgbox">
<img src="example.gif" alt="Title">
</div>
<div class="textbox">
<h3>Titel</h3>
<p>Description</p>
<p> <a id="button1">
<img src="https://dummyimage.com/40x40/000/fff&text=1"> Like
</a>
<span class="output1">0</span>
</p>
</div>
</div>
<div class="boxwrapper">
<div class="imgbox">
<img src="example.gif" alt="Title">
</div>
<div class="textbox">
<h3>Titel 2</h3>
<p>Description 2</p>
<p> <a id="button2">
<img src="https://dummyimage.com/40x40/000/fff&text=2"> Like
</a>
<span class="output2">0</span>
</p>
</div>
</div>
</div>
<button id="sort">
Sort
</button>
I have some modals where there are some images. I also have a download button, that should download just the shown (the only visible) image in the modal.
I tried to make that the href link of the download button is equal to the visible image href, but it it doesn't seem to work...
Here you can see the full page code, but the part that interests me is this one:
<div id="myModal_12" class="modal">
<div class="modal-content">
<div class="Slide mySlides_12">
<div class="numbertext">1 / 3</div>
<img src="uploads/IMG_4946.JPG43879.jpg" class="little_image" style="width:50%;">
</div>
<div class="Slide mySlides_12">
<div class="numbertext">2 / 3</div>
<img src="uploads/IMG_4949.JPG21730.jpg" class="little_image" style="width:50%;">
</div>
<div class="Slide mySlides_12">
<div class="numbertext">3 / 3</div>
<img src="uploads/IMG_4950.JPG72501.jpg" class="little_image" style="width:50%;">
</div>
<!-- Next/previous controls -->
<div class="input-group-btn">
<a onclick="downloadFunction(this)">Download this image</a>
</div>
<span class="close cursor" onclick="closeModal(12)">
<img src="/images/close.png">
</span>
<a class="prev" style=" display: block; " onclick="plusSlides(-1, 12)">❮</a>
<a class="next" style=" display: block; " onclick="plusSlides(1, 12)">❯</a>
</div>
</div>
</div>
<script>
function downloadFunction(linkElement) {
var little_image = document.getElementsByClassName("little_image"); // Get all the images with that class
var right_image = $(little_image).not(":hidden"); // Get just the visible image
var src = right_image.src;
linkElement.href = src; // Set the link href on the visible image src
}
</script>
The JavaScript function return an "undefined" value...
Any help is very appreciated
To get the src attribute of an element you should use the attr(<attribute>) method. Given what you are trying to do, this logic could be reduced to:
linkElement.href = $('.little_image:visible').attr('src');
As Taplar has said you can use:
linkElement.href = $(".little_image:visible").attr("src");
However, there is an issue. The jQuery function returns an array and if you added another element that fits this criteria before this element that could cause an issue. Since attr returns for the first element of that array it may not work for the proper element you wanted it to. To fix this you could write this:
linkElement.href = $(".little_image:visible")[1].getAttribute("src"); // [1] the second element
If you want to get an attribute of element you should use attr function. In your problem you need to call like this;
linkElement.href = right_image.attr('src');
In addition, if you want to set an attribute then use .attr(attribute, value) like this:
right_image.attr("src", "https://www.example.com/")
I wanted to create a modal of sorts to open when a <li> offering additional information about a topic is clicked. I created a popUpTrigger that responds to a user "click" and then gathers the provided section (and all tags nested inside) and moves it to the popUp div that then appears on the page. I've taken necessary precaution in case the section is empty in which an alert will sound. However, the alert still fires when a section is not empty (it has text and contains an additional anchor tag). I'm not sure why this is happening.
When I console log, I see the nested anchor tag is being viewed by the browser as a separate entity to the section. I've tried nesting the anchor tag further within a div element and rewriting the javascript so the html of the nested anchor tag will be evaluated accordingly as part of the section but all to no avail. This backfiring only occurs when an additional anchor tag is included in the section element of the HTML.
HTML
<li id="card">
<a class="popUpTrigger" href="#">
Get a Library Card
<section class="hide">
<h6> How to Obtain a Library Card:</h6>
<p> Additional Info </p>
<p> Additional Info </p>
<p> Additional Info </p>
<p> Additional Info </p>
<a href="https://docs.wixstatic.com/ugd/858998_1fae2b5d06fa41a3ba3fcb493b349d19.pdf">
<img src="imgs/LibraryCardVector.png" alt="library card">
</a>
</section>
</a>
</li>
<div class="popUp">
<div>
<div id="popUpClose"> <button type="button" class="btn">X</button></div>
</div>
<div id="moreInfo">
<!--WILL BE FILLED IN WITH <section class="hide"> DATA ABOVE-->
</div>
</div>
JavaScript
$('a.popUpTrigger').on('click', function() {
$(this).addClass('selected');
if ($('.selected')) {
let messageArea = $('.selected > section.hide');
let strippedMessage = messageArea.text().replace(/(\r\n|\n|\r)/gm, "").replace(/\s/g, "");
let fullMessage = messageArea.html();
if (strippedMessage === "") {
alert("Sorry that page isn't available right now.");
$(this).removeClass('selected');
} else {
$('.popUp').css('display', 'block');
$('.popUp #moreInfo').html(fullMessage);
}
}
$('.popUp #popUpClose').on('click', function() {
$('.popUpTrigger').removeClass('selected');
$('.popUp').css('display', 'none');
});
});
I removed the children from your anchor, and instead used NEXT. Also your if statement was not needed. I left .selected in the code just in case you wanted to style the anchor when clicked.
$('a.popUpTrigger').on('click', function() {
$('a.popUpTrigger').removeClass("selected");
$(this).addClass('selected');
let messageArea = $(this).next("section");
let strippedMessage = messageArea.text().replace(/(\r\n|\n|\r)/gm, "").replace(/\s/g, "");
let fullMessage = messageArea.html();
if (strippedMessage === "") {
alert("Sorry that page isn't available right now.");
$(this).removeClass('selected');
} else {
$('.popUp').css('display', 'block');
$('.popUp #moreInfo').html(fullMessage);
}
$('.popUp #popUpClose').on('click', function() {
$('.popUpTrigger').removeClass('selected');
$('.popUp').css('display', 'none');
});
});
.selected{color:red;}
.hide{display:none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<li id="card">
<a class="popUpTrigger" href="#">
Get a Library Card </a>
<section class="hide">
<h6> How to Obtain a Library Card:</h6>
<p> Additional Info </p>
<p> Additional Info </p>
<p> Additional Info </p>
<p> Additional Info </p>
<a href="https://docs.wixstatic.com/ugd/858998_1fae2b5d06fa41a3ba3fcb493b349d19.pdf">
<img src="imgs/LibraryCardVector.png" alt="library card">
</a>
</section>
</li>
<div class="popUp">
<div>
<div id="popUpClose"> <button type="button" class="btn">X</button></div>
</div>
<div id="moreInfo">
<!--WILL BE FILLED IN WITH <section class="hide"> DATA ABOVE-->
</div>
</div>
You have the following code
<a href="#">
</a>
It is not valid to have nested anchors in HTML. So the browser breaks it up when it renders. That is why you are seeing it act weird.
You will need to stick the pop up code outside of the element.
<a class="popUpTrigger" href="#">
Get a Library Card
</a>
<section class="hide">
<p>Foo</p>
Bar
</section>
and reference it with next()
$(".popUpTrigger").on("click", function (e) {
e.preventDefault();
var anchor = $(this);
anchor.next('section').toggleClass("hide");
});
I've been looking for an elegant solution for a day now and I am pretty new to jQuery.
I would like to get each .figure and assign them an inline style where the value is contained inside the child element via a custom data- attribute :
<div>
<a href="#">
<div class="figure">
<img class="thumbnail" data-thumbnail="images-01-thumbnail.png" src="images-01.png" />
</div>
<div class="content">
<h3>Sale</h3>
<h4>Discover our latest styles</h4>
</div>
</a>
<a href="#">
<div class="figure">
<img class="thumbnail" data-thumbnail="images-02-thumbnail.png" src="images-02.png" />
</div>
<div class="content">
<h3>Free Shipping</h3>
<h4>When you buy xxxxxx</h4>
</div>
</a>
<a href="#">
<div class="figure">
<img class="thumbnail" data-thumbnail="images-03-thumbnail.png" src="images-03.png" />
</div>
<div class="content">
<h3>Free Shipping</h3>
<h4>When you buy xxxxxx</h4>
</div>
</a>
</div>
In other words, the results would be :
...
<div class="figure" style="background: url(images-01-thumbnail.png);">
...
<div class="figure" style="background: url(images-02-thumbnail.png);">
...
<div class="figure" style="background: url(images-03-thumbnail.png);">
...
Also, I'm always ready something about jQuery so if you have any books about JavaScript or jQuery to suggest, that is always appreciated.
You can iterate over all .picture elements, find the image descendant and read its data attribute:
$('.figure').css('background', function() {
return 'url(' + $(this).children('img').data('thumbnail') + ')';
});
Some methods, like .css even accept functions so that you can iterate over the selected elements implicitly.
Reference: .css, .children, .data
you can iterate over each item with the class thumbnail and set the css property to the closet div.
$('.thumbnail').each(function() {
var $this = $(this),
$background = $this.data('thumbnail');
$this.closest('.figure').css({background : $background} )
});
This should work
$("[data-thumbnail]").each(function ()
{
var $this = $(this), url = $this.data("thumbnail");
$this.parents(".figure").css("background-image", 'url("' + url + '")');
});
How about this (Working code example: http://jsfiddle.net/jpbH2/2/):
var pathToImages = "/";
$(".figure img").each(function(){
$(this).parent().css({"background": "url(" + pathToImages + $(this).data('thumbnail') +")"})
});
Edit
I actually didn't notice the data-thumbnail. Edited my answer above
This seems like it should be easy. I have a html snippet that I wish to locate and modify in place via javascript. But not just the innerHTML; I want to replace the entire element. Example:
<div class="content">
<div class="item">
<img src="images/pic1.jpg" />
<a class="clicker" onclick="javascript:doSomethingUseful(##);">Do ##!</a>
<h3>title</h3>
<p>description</p>
</div>
</div>
After page load, I want to grab the <a class="clicker" ...>Now!</a> and replace it with three instances like:
<div class="content">
<div class="item">
<img src="images/pic1.jpg" />
<a class="clicker" onclick="javascript:doSomethingUseful(1);">Do 1!</a>
<a class="clicker" onclick="javascript:doSomethingUseful(2);">Do 2!</a>
<a class="clicker" onclick="javascript:doSomethingUseful(3);">Do 3!</a>
<h3>title</h3>
<p>description</p>
</div>
</div>
Using prototype.js, I can easily do $$('.clicker') and get an array with the element. I can use .innerHTML and get the 'Do ##!' and change it. But I want, nay, need the entire element to insert it in place. I can go through weird machinations of siblings and parent, and walk back around the nodes to eventually get what I need, and I will do that. It just seems that I am missing something here that would make this easy.
If it is not the only HTML generation you want to run in your page, you may consider a javascript templating engine.
There are several advantages, the main one being a clear cut between the HTML view and the JS logic.
There are plenty of these engines available for every taste.
Here is how it would look with prototype.js and the PURE template engine:
$$('div.content')[0].render([1,2,3], {
'a.clicker':{
'id <-':{
'.':'Do #{id}!',
'#onclick':'javascript:doSomethingUseful(#{id});'
}
}
});
In IE you can set outerHTML. In FF, you can use this:
http://snipplr.com/view/5460/outerhtml-in-firefox/
So the way I would do this is:
Iterate over all the anchors with class clicker that are inside a div with class item which are inside class content
To each one, add a function which will hide that anchor, and then append the 3 anchors you want
So here's what my html chunk looks like:
<div class="content">
<div class="item">
<img src="images/pic1.jpg" />
<a class="clicker" href='#'>Do ##!</a>
<h3>title</h3>
<p>description</p>
</div>
</div>
And I need to include Prototype:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js"></script>
And a variable to hold your replacement html, and a dummy function so what we insert works:
var myReplacementHtml = '<a class="clicker" onclick="doSomethingUseful(1);" href="#">Do 1!</a>';
myReplacementHtml += ' <a class="clicker" onclick="doSomethingUseful(2);" href="#">Do 2!</a>';
myReplacementHtml += ' <a class="clicker" onclick="doSomethingUseful(3);" href="#">Do 3!</a>';
function doSomethingUseful(n) {
alert(n);
return false;
}
Then here's my code, you may find it useful to get the backstory on how these work: $$, Element.observe, Element.hide, Element.insert, Event.stop:
<script type="text/javascript">
Event.observe(window, 'load', function(){
$$('.content .item a.clicker').each(function(item){
item.observe('click', function(evt){
item.hide();
Element.insert(item, {after: myReplacementHtml});
});
Event.stop(evt);
});
});
</script>
You can add and append elements.
function doSomethingUseful(val) {
var ele = document.getElementById('myDiv');
var newdiv = document.createElement('div');
var divIdName = 'my'+num+'Div';
newdiv.setAttribute('id',divIdName);
ni.appendChild(newdiv);
}