I am a newbie in javascript, so be aware. I already searched on this website for a solution of this issue but I was not able to find the working solution.
The problem is on my development website: https://famnabuurs.nl (it is on the homepage). I use Wordpress with DIVI and now some javascript.
The three columns I created have a similar setup. The columns all have an id so I can manage the behaviour. When you hover over a column some changes should be initiated: background-color of the column should switch to black, stripe background should change from blue to black and the image in the background should grow. That all works for for an individual column. But now I have 3 columns it only works at the last one. What I saw form other issues on this website it will have to do with the definition of my variables, but no idea where to update my script.
My html looks like this, the same for every column except for the id:
<div id='research'>
<div class='textblock'>
.. my text ...
</div>
<div class='myimage koek-achtergrond'>
.. my background image ...
</div>
<div class='myimage koek-stripe'>
.. my other image ...
</div>
</div>
Here is my generic code:
<script>
function mouseover() {
console.log('mouse over this column: ',this.id);
var column = document.getElementById(this.id);
column.style.backgroundColor = 'black';
var stripe = document.getElementById(this.id).getElementsByClassName('koek-stripe')[0];
stripe.classList.add('koek-stripe-hovered');
var background = document.getElementById(this.id).getElementsByClassName('koek-achtergrond')[0];
background.classList.add('koek-transform');
}
function mouseleave() {
console.log('mouse leaves this column: ',this.id);
var column = document.getElementById(this.id);
column.style.backgroundColor = 'var(--primary-blue-color)';
var stripe = document.getElementById(this.id).getElementsByClassName('koek-stripe')[0];
stripe.classList.remove('koek-stripe-hovered');
var background = document.getElementById(this.id).getElementsByClassName('koek-achtergrond')[0];
background.classList.remove('koek-transform');
console.log('classList after leaving: ',background.classList);
}
</script>
In every column I add a short script, where only the columname is changed, in line with the name in the html:
<script>
var columnname = 'research';
columnElement = document.getElementById(columnname);
columnElement.onmouseover = function() {
columnElement.addEventListener('mouseover', mouseover);
}
columnElement.onmouseleave = function() {
columnElement.addEventListener('mouseleave', mouseleave);
}
console.log('kolomdetails: ',columnElement);
</script>
In my opinion it is not relevant to show the css in this case, since the issue refers to the javascript. The problem is that the classes that should be added in the generic script only are applied in the last column. The question is: why do they not remain in de first two columns?
I saw some remarks in other threads indicating it is the classical error in Javascript. So I hope this can help me understand variables in a better way.
Consider using event delegation. Here's a minimal reproducable example to work with:
[`mouseover`, `mouseout`].forEach(h => document.addEventListener(h, handle));
function handle(evt) {
const el2Handle = evt.target.closest(
[`.textblock`, `.koek-achtergrond`, `.koek-stripe`]
.find(c => evt.target.closest(c)) );
if (el2Handle) {
el2Handle.style.color = evt.type === `mouseover` ? `red` : ``;
}
}
#research div {
cursor: pointer;
}
<div id='research'>
<div class='textblock'>
.. my text ...
</div>
<div class='myimage koek-achtergrond'>
.. my background image ...
</div>
<div class='myimage koek-stripe'>
.. my other image ...
</div>
</div>
Yeesssss, this works fine. I took the answer as pointed out below and tailored it to my final solution:
<script>
document.addEventListener(`mouseover`, handle);
document.addEventListener(`mouseout`, handle);
function handle(evt) {
const origin = evt.target;
if ([`.koek-textblock`, `.koek-achtergrond`, `.koek-stripe`].find( c => origin.closest('.koek-kolom'))) {
kolom = origin.closest('.koek-kolom');
kolom.style.backgroundColor = evt.type === `mouseover` ? 'black' : ``;
stripe = kolom.getElementsByClassName('koek-stripe')[0];
stripe.style.backgroundImage = evt.type === `mouseover` ? "url('https://famnabuurs.nl/wp-content/uploads/2022/10/stripe_zwart.png')": ``;
backgroundimage = kolom.getElementsByClassName('koek-achtergrond')[0];
backgroundimage.style.transform = evt.type === `mouseover` ? "scale(1.2) translate(-80px, 40px)" : ``;
}
}
</script>
I also added the class 'koek-kolom' to the column so I am sure I find the right parent.
If you want you can see the result on https://famnabuurs.nl/afbeelding-hoveren-improved/
An image is display to my webpage, all having the same class name.
I try hiding a particular one with it is clicked but any time I click that particular class, all the classes are affected
I used PHP to echo the image to webpage. I have tried all I could but not working.
<img class="media_image" onclick="hide()" src="media/<?php echo $media?>"/>
<script>
function hide(){
var divs = document.getElementsByClassName("media_image");
for(var i = 0; i <= divs.length; i++){
console.log("Item: ", i);
}
}
</script>
You can change onclick="hide()" to onclick="hide(this)" to pass the element into the function and then the function can be changed to accept it.
function hide (element) {
//do whatever with element
element.style.display = "none";
}
you could add a second special class to every image in the webpage like :
<img class="myimg img-1">
<img class="myimg img-2">
<img class="myimg img-3">
// ect
I am building a application where user can write something inside input and it will be converted to a image they can download.
I use html2canvas.js for converting text to a downloadable image (this part works fine)
Currently it take the text inside <div id="talltweets"></div> and converts it to a image, but what I want is to be able to change the text/image when writing text inside input.
I tried to make a function called edValueKeyPress and it takes whats inside the input and adds it into <div id="talltweets"></div>, Now how can I take the text inside #talltweets and add it to <img id="textScreenshot"/> in realtime/when writing?
This is my code:
html2canvas(document.getElementById("talltweets"), {
onrendered: function(canvas) {
var screenshot = canvas.toDataURL("image/png");
document.getElementById("textScreenshot").setAttribute("src", screenshot);
}
});
function edValueKeyPress() {
var edValue = document.getElementById("body");
var s = edValue.value;
var lblValue = document.getElementById("talltweets");
lblValue.innerText = s;
}
<script src="http://files.codepedia.info/uploads/iScripts/html2canvas.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>
<input type="text" onKeyPress="edValueKeyPress()" onKeyUp="edValueKeyPress()" id="body">
<div id="talltweets"></div>
<!-- The PNG image will be added here-->
<div>
<img id="textScreenshot" />
</div>
Basically, you need to wrap that whole rendering step of the process into a function that can then be called with the keypress event. You're already on the right track - here's one way you could implement this (plus a few miscellaneous code improvements; also, I had to change the URL for html2canvas to pull from a different cdn, as the original one wasn't loading correctly from SO):
// If we store these, we only need to query the dom once, not on every update
var tallTweets = document.getElementById('talltweets');
var screenshotImg = document.getElementById('textScreenshot');
var textInput = document.getElementById('body');
// Note - it wouldn't surprise me if html2canvas has a specific API
// for doing this kind of update. Worth checking their documentation for.
function updateImage() {
html2canvas(tallTweets, {
onrendered: function(canvas) {
var screenshot = canvas.toDataURL("image/png");
screenshotImg.setAttribute("src", screenshot);
}
});
};
function edValueKeyPress() {
tallTweets.innerText = textInput.value || '';
updateImage();
}
updateImage();
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>
<input type="text" onKeyPress="edValueKeyPress()" onKeyUp="edValueKeyPress()" id="body" placeholder="Type something!">
<div id="talltweets"></div>
<!-- The PNG image will be added here-->
<div>
<img id="textScreenshot" alt="Generated screenshot" />
</div>
You could also make it even simpler by combining the two functions into one - IE, moving tallTweets.innerText = textInput.value into updateImage, and then binding the event listener to updateImage instead. But keeping them separated has its advantages, especially if you might want to reuse updateImage elsewhere.
I am trying to toggle images from the thumbnail to the feature image when the thumb nail is clicked. Currently when its clicked the images will swap but I cant get them to swap back with the thumb nail is clicked on again. I've tried using toggle but when the thumb nail is clicked on it would remove the image completely and I couldnt get any image to return. Currently this will switch the images but not switch or toggle them back on click.
$(".browseTable").on('click', 'td', function () {
var thumbNail = $(this).parent('tr').find('img').attr('src');
var feature = $('#featureImg img').attr('src');
$('#featureImg img').fadeOut(400, function () {
$(this).fadeIn(400)[0].src = thumbNail;
});
});
You can use data for store source string and toggling images
preview on : https://jsfiddle.net/5kxf65Lx/
<img src="source1.jpg" data-srcfirst="source1.jpg" data-srcsecond="source2.jpg" />
<script type="text/javascript">
$('img').click(function(){
var loaded = $(this).attr('src')
var first = $(this).data('srcfirst')
var second = $(this).data('srcsecond')
if(loaded == first){
$(this).attr('src' , second)
} else {
$(this).attr('src' , first)
}
})
Try this. When the parent is clicked we toggle both children. The large version starts off hidden.
<div class="toggle js-toggle">
<img src="http://www.placehold.it/100x100" alt="" class="toggle__thumb js-toggle-image"/>
<img src="http://www.placehold.it/500x500" alt="" class="toggle__active js-toggle-image" style="display: none" />
</div>
The jQuery
$('.js-toggle').on('click', function() {
$(this).find('.js-toggle-image').toggle();
});
https://jsfiddle.net/uoLv2nkh/1/
Or an only CSS way if you only care about when the user is clicking.
https://jsfiddle.net/uoLv2nkh/
You can achieve your target via setting src of image in css.
.imageOne{
content:url(YOUR SOURCE);
}
.imageTwo{
content:url(YOUR SOURCE);
}
add class to your image element in start
check if element exist by either class if exist toggle() to another, this will change the image back to another.
And use toggle() like following example
$(".browseTable").on('click', 'td', function () {
//var thumbNail = $(this).parent('tr').find('img').attr('src');
//var feature = $('#featureImg img').attr('src');
//$('#featureImg img').fadeOut(400, function () {
// $(this).fadeIn(400)[0].src = thumbNail;
//});
$('#featureImg img').find('.imageOne, .imageTwo').toggle();
});
I am able to use toggle simply to change one element to another. etc. hope it will help you.
Is it possible to set the equivalent of a src attribute of an img tag in CSS?
I just created script that shows/hides (toggles) block of HTML. There are four buttons that each can toggle its HTML block. When any HTML block is opened, but user has been clicked on other button than that HTML block's associated button... it hides that HTML block and shows new one.
Here is what I have at the moment:
$('.btn_add_event').click( function() {
$('.block_link, .block_photos, .block_videos').hide();
$('.block_event').toggle();
});
$('.btn_add_link').click( function() {
$('.block_event, .block_photos, .block_videos').hide();
$('.block_link').toggle();
});
$('.btn_add_photos').click( function() {
$('.block_event, .block_link, .block_videos').hide();
$('.block_photos').toggle();
});
$('.btn_add_videos').click( function() {
$('.block_event, .block_link, .block_photos').hide();
$('.block_videos').toggle();
});
Any ideas how to reduce code size? Also, this script isn't very flexible. Imagine to add two new buttons and blocks.
like Sam said, I would use a class that all the blocks share, so you never have to alter that code. Secondly, you can try 'traversing' to the closest block, therefore avoiding it's name. That approach is better than hard coding each specific block, but if the html dom tree changes you will need to refactor. Last, but best, you can pass in the class name desired block as a variable to the function. Below is something you can copy paste that is close to what you started with.
$('.myAddButtonClass').click( function() {
$('.mySharedBlockClass').filter(':visible').hide();
//find a good way to 'traverse' to your desired block, or name it specifically for now.
//$(this).closest(".mySharedBlockClass").show() complete guess
$('.specificBlockClass').show();
});
I kept reading this "When any HTML block is opened, but user has been clicked on other button than that HTML block's associated button" thinking that my eyes were failing me when Its just bad English.
If you want to make it more dynamic, what you can do is add a common class keyword. Then
when the click event is raise. You can have it loop though all the classes that have the
keyword and have it hide them all (except the current one that was clicked) and then show the current one by using the 'this' keyword.
you can refer below link,
http://chandreshmaheshwari.wordpress.com/2011/05/24/show-hide-div-content-using-jquery/
call function showSlidingDiv() onclick event and pass your button class dynamically.
This may be useful.
Thanks.
try this
$('input[type=button]').click( function() {
$('div[class^=block]').hide(); // I resumed html block is div
$(this).toggle();
});
Unfortunatly I couldn't test it, but if I can remember right following should work:
function toogleFunc(clickObject, toogleTarget, hideTarget)
{
$(clickObject).click(function()
{
$(hideTarget).hide();
$(toogleTarget).toggle();
});
}
And the call:
toogleFunc(
".btn_add_videos",
".block_videos",
".block_event, .block_link, .block_photos"
);
and so far
Assuming the buttons will only have one class each, something like this ought to work.
var classNames = [ 'btn_add_event', 'block_link', 'block_photos', 'block_videos' ];
var all = '.' + classNames.join(', .'); // generate a jquery format string for selection
$(all).click( function() {
var j = classNames.length;
while(j--){
if( this.className === classNames[j] ){
var others = classNames.splice(j, 1); // should leave all classes but the one on this button
$('.' + others.join(', .')).hide();
$('.' + classNames[j]).toggle();
}
}
}
All the buttons have the same handler. When the handler fires, it checks the sender for one of the classes in the list. If a class is found, it generates a jquery selection string from the remaining classes and hides them, and toggles the one found. You may have to do some checking to make sure the strings are generating correctly.
It depends by how your HTML is structured.
Supposing you've something like this
<div class="area">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
...
<div class="sender">
<a class="one"></a>
<a class="two"></a>
<a class="three"></a>
</div>
You have a class shared by the sender and the target.
Your js would be like this:
$('.sender > a').click(function() {
var target = $(this).attr('class');
$('.area > .' + target).show().siblings().hide();
});
You show your real target and hide its siblings, which aren't needed.
If you put the class postfixes in an array, you can easily make this code more dynamic. This code assumed that it doesn't matter in which order toggle or hide are called. If it does matter, you can just remember the right classname inside the (inner) loop, and toggle that class after the loop.
The advantage to this approach is that you can extend the array with an exta class without needing to modifying the rest of the code.
var classes = new Array('videos', 'event', 'link', 'photos');
for (var i = 0; i < classes.length; ++i)
{
$('.btn_add_' + classes[i]).click(
function()
{
for (var j = 0; j < classes.length; ++j)
{
if (this.hasClass('btn_add_' + classes[j]))
{
$('.block_' + classes[j]).toggle();
}
else
{
$('.block_' + classes[j]).hide();
}
}
});
}
You could make this code more elegant by not assigning those elements classes like btn_add_event, but give them two classes: btn_add and event, or even resort to giving them id's. My solution is based on your description of your current html.
Here is what I think is a nice flexible and performant function. It assumes you can contain your links and html blocks in a parent, but otherwise it uses closures to precalculate the elements involved, so a click is super-fast.
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js" ></script>
<script type="text/javascript">
// Enables show/hide functionality on click.
// The elements within 'container' matching the selector 'blocks' are hidden
// When elements within 'container' matching the selector 'clicker' are clicked
// their attribute with the name 'clickerAttr' is appended to the selector
// 'subject' to identify a target, usually one of the 'blocks'. All blocks
// except the target are hidden. The target is shown.
//
// Change clickerAttr from 'linkTarget' to 'id' if you want XHTML compliance
//
// container: grouping of related elements for which to enable this functionality
// clicker: selector to element type that when clicked triggers the show/hide functionality
// clickerAttr: name of the DOM attribute that will be used to adapt the 'subject' selector
// blocks: selector to the html blocks that will be shown or hidden when the clicker is clicked
// subject: root of the selector to be used to identify the one html block to be shown
//
function initToggle(container,clicker,clickerAttr,blocks,subject) {
$(container).each(
function(idx,instance) {
var containerElement = $(instance);
var containedBlocks = containerElement.find(blocks);
containerElement.find(clicker).each(function(idxC, instanceClicker) {
var tgtE = containerElement.find(subject+instanceClicker.getAttribute(clickerAttr));
var clickerBlocks = containedBlocks.not(tgtE);
$(instanceClicker).click(function(event) {
clickerBlocks.hide();
tgtE.toggle();
});
});
// initially cleared
containedBlocks.hide();
}
);
}
$(function() {
initToggle('.toggle','a.link','linkTarget','div.block','div.');
});
</script>
</head>
<body>
Example HTML block toggle:
<div class="toggle">
a <br />
b <br />
c <br />
<div class="A block"> A </div>
<div class="B block"> B </div>
<div class="C block"> C </div>
</div> <!-- toggle -->
This next one is not enabled, to show scoping.
<div class="toggle2">
a <br />
<div class="A block">A</div>
</div> <!-- toggle2 -->
This next one is enabled, to show use in multiple positions on a page, such as in a portlet library.
<div class="toggle">
a <br />
<div class="A block">A</div>
</div> <!-- toggle (2) -->
</body>
</html>