Javascript function changeImage: Issues using variables for getElementById or getElementsByName - javascript

I'm having some trouble getting my code to do what I want. I have multiple sections that I have set to toggle show/hide, and it functions correctly. However, I'm now trying to switch the images to where instead of always being static with "More," I'd like it to switch to "Less" when it's expanded.
It does work... but only for the first one. If I press the buttons on any of the others, it only changes just the first one. You can see the page here:
http://jfaq.us
I've tried several different solutions with variables, but I can't seem to get it to work.
Help? Thanks in advance!
function changeImage() {
if (document.getElementById("moreorless").src == "http://jfaq.us/more.png")
{
document.getElementById("moreorless").src = "http://jfaq.us/less.png";
}
else
{
document.getElementById("moreorless").src = "http://jfaq.us/more.png";
}
}
function toggleMe(a){
var e=document.getElementById(a);
if(!e)return true;
if(e.style.display=="none")
{
e.style.display="block"
}
else{
e.style.display="none"
}
return true;
}
<div>
Guestbook
<div>
<input type="image" src="http://jfaq.us/more.png" id="moreorless" onclick="changeImage();return toggleMe('para3')" >
</div>
<div id="para3" style="display:none">
This is normally hidden, but shows up upon expanding.
This is normally hidden, but shows up upon expanding.
</div>
About
<div>
<input type="image" src="http://jfaq.us/more.png" id="moreorless" onclick="changeImage();return toggleMe('para2')" >
</div>
<div id="para2" style="display:none">
This is normally hidden, but shows up upon expanding.
This is normally hidden, but shows up upon expanding.
</div>
</div>

The id attribute must be unique. That's why it's not working. Also, it's not a good idea to use inline event handlers like you are doing, you should register event handlers using addEventListener instead.
Without changing all your code, one thing you can do is pass a reference to the currently clicked element to the changeImage function.
function changeImage(el) {
var moreUrl = 'http://jfaq.us/more.png';
el.src = el.src === moreUrl? 'http://jfaq.us/less.png' : moreUrl;
}
Then change the inline handler for onclick="changeImage(this);"

You are using same Id for all inputs. This is causing the problem.
Give every element a unique Id.
If you want to perform grp operation use jquery class.

That's because you use the same id for the both images, and getElementById apparently takes the first one.
Here is the updated code:
html:
<input type="image" src="http://jfaq.us/more.png" id="moreorless" onclick="changeImage.call(this);return toggleMe('para3')" >
script:
// inside the event handler 'this' refers to the element clicked
function changeImage() {
if (this.src == "http://jfaq.us/more.png") {
this.src = "http://jfaq.us/less.png";
} else {
this.src = "http://jfaq.us/more.png";
}
}

check this
http://jsfiddle.net/Asb5A/3/
function changeImage(ele) {
if (ele.src == "http://jfaq.us/more.png")
{
ele.src = "http://jfaq.us/less.png";
}
else
{
ele.src = "http://jfaq.us/more.png";
}
}
<input type="image" src="http://jfaq.us/more.png" onclick="changeImage(this);return toggleMe('para3')" >

Related

addEventListener within a class always gets executed on the first element

I have this code, it's about disabling and enabling a button of a form according to its check box input. It's getting executed on different pages, you can see the last two lines where I loop through the forms on the page, all works fine when there is one from in the page, however, on pages where there is more than one form, it doesn't matter which check box I check (second or third for instance) it always affects the first button.
you can notice there are two "console.log" statements, the first one returns the correct input element (so when there are two forms in the pages, you can see in the console the elements reference the correct inputs on the DOM), however, the second one always shows an element in the console referring to the first input in the DOM.
my guess is that there is something wrong with the way I add the event listener, any suggestions for making that work?
class Steps {
constructor(el) {
this.el = el;
this.bindDOM();
this.bindStepEvents();
}
bindDOM() {
this.checkboxSelectorStep = this.el.querySelector('.radio-selector-steps-enable');
this.submit = this.el.querySelector('button[type=submit]');
}
bindStepEvents() {
console.log(this.checkboxSelectorStep); // returns the correct element
this.checkboxSelectorStep.addEventListener('click', (ev) => {
console.log(this.checkboxSelectorStep); // always returns the first element
if (ev.target.checked) {
this.submit.removeAttribute('disabled');
} else {
this.submit.setAttribute('disabled', '');
}
});
}
}
const forms = Array.from(document.querySelectorAll('.radio-selector-steps-form'));
forms.map(form => new Steps(form));
<form method="get" class="radio-selector-steps-form">
<input type="checkbox"
name="checkbox-selector-step"
id="checkbox-selector-step"
class="radio-selector-steps-enable">
<label for="checkbox-selector-step"><span>some text</span></label>
<button type="submit" disabled="">button text</button>
</form>
<form method="get" class="radio-selector-steps-form">
<input type="checkbox"
name="checkbox-selector-step"
id="checkbox-selector-step"
class="radio-selector-steps-enable">
<label for="checkbox-selector-step"><span>some text</span></label>
<button type="submit" disabled="">button text</button>
</form>
The problem was that both of the inputs had the same id, and the labels are referencing that id, so hitting the input itself works fine but whenever the label is being clicked the first listener gets called.
(due to styling, clicking the input was not possible for my case so I would always end up with the wrong behavior until I tried to create a SO snippet for it and caught the issue)
Hoping this might help someone.
You need to use querySelectorAll instead of querySelector
bindDOM() {
this.checkboxSelectorStep = this.el.querySelectorAll(STEPS_ENABLE_CHKBOX);
this.submit = this.el.querySelector(STEPS_FORM_SUBMIT);
}
bindStepEvents() {
console.log(this.checkboxSelectorStep);
this.checkboxSelectorStep.forEach(function(elem) {
elem.addEventListener('click', (ev) => {
console.log(this.checkboxSelectorStep);
if (ev.target.checked) {
this.submit.removeAttribute('disabled');
this.update(JSON.parse(this.steps[0].primaryInput.value))
} else {
this.submit.setAttribute('disabled', '');
}
});
});

How can I hide a div until a button is clicked?

I'm trying to create 3 divs that are hidden when the page load, so that when I click their respective buttons they show up, however, no matter what I do, I cannot get them to show up with the button click.
Here is the relevant part of the code:
My div and button:
<button onclick="TestsFunction()">Tests</button>
<div id="TestsDiv" style="display:none">
tests here!
</div>
And the JS used to show it:
function TestsFunction() {
var T = document.getElementById("TestsDiv");
T.style.display = "none";}
I can successfully hide the div when I load the page, however after I click the button it doesn't show up again.
I tried
window.onload = function(){
document.getElementById('TestsDiv').style.display = 'none';
}
Instead of style="display:none" on the div to see if the way I hid it was the problem, but the div still wouldn't show up.
I'm a beginner and I'm not good with JS, HTML or PHP, if possible can someone both help and explain my mistake? Do I need something else in my code? I tried reading similar threads but the solutions were all too complicated for my understanding and I ended up not being able to fix my problem. Thank you!
You need to set display to block (or something else) but not hide when button is clicked!
function TestsFunction() {
var T = document.getElementById("TestsDiv");
T.style.display = "block"; // <-- Set it to block
}
<button onclick="TestsFunction()">Tests</button>
<div id="TestsDiv" style="display:none">
tests here!
</div>
try
function TestsFunction() { TestsDiv.style.display = 'block' }
function TestsFunction() { TestsDiv.style.display = 'block' }
<button onclick="TestsFunction()">Tests</button>
<div id="TestsDiv" style="display:none">
tests here!
</div>
You need to adapt your function to toggle the display of the div. Currently it is only hiding it - but if its already hidden, remove the display = "none" to show it again. You remove it by setting the display style to an empty string (which makes it default).
function TestsFunction() {
var T = document.getElementById("TestsDiv"),
displayValue = "";
if (T.style.display == "")
displayValue = "none";
T.style.display = displayValue;
}
<button onclick="TestsFunction()">Tests</button>
<div id="TestsDiv" style="display:none">
tests here!
</div>
If you only want it to be shown, and not to be able toggle display on and off, just set it to the empty string right away.
function TestsFunction() {
document.getElementById("TestsDiv").style.display = "";
}
<button onclick="TestsFunction()">Tests</button>
<div id="TestsDiv" style="display:none">
tests here!
</div>
You should look into jQuery's hide() and show() methods. They take care of setting the styles for you.
https://www.w3schools.com/jquery/jquery_hide_show.asp
do like this =>
function TestsFunction(){
$("#TestsDiv").css("display","block")
}
before that you should include jquery cdn.
thank you.

Click outside an element doesn't work

I have this code:
function showAll(el){
var id = el.parentNode.id;
var all= document.getElementById(id).getElementsByClassName('items')[0];
if(all.style.display === 'block'){
all.style.display = 'none';
} else{
all.style.display = 'block';
window.addEventListener('mouseup', function(e){
document.getElementById('test').innerHTML = e.target.className;
if(e.target != all){
all.style.display = 'none';
}
});
}
}
<div id="parent">
<div class="selected" onClick="showAll(this);">
</div>
<div class="items" style="display: none">
</div>
</div>
Basically what i want to achieve is: click on selected to display items which is now hidden after that if i click again on selected or if i click outside of items(a random spot on that page or even on selected) i want to be able to hide items.
The problem is that without the EventListener when i click on selected it works to display items and then if i click again on selected it works to hide items but if i click on a random spot it doesn't work to close items.
But when i add EventListener and i click on selected it works to click a random spot to close items but it doesn't work to click selected again to close items.
Can anybody help me with a full JavaScript explanation, please?
You're going to want to use highly reusable code. I use change() and id_() on my web platform all of the time and it's very direct and simple. In the below example the second parameter will make the class empty (you can also use id_('items').removeAttribute('class') for a cleaner DOM (Document Object Model)).
HTML
<input onclick="change(id_('items','');" type="button" value="Display Items" />
<div clas="hidden" id="items"><p>Items here.</p></div>
CSS
.hidden {display: none;}
JavaScript
function change(id,c)
{
if (id_(id)) {id_(id).className = c; if (id_(id).className=='') {id_(id).removeAttribute('class');}}
else if (id) {id.className = c; if (id.className=='') {id.removeAttribute('class');}}
else {alert('Error: the class id \''+id+'\' was not found or has not yet been imported to the DOM.\n\nNew class intended: '+c);}
}
function id_(id)
{
if (id == '' && window['console']) {console.log('Developer: empty id called from: '+id_.caller.toString().split('function ')[1].split('(')[0]);}
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
This code exists from years of refining the same platform instead of industry standard drama of pointlessly changing things. You are two clicks from finding more highly reusable functions on my platform's JavaScript documentation from the link in my profile.

Show hide/div based on drop down value at page load

I have the following code that I use to hide/show a div using a drop-down. If the Value of the drop-down is 1, I show the div, otherwise I hide it.
var pattern = jQuery('#pattern');
var select = pattern.value;
pattern.change(function () {
if ($(this).val() == '1') {
$('#hours').show();
}
else $('hours').hide();
});
The select drop down retrieves its value from the database using form model binding:
<div class="form-group">
<label for="pattern" class="col-sm-5 control-label">Pattern <span class="required">*</span></label>
<div class="col-sm-6">
{{Form::select('pattern',['0'=> 'Pattern 0','1'=> 'Pattern 1'],null,
['id'=>'pattern','class' => 'select-block-level chzn-select'])}}
</div>
</div>
This select drop-down then hides or shows the following div:
<div id="hours" style="border-radius:15px;border: dotted;" >
<p>Example text</p>
</div>
The problem:
The div won't be hidden if the pattern stored in the database is set to 0. I have to manually select "Pattern 0" from the drop down to change it. I know that is due to the .change() method. But how do I make it hide/show on page load?
Usually in such case I store the anonymous function reference as below:
var checkPattern = function () {
if ($('#pattern').val() == '1') {
$('#hours').show();
}
else $('#hours').hide();
}
It makes the code ready to use in more then one place.
Now your issue could be resolve in a more elegant way:
$(document).ready(function(){
// add event handler
$('#pattern').on('change', checkPattern);
// call to adjust div
checkPattern();
});
Well, if the element "should" be visible by default, you just then have to check condition to "hide it" (you don't have to SHOW an element that is already visible...) :
if(pattern.value != %WHATEVER%) { $('#hours').toggle(); }
Then, to switch display on event or condition or whatever :
pattern.change(function(evt){
$('#hours').toggle();
});
Not sure that your event will work. I'd try something like
$(document).on(..., function(evt){
//behaviour
});
http://api.jquery.com/toggle/
https://learn.jquery.com/events/handling-events/

How to change class name of two IDs at same time using js?

I have two IDs in same name ! if any one clicked among them , i need to change the class name of the both IDs. i know we should use ID for single use. Because of my situation(I have two classes for button ) so i have moved to ID.
Her is my code if i click one id that name only changes another one is remains same
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
<button class="success" id="1" onClick="reply(this.id)"> Added </button>
js function
function reply(clicked_id)
{
document.getElementById(clicked_id).setAttribute('class', 'failed');
var el = document.getElementById(clicked_id);
if (el.firstChild.data == "Added")
{
el.firstChild.data = "Add";
}
}
if i use instead of 'class' to id while renaming class which one will be renamed success class or 'class name 1' ?
You can't. Getelementbyid will only return one element. Probably the first one.
Pure JS Is Second Example
My JS Fiddle Example: http://jsfiddle.net/eunzs7rz/
This example will use the class attribute only to perform the switching that you need, its a extremely basic example as do not want to go beyond what is needed... Also i forgot to remove the id's in the JS Fiddle Example.. so just ignore them
THE CSS:
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
THE HTML:
<button class="success"> Added </button>
<button class="success"> Added </button>
THE JAVSCRIPT:
$(function() {
$(".success").click(function(){
Reply(this);
});
});
function Reply(oElm) {
$(oElm).attr('class', 'failed');
}
EDIT - PURE JAVASCRIPT VERSION
Sorry, did not think to check the post tags if this was pure JS. But here you go anyway ;)
<style>
.success {
background-color:#00f;
}
.failed {
background-color:#f00;
}
</style>
<button class="success" onclick="Reply(this)"> Added </button>
<button class="success" onclick="Reply(this)"> Added </button>
<script>
function Reply(oElm) {
oElm.className = 'failed';
}
</script>
THE MAIN THING HERE
Once you have the element either by using 'this' or by using 'getElementBy', you can then simply use ".className" to adjust the class attribute of the selected element.
As already explained by others, id is for single use and is quicker than using class or type. So even if you have a group, if only one is ever used.. use an id.
Then you use the object/reference of 'this' from an event on an element, in this case the onclick... that will send that variable to the function / code called.
So using 'this' is a preferred option as it will always reference the element that it is used/called from.
pass elemenet, not it's Id
<button class="success" id="1" onClick="reply(this)"> Added </button>
<button class="success" id="1" onClick="reply(this)"> Added </button>
function reply(elem)
{
$(elem).setAttribute('class', 'failed');
if (elem.firstChild.data == "Added")
{
elem.firstChild.data = "Add";
}
}
the ID attribute must be unique or else it will get the last defined element with that ID.
See this for reference.
Use a class instead of an id. ids are supposed to be unique in a dom tree.
html:
<button class="success" onClick="reply()"> Added </button>
<button class="success" onClick="reply()"> Added </button>
js:
var ary_success = document.querySelectorAll(".success"); // once and forever. If the set of elements changes, move into function `reply`
function reply () {
var elem;
var s_myclasses;
for (var i=0; i < ary_success.length; i++) {
elem = ary_success[i];
s_myclasses = elem.getAttribute('class');
s_myclasses = s_myclasses.replace ( /(success|failed)/g, '' );
s_myclasses = s_myclasses + ' failed';
elem.setAttribute('class', s_myclasses );
if ( elem.firstChild.data.indexOf("Added") !== -1) {
elem.firstChild.data = "Add";
}
}
}
Live Demo here.
Notes
Make sure that you set ary_successin the onload handler or in an appropriately placed script section - at the timeof execution the buttons must be present in the dom ! If in doubt, move it to the start of reply' body.
If you employ jquery, the code simplifies (well...) to:
$(document).ready( function () {
$(".success").on ( 'click', function ( eve ) {
$(".success").removeClass("success").addClass("failed");
$(".success *:first-child:contains('Added')").text(" Add ");
});
});
Updates
Notes, Live Demo
Iterator method changed, every not supported on test platform

Categories

Resources