jQuery Hide and Show Attr Src Image not switching as intended - javascript

so I searched around and edited a show/hide jquery code I found, and it works just fine except the html img attribute does not get replaced when I click on it.
My jQuery code:
<script>
$(document).ready(function() {
var button = $('#hideButton');
//check the cookie when the page loads
if ($.cookie('currentToggle') === 'hidden') {
togglePanel(button, false);
}
else {
togglePanel(button, true);
}
//handle the clicking of the show/hide toggle button
button.click(function() {
//toggle the panel as required, base on current state
if (button.attr('src') === "images/expand.gif") {
togglePanel($(this), true);
}
else {
togglePanel($(this), false);
}
});
});
function togglePanel(button, show) {
var panel = $('#panel');
if (show) {
panel.removeClass('hidden');
button.attr('src','images/collapse.gif');
$.cookie('currentToggle', '', { path: '/' });
}
else {
panel.addClass('hidden');
button.attr('src','images/expand.gif');
$.cookie('currentToggle', 'hidden', { path: '/' });
}
}
</script>
My HTML code:
<a id="hideButton" href="#"><img src="images/collapse.gif"></a>
<div id="panel">
<p>
Test
</p>
</div>
When I look at my firebug console, it shows the a href src attribute changing like so "<a ... src="extend.gif">" but not the actual "<img src="">" element itself. How do I fix this? Thank you.

button refers to the a tag, if you want to change the img src then you need to use the correct selector :
$('img',button).attr('src', 'whatever.gif');
In your code :
if (button.attr('src') === "images/expand.gif") {
should be :
if ($('img', button).attr('src') === "images/expand.gif") {
You need to do the same thing in the togglePanel function too.

to make your function work - you will want to change it to instead update the src attribute of the IMG element. not the anchor tag... you can do that like so:
function togglePanel(button, show) {
var panel = $('#panel');
if (show) {
panel.removeClass('hidden');
button.find('img').attr('src','images/collapse.gif');
$.cookie('currentToggle', '', { path: '/' });
}
else {
panel.addClass('hidden');
button.find('img').attr('src','images/expand.gif');
$.cookie('currentToggle', 'hidden', { path: '/' });
}
}
the .find('img') will return the child objects matching the selector of that parameter - for the element you call it on... in this case the anchor tag stored in your variable button...
a few things i would like to note: swapping src attributes might be effective, but you will notice a "flashing" on slower internet connections or as the image sizes gets larger. this is because you are actually having the user make a request and load that image.
the recommended way would be to do this like Diodeus said - utilizing css classes and my preference would be image sprites - that will negate the 'flashing' and minimize resource load times after the DOM has completed loading.
EDIT:
RafH has a good point! - you will also have to update the if conditional ( i overlooked ) to check the image source - not the anchors source. as he suggested

Sorry if i didn't understand your question correctly.
You want to show/hide the panel when there is clicked on the anchor, when it's clicked also the image should change.
Why not make a layout for the anchor itself and use background url to change it?
#hideButton
{
width: 25px;
height: 25px;
display: inline-block;
background: url('http://png.findicons.com/files/icons/2338/reflection/128/collapse_arrow.png');
background-size:25px 25px;
}
.reverse
{
-moz-transform: scaleY(-1);
-o-transform: scaleY(-1);
-webkit-transform: scaleY(-1);
transform: scaleY(-1);
//you can place a other image in here.
margin-bottom: 2px;
}
Now i have used mirrored image on click, you can use any image you want.
Now the jQuery code:
$(document).ready(function() {
$("#hideButton").click(function()
{
if($("#panel").is(":visible"))
{
$('#panel').slideUp('slow');
$('#hideButton').addClass('reverse');
}
else
{
$('#panel').slideDown('slow');
$('#hideButton').removeClass('reverse');
}
})
})
I use the premade animation SlideUp and slideDown. again, you can change this to your needs.
and finally the HTML:
<a id="hideButton" href="#" ></a>
<div id="panel">
<p>
Test
</p>
</div>
jsFiddle

Related

Avoid flickering when changing existing DOM elements on page load event

I have the following DOM element change function using vanilla JavaScript where I change the span element that contains some text string of the DOM with a page load event.
With the following code, the DOM elements are changed as expected. However, they still see a minimal fraction of flickering before the DOM element change for the variable desktop and mobile.
Example of the flickering scenario:
I see the tag span "Text I want to change" for a fraction of second.
I see the changed tag span "text1 changed" after the content has fully loaded.
I think this is happening because the DOM changes are applied when the DOM content of the page is fully loaded. I would like to hide the existing tag elements until the changes have been applied and then display them.
The elements structure for desktop and mobile I want to manipulate is like the following:
<span class="first-headline target-span">Text I want to change</span>
See the concept below:
var changesObj = {
"us": {
title: "text1 changed"
},
"eu": {
title: "text2 changed"
}
};
function changes() {
var webshop = changesObj[window.location.pathname.split('/')[1]];
console.log(webshop);
var changesText;
if (!webshop) {
console.log('webshop not found');
}
changesText = webshop.title;
if (document.querySelector('.target-span').innerText.length > 0) {
var desktop = document.querySelector('.target-span');
console.log(desktop);
desktop.innerText = changesText;
console.log(desktop.innerText);
console.log("applied changes for dekstop");
}
if (document.querySelector('.target-span').innerText.lenght > 0) {
var mobile = document.querySelector('.target-span');
mobile.innerText = changesText;
console.log(mobile.innerText);
console.log("applied changes for mobile");
}
}
function invokeChanges() {
document.addEventListener("DOMContentLoaded", function () {
changes();
});
}
invokeChanges();
Is there a way to initially hide the DOM element until the change to the existing element has been applied and then show it?
I was thinking of using something inline CSS rules like the following:
Set .style.visbility='hidden' and when the text content is changed to show it with .style.visbility='visble'.
But I'm not sure how this solution should be appropriately implemented in my code.
There are a few reasons as to why it's flickering, but two preventative steps you can take:
Use defer on your script tag <script defer>, as this lets the browser handle the order your scripts are run instead of DOMContentLoaded. You also get to avoid the changes wrapper function.
As suggested by this question (and your own reasoning) attach inline CSS / a CSS file to the page to set the text as invisible, then mark it as visible
If it doesn't affect the layout of your page too much, you can also opt to dynamically generate the element instead.
However, do note that regardless of any of these, these still require JS to be executed and may still have a delay. If you are able to use it, you may be interested in prerendering your webpage - from your JS code, it looks for the route name if its eu or us, which means your page is pre-renderable.
Quick & Dirty:
Place the script tag just below your span tag:
<span class="first-headline target-span">Text I want to change</span>
<script>
var changesObj = {
"us": {
title: "text1 changed"
},
"eu": {
title: "text2 changed"
}
};
function changes() {
var webshop = changesObj[window.location.pathname.split('/')[1]];
console.log(webshop);
var changesText;
if (!webshop) {
console.log('webshop not found');
}
changesText = webshop.title;
if (document.querySelector('.target-span').innerText.length > 0) {
var desktop = document.querySelector('.target-span');
console.log(desktop);
desktop.innerText = changesText;
console.log(desktop.innerText);
console.log("applied changes for dekstop");
}
if (document.querySelector('.target-span').innerText.lenght > 0) {
var mobile = document.querySelector('.target-span');
mobile.innerText = changesText;
console.log(mobile.innerText);
console.log("applied changes for mobile");
}
}
changes();
</script>
This way you avoid the asynchronous code part.
In any case you need to wait until the DOM has been loaded before you can manipulate it. Using an even listener for DOMContentLoaded would be the way to go. So, three things need to happen:
Wait for the DOM to load
Find the elements and change the text
Make the elements visible. You can either use the property visibility: hidden or display: none. Difference is that with visibility: hidden the element will still take up space. So, the choice depends on the context.
In the first example I add a timeout so that you can see what the page looks like just before the text is changed. I also styled the <p> (display: inline-block) so that you can see the size of the hidden span.
window.location.hash = "us"; // for testing on SO
var changesObj = {
"us": { title: "text1 changed" },
"eu": { title: "text2 changed" }
};
function changes(e) {
//let webshop = changesObj[window.location.pathname.split('/')[1]];
let webshop = changesObj[window.location.hash.substring(1)]; // for testing on SO
if (webshop) {
[...document.querySelectorAll('.target-span')].forEach(span => {
span.textContent = webshop.title;
span.classList.add('show');
});
}
}
document.addEventListener('DOMContentLoaded', e => {
setTimeout(changes, 1000);
});
p {
border: thin solid black;
display: inline-block;
}
.target-span {
visibility: hidden;
}
.target-span.show {
visibility: visible;
}
<p>
<span class="first-headline target-span">Text I want to change</span>
</p>
<p>
<span class="first-headline target-span">Text I want to change</span>
</p>
In the second example I combined all the code into one HTML page. Notice that the style is defined in the header. So, when the DOM is passed the CSS will be passed as well without having to load a external style-sheet (well, there are tricks for that as well, but out of scope for this answer).
<html>
<head>
<style>
p {
border: thin solid black;
}
.target-span {
visibility: hidden;
}
.target-span.show {
visibility: visible;
}
</style>
<script>
window.location.hash = "us"; // for testing on SO
var changesObj = {
"us": {title: "text1 changed"},
"eu": {title: "text2 changed"}
};
function changes(e) {
//let webshop = changesObj[window.location.pathname.split('/')[1]];
let webshop = changesObj[window.location.hash.substring(1)]; // for testing on SO
if (webshop) {
[...document.querySelectorAll('.target-span')].forEach(span => {
span.textContent = webshop.title;
span.classList.add('show');
});
}
}
document.addEventListener('DOMContentLoaded', changes);
</script>
</head>
<body>
<p>
<span class="first-headline target-span">Text I want to change</span>
</p>
<p>
<span class="first-headline target-span">Text I want to change</span>
</p>
</body>
</html>

Disable/Enable CSS on webpage using Javascript

According to This page I was able to remove all the CSS preloaded and added on the webpage using that. I wanted to implement a button system where "onclick" = enable/disable webpage CSS even the ones pre-loaded by my web-host. I would like to eliminate the style tags to prevent lags for my website users. I prefer using the script that I have linked above unless there is another alternative that works better. Is it possible to enable CSS onclick the same button to disable? If not is it possible, can it be done with this quick? example with the preferred script below:
if (disable) {
style = "disable";
} else {
location.reload();
}
PREFERRED SCRIPT:
function removeStyles(el) {
el.removeAttribute('style');
if(el.childNodes.length > 0) {
for(var child in el.childNodes) {
/* filter element nodes only */
if(el.childNodes[child].nodeType == 1)
removeStyles(el.childNodes[child]);
}
}
}
removeStyles(document.body);
What about a different aproach?
Add initially a class to a body called 'styled' for example
<body class="styled">
use it as a main selector in your css definitions
<style>
.styled a { ... }
.styled h1 { .... }
</style>
then an example jquery script to toggle the class:
<script>
$(function() {
$('#myswitch').click(function() {
$('body').toggleClass('styled');
});
});
</script>
when class is present, the page will be styled, when absent there will be no styling.
Of coures there could be better aproach, but this is the first thing which pops up in my mind
To remove all style on an element, you could do
function removeStyles(el) {
el.style = {};
}
If you want to enable/disable the CSS on the page, then the goal is not to merely remove all the styles on the page, but you will need to save them somewhere also so they can be recalled when the user re-clicks the button. I would recommend having jQuery to help you with this, and it could be done the following way:
var style_nodes = $('link[rel="stylesheet"], style');
style_nodes.remove();
$('*').each(function(num, obj) {
var style_string = $(obj).attr("style");
if (style_string) {
$(obj).data("style-string", style_string);
$(obj).attr("style", "");
}
});
Now you've saved the stylesheets and style DOM nodes inside of style_nodes, and the actual style attribute inside of a jQuery data attribute for that specific DOM node. When you click to add the CSS back to the page, you can do the following:
$('head').append(style_nodes);
$('*').each(function(num, obj) {
if ($(obj).data("style-string"))
$(obj).attr("style", $(obj).data("style-string"));
});
Check out this JS Fiddle I put together to demonstrate it:
https://jsfiddle.net/5krLn3w1/
Uses JQuery, but I'm sure most frameworks should give you similar functionality.
HTML:
<h1>Hello World</h1>
Turn off CSS
Turn on CSS
JS:
$(document).ready(function() {
$('a#turn_off').click(function(evt) {
evt.preventDefault();
var css = $('head').find('style[type="text/css"]').add('link[rel="stylesheet"]');
$('head').data('css', css);
css.remove();
});
$('a#turn_on').click(function(evt) {
evt.preventDefault();
var css = $('head').data('css');
console.info(css);
if (css) {
$('head').append(css);
}
});
});
CSS:
body {
color: #00F;
}
h1 {
font-size: 50px;
}

Toggling Background Color on Click with Javascript

I am working on a class project and need to be able to toggle the background color of a transparent png on click. I have been working through a number of examples from the site, but I can't get it working. I am a total novice at Javascript and haven't had luck trying to plug in jQuery code either.
Here is the targeted section:
<div class="expenseIcon"><a href="#">
<img src="images/mortgage.png"></a><br/>
<p>Rent or Mortgage</p>
</div>
On clicking the linked image, the goal is for the background on the image to change to green. Clicking it again would change it back to the default, white. Here's the CSS I'd like to toggle on/off with click.
.colorToggle {
background: #A6D785;
}
I had tried adding class="iconLink" to the href and class="iconBox" to the image with the following Javascript adapted from another post, but it didn't work.
var obj = {};
$(document).ready(function () {
$(".iconLink").click(function () {
var text = $(this).find(".iconBox");
obj.var1 = text;
//alert(obj.var1);
//return false;
$('.iconBox').removeClass('colorToggle');
$(this).addClass('colorToggle')
});
});
Any advice would be greatly appreciated!
Let's break down what is happening with your current code when you click the link.
var obj = {};
$(document).ready(function () {
$(".iconLink").click(function () {
var text = $(this).find(".iconBox");
obj.var1 = text;
$('.iconBox').removeClass('colorToggle');
$(this).addClass('colorToggle')
});
});
JQuery finds all elements with the classname "iconBox". In your case, this is the img element. The reference to that element is then saved in "obj.var1". You do not end up doing anything with this reference, so these two lines can be removed.
All elements with the class "iconBox" have the class "colorToggle" removed. Your img element didn't have this class on it, so nothing happens.
The class "colorToggle" is added to the anchor element. Yes! Now the element wrapping the img has a background color.
Unfortunately, clicking the anchor tag again won't do anything, since the anchor tag will already have the "colorToggle" class and all we would be doing would be trying to add it again. Hmm. Let's try changing addClass to toggleClass. Here's our new code:
$(document).ready(function () {
$(".iconLink").click(function () {
$(this).toggleClass('colorToggle');
}
});
Also, note that because we're working with the anchor element, the p element won't be affected by this change. If you want the entire div to change background colors, use this line instead:
$(".expenseIcon").toggleClass('colorToggle');
Using the given markup:
<!-- to toggle the bg-color onClick of anchor tag -->
<div class="expenseIcon">
<a href="#">
<img src="images/mortgage.png">
</a>
<br/>
<p>Rent or Mortgage</p>
</div>
since the question asks for javascript, heres an option for updating the background-color of an element using the built-in js.style method
//get a handle on the link
//only one element w/ className 'expenseIcon'
//first child of 'expenseIcon' is the anchor tag
var link = document.getElementsByClassName('expenseIcon')[0].children[0];
//get a handle on the image
var image = link.children[0];
//listen for click on link & call bgUpdate()
link.addEventListener('click', bgUpdate, false);
function bgUpdate() {
if(image.style.backgroundColor === 'lightgoldenrodyellow'){
image.style.backgroundColor = 'aliceblue';
} else if (image.style.backgroundColor === 'aliceblue') {
image.style.backgroundColor = 'lightgoldenrodyellow';
}
else console.log('image bgColor: ' + image.style.backgroundColor);
}
a similar example
css
.expenseIcon{
background: red;
}
.colorToggle {
background: blue;
}
jquery
$(".expenseIcon").click(function () {
$('.expenseIcon').toggleClass('colorToggle');
});
By default, the div will have expenseIcon background. ToggleClass will toggle the div class with colorToggle so will override the previous color.
You don't need an hyperlink tag A to manage clicks, just put it on the DIV.

IF ELSE Hover statement only works on second hover

I have a menu, that when you roll over the image the image changes, unless the image has an active class attached. My problem is that the image only changes on the SECOND ROLL OVER not the FIRST. Any ideas why this is.
$("#contact").hover(function () {
if ($("#contact").is(".active")) {
$("#contact img").attr("src","Images/Menu/contact_hover.png" )
}
else {
$("#contact").hover(function () {
$("#contact img").attr("src","Images/Menu/contact_hover.png" )
},
function() {
$("#contact img").attr("src","Images/Menu/contact.png" )
});
}
});
You shouldn't be doing this with jQuery, there really is no need. Please read up on CSS Image sprites and use the css hover selector like this:
#contact {
background: url(/url/of/img) no-repeat;
}
#contact:hover {
background-position: ; // Change to desired image
}
Do this to change the background position of the image sprite you use, if you're lazy you could change the image altogther instead of bothering with sprites. You will find this method much lighter page size, as well as compatibility.
It's because you aren't making the second call to hover until the else-block runs the first time. Set all of you event handlers up in $(document).ready, and you should be good to go.
you should simplify your code - try this
$("#contact").hover(function () {
if (!$("#contact").hasClass("active")) {
$("#contact img").attr("src","Images/Menu/contact_hover.png" )
}
},
function() {
if (!$("#contact").hasClass("active")) {
$("#contact img").attr("src","Images/Menu/contact.png" )
}
});
Working example at: http://jsfiddle.net/HNGMT/
**The example uses two divs to demonstrate the difference between one with the class of active and one without. The HTML of cours is solely for demonstration purposes as well. And the jQuery selector for the contact class would be modified to reflect the id selector.
HTML:
<div class="contact"><img src="/contact.png" alt="contact inactive" /></div>
<div class="contact active"><img src="/contact.png" alt="contact active" /></div>
JavaScript:
$(".contact").hover(function () {
$(this).find("img").attr({src:"contact_hover.png", alt:"contact hover"});
}, function(){
var ele = $(this);
if(!ele.hasClass("active")){
ele.find("img").attr({ src:"contact.png", alt:"contact inactive"});
}
});

Javascript Problem! Not changing the css style

I have this code in JavaScript:
function change() {
document.getElementById("mem").className = 'gif';
}
The fig and gif are like this:
a.fig {
background: #FFFFFF;
}
a.gif {
background: #000099 ;
}
and the function is used like this
<a class ="fig" id ="mem" onClick="javascript:change()" href="users" >
Where the only difference between gif and fig in CSS is that they have different background colors. The problem is that the change is only noticeable in just a second and it is not permanent!
Any ideas?
HTML:
<a id="mem" class="fig" href="users"> MEMBERS </a>
JavaScript:
var a = document.getElementById('mem');
a.onclick = function() {
this.className = this.className == 'fig' ? 'gif' : 'fig';
}
Live demo: http://jsfiddle.net/eVQjB/
Note: in the demo, I return false; from the click handler to prevent the anchor from being activated.
function change() {
var mem = document.getElementById("mem");
if (mem.className == 'fig') {
mem.className = 'gif';
}
else {
mem.className = 'fig';
}
}
You may be looking for a different problem with JavaScript and styles, but if I understand your problem, you'll still need a different color for the anchor if it has been visited. You can let CSS do that for you:
#mem {
background: #FFF;
}
#mem:visited {
background: #009;
}
<a id="mem" href="users">Lead me to the promised land!</a>
you can try by following way
document.getElementById("idElement").setAttribute("class", "className");
IF still not working you r class is not chaning the style of your html element
Just add return false:
onClick="change(); return false;"
The thing is that without it, the class is changed then the page is redirected as this is the default behavior of anchor tag.
If you want to reload the page and change the class in the reloaded page, have such link:
href="?change=true"
Then in the server side code check for this flag and if true put different class. I'm not familiar with PHP but here is classic ASP version, hopefully similar enough to PHP:
<%
Dim sClassName
If Request("change")="true" Then
sClassName = "gif"
Else
sClassName = "fig"
End If
%>
<a class ="<%=sClassName%>" id ="mem" href="?change=true">

Categories

Resources