Javascript simple style.display function only works at random - javascript

I have been given an assignment to code my own tic tac toe game. I am fairly new to coding, but absolutely love it. I have for now set up a simple function to just hide the "O", and thus only displaying the X. It's a long way to go, but either way I'd like to start off like this.
However, when I click one of the squares, the "O" only hides at random. Sometimes the first time I click, sometimes after four times. Does anybody know what's wrong?
This is the function I'm working with, and this is how one square is built in html:
function hideO() {
document.getElementById("O" + event.target.id).style.display = "none";
}
<div class="square" >
<button class="1" id="1" onclick="hideO()">
<p class="X1" id="X1">X</p>
<p class="O1" id="O1">O</p>
</button>
</div>
Here's all the code I've got.

The problem here is that event.target returns the element you actually clicked on, so when you think you have clicked on .square, you have actually clicked on the p inside it. One solution here is to use event.currentTarget. It will always return the element to which the click method was attached:
function hideO() {
document.getElementById("O" + event.currentTarget.id).style.display = "none";
}
Also, I have no idea why you are making .grid call hideO. I would remove that.
Edit: this seems to break because event.currentTarget is only valid at the time the event is fired. You can try an alternative solution.
Amend your hideO() function as follows:
function hideO(btn) {
btn.querySelector("#O" + btn.id).style.display = "none";
}
And instead of onclick="hideO()", use onclick="hideO(this)", so that the button that was clicked gets passed in as a parameter. Once you have that button in your function, you can get the "O" element inside it.

Related

On-click assigned function with multiple parameters

I am creating a game which involves numbers. The idea is simple, If i click a number(from 1 to 6) and my code randomly picks one(also from 1 to 6). If my choice(onclick) equals to cpu's choice, the game will be over! If they both are unlikely numbers, my score adds up!
Now the question is, if i click "1" or "2"..(and so on) i need a very new function for all of the numbers.
The code looks like this,
<button id="runs" onclick="i0()">0</button>
<button id="runs" onclick="i1()">1</button>
<button id="runs" onclick="i2()">2</button>
<button id="runs" onclick="i3()">3</button>
<button id="runs" onclick="i4()">4</button>
<button id="runs" onclick="i5()">5</button>
<button id="runs" onclick="i6()">6</button>
I should write each and every function repeatedly which is almost the same! How can i use parameters instead which involves only one function. And how can i add an "if" statement in which the condition should say that i clicked "1".etc
Like,
if(Clicked one//for example) {
document.getElementById("someId").innerHTML = "You pressed one";//:ex
}
can i use,
function click(i0, i1, i2//etc)
if(i0 == true) {
//some code
}
Please remember! I need to use parameters (I am new to JavaScript).
First, you shouldn't be setting up your event handlers with HTML event attributes as that technique is 20+ years old and has many reasons not to use it (one of which is that you'll wind up writing a lot of redundant event handler calls as you are doing now).
Please remember! I need to use parameters
No, you don't (unless this is some sort of school assignment which you didn't state - and if that is the case, get your money back for the course because the instructor shouldn't be teaching you outdated ways of writing code, even for learning purposes). Each button is already displaying the number that corresponds to it. Using a parameter is just more redundancy in the code that makes it more brittle of a solution. You just need a centralized function that runs when any of the buttons gets clicked and then that function can simply compare the random number against the clicked button's content.
Also, you can't have multiple elements with the same id.
Take note of how much cleaner the HTML is when you separate the event handlers out of the HTML and note that this solution works no matter how many buttons you want the game to have. Just make sure that any button that is part of the game has the gameButton class and that the content of the element is the next numeric character that hasn't been used yet.
// Get all buttons into an Array
var buttons = Array.prototype.slice.call(document.querySelectorAll("button.gameButton"));
// Loop over the buttons
buttons.forEach(function(btn){
// Give each button a click event callback function
btn.addEventListener("click", function(){
// Generate a random number from 1 to the number of buttons there are in the game
var num = Math.floor(Math.random() * buttons.length) + 1 ;
var output = "The random was: " + num + ", and the clicked button was: " + this.textContent;
// The prepended + converts the text to a number
if(num === +this.textContent){
alert("You win!\n" + output);
} else {
alert("Keep trying!\n" + output);
}
});
});
/* Just for fun */
.gameButton{
background-color:#800080;
color:#ff0;
font-weight:bold;
font-size:2em;
border-radius:2em;
box-shadow:2px 2px #808080;
outline:none;
}
.gameButton:active{
box-shadow:-2px -2px #808080;
}
<button class="gameButton">1</button>
<button class="gameButton">2</button>
<button class="gameButton">3</button>
<button class="gameButton">4</button>
<button class="gameButton">5</button>
<button class="gameButton">6</button>
You don't need a separate function for each button. You can pass a parameter directly to the function call statement:
<button id="runs" onclick="i(0)">0</button>
<button id="runs" onclick="i(2)">1</button>
...
And then in your JS code:
function i(param) {
...
}
Read more, here: https://www.w3schools.com/js/js_functions.asp
As mentioned, you can not use the same ID on multiple elements.
A good way is to pull the id of the button and pass it to the function, like this:
Have a look at this other question and answers in detail:
How to get ID of button user just clicked?

Passing parameter to javascript onclick without using HTML

I can't figure this out. I'm trying to create an onclick handler purely in Javascript.
What I plan to do here is inside this DIV, have a collection of items that I can click on. For now, these items will be numbers from 0 to 9 inclusive. When a number is clicked on, a system message consisting solely of that number should pop-up on the screen. I narrowed my problem down to just the onclick handler definition.
If I use this format:
item[n].onclick=function(n){
handler(n);
}
The handler will fire only when click a number which is correct, but the message that appears is something about mouse event.
If I use this format:
item[n].onclick=function(){
handler(n);
}
The handler will pass a value of -1 which in turn is printed as a message. I think it means "false".
How do I modify this:
item[n].onclick=function(){
handler(n);
}
so that 'n' being used as the handler parameter is the same as the number I click on the screen?
My code is the following:
<div ID="Itemset"></div>
function handler(n){
alert(n);
}
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
collections.appendChild(item[n]);
item[n].onclick=function(n){
handler(n);
}
}
What I'm effectively trying to do if you want to understand it HTML wise is this:
<div ID="Itemset">
<div onclick="handler(0);">0</div>
<div onclick="handler(1);">1</div>
<div onclick="handler(2);">2</div>
<div onclick="handler(3);">3</div>
<div onclick="handler(4);">4</div>
<div onclick="handler(5);">5</div>
<div onclick="handler(6);">6</div>
<div onclick="handler(7);">7</div>
<div onclick="handler(8);">8</div>
<div onclick="handler(9);">9</div>
</div>
Except that I don't want to write out onclick="handler(n);" a million times.
Any advice? and feel free to point to another resource that has the answer I need if there is one.
UPDATE
I'm looking for something compatible with older browsers as well. I'm going to have to not go for the bind function because according to mozilla docs, it works for IE 9+. I'm looking for something that works for IE 7+ as well as other browsers. I might have to go for event listeners if there is no other alternative.
You have a closure issue here (see JavaScript closure inside loops – simple practical example), a simple solution is to use bind to use the current value of n to be a parameter of the handler function
item[n].onclick=handler.bind(item[n],n);
U can use addEventListener and ID for find clicked element...
document.getElementById("Itemset").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was a list item
var value_data = parseInt(e.target.textContent);
if(e.target && value_data > -1) {
alert("Malai test:: "+value_data);
//handler(value_data);
}
});
https://jsfiddle.net/malai/tydfx0az/
I found my answer here: https://bytes.com/topic/javascript/answers/652914-how-pass-parameter-using-dom-onclick-function-event
Instead of:
item[n].onclick=function(n){
handler(n);
}
I have to do:
item[n].onclick=new Function('handler('+n+')');
Funny thing is, the word function needs to be capitalized when making a new instance. It's awkward I have to go this route but it works in IE 7+
One alternative is :
function handler(){
alert(this.id);
}
function myFunction() {
var item=[];
collections=document.getElementById('Itemset');
for(n=0;n<10;n++){
item[n]=document.createElement('DIV');
item[n].innerHTML=n;
item[n].setAttribute("id","itemset"+n);
collections.appendChild(item[n]);
item[n].onclick=handler;
}
}
Insert dynamic ids to the elements and when you click on any element retrieve its id using this.id and do whatever you want to do with that value.
That's all.
Hope this helps.

Javascript interchange with command button

I am trying to setup an interchange using two texts boxes with a command button in between.
The idea is you type a reference/code in the left hand text box, click the button and it generates an alternative reference/code in the right hand text box.
The point being the user can check alternate bearing references if they can't find what they are looking for with the one they have.
The code I use so far is:
<script type="text/javascript">
oldRef = new Array ("Z582","T608","A173");
newRef = new Array ("C850","S708","X449");
function convert()
{
document.getElementById("v2").value = "";
for (index=0 ; index < oldRef.length ; index++)
{
if ( document.getElementById("v1").value == oldRef[index] )
document.getElementById("v2").value = newRef[index];
}
}
</script>
V1 and V2 refer the the text box ID.
This works with the text boxes but I don't know how to incorporate the command button into this so that they need to click the button in the middle for it to generate.
Any suggestions would be much appreciated.
Best
Will
Its pretty Easy stuff what you need to do is to use onclick of the button like this
document.getElementById('button').onclick = function () {
document.getElementById("v2").value = "";
for (var index=0 ; index < oldRef.length ; index++) {
if (document.getElementById("v1").value == oldRef[index])
document.getElementById("v2").value = newRef[index];
}
}
Here is a demo
I hope this is waht you want....
So essentially there are two things that you need to accomplish what you asked. You need to create a element within your HTML, in this case a button. You then need to catch the event that you want to catch from that element and then execute you convert function.
This is one example of accomplishing this:
So create an button within your HTML
<button id="btn_command">Command</button>
Then in Javascript you want to target that button and add an event listener to that button. In the example the below the variable var btnCommand is set to the html button by using the getElementById method to get that button with that id. Then we add and event listener to that element that when clicked it executes your convert function.
var btnCommand = document.getElementById ("btn_command") ;
btnCommand.addEventListener("click", convert, false) ;
If you want to use jQuery you would do something like this.
$('#btn_command').on('click', function() { convert(); });
Here is another quick and dirty way to just test you button with your function. It is not a best idea to mix your javascript inline with your html but just to test your button and if your convert function is doing that you think you could just say
<button onClick="convert()">Command</button>
Well there are few ways to accomplish what you asked. Happy Coding!

independently working div in Jquery

I am trying to make an independently working div which has a form inside of it.
I use jquery to calculate the price of a product depending of the user's selections in the form. However the user is able to add multiple items in his 'cart' so the form is duplicated to another div. The problem is that the calculation pattern can't separate these two divs and the calculation will be incorrect. The form is also interactive so it will be generated by the user's input. This is really complex set and renaming every variable by the 'product number' doesn't sound really efficient to me.
I'm kind of stuck here and i don't really know how to solve this problem. I had an idea that what if I put an iframe inside of the div and load my form and its calculation script inside of it, and then use post command to transfer the price of the product to the 'main page' to calculate the total price of all of the products the user wanted.
However it seems that jQuery scripts doesn't work independently inside of these iframes, they still have connection so they broke each other.
i will appreciate any kind of suggestions and help to solve this matter, thank you!
here's the code so far
Heres the body
var productNumber = 1;
<div id="div_structure">
</div>
<button id="newProduct" >Add new product</button><br \>
add new item
<!-- language: lang-javascript -->
$('#newProduct').click(function ()
{
$('<div id="productNo'+productNumber+'">')
.appendTo('#div_structure')
.html('<label onclick="$(\'#div_productNo'+productNumber+'\').slideToggle()">Product '+productNumber +' </label>'+
'<button onclick="$(\'#product'+productNumber+'\').remove()">Remove</button>');
$('<div id="div_product'+productNumber+'" style="display: none;">').appendTo('#product'+productNumber+'');
$('<iframe src="productform.html" seamless frameborder="0" crolling="no" height="600" width="1000">').appendTo('#div_product'+productNumber+'');
productNumber++;
});
it also has a function that allows the user to remove the inserted div.
Here's just few lines from the productform
$(document).ready(function()
{
$('#productCalculation').change(function ()
{
shape = $('input[name=productShape]:checked', '#productCalculation').val();
alert(shape);
});
});
<form id="productCalculation">
<div id="div_productShape" class="product1">
<h1>Select the shape of the product</h1>
<input type="radio" name="productShape" value="r1">R1</input><br \>
<input type="radio" name="productShape" value="r2">R2</input><br \>
<input type="radio" name="productShape" value="r3">R3</input><br \>
</div>
.
.
.
</form>
I translated all of the variables so they may not function correctly since i didn't test the translated version. So the problem is, if i try to make selections in the second generated div it wont even alert() the selected variable
There are two problems with this code: You say somewhere "I translated all of the variables so they may not function correctly since i didn't test the translated version. So the problem is, if i try to make selections in the second generated div it wont even alert() the selected variable". This is because event handlers are attached to elements that are in the DOM at that specific moment. To get it to work for all elements, use event delegation:
$(document).ready(function()
{
$(document).on( 'change', '#productCalculation', function ()
{
shape = $('input[name=productShape]:checked', '#productCalculation').val();
alert(shape);
});
});
Your other question is "My question in a nutshell: Is there a way to restrict jquery to function only in certain div even though i use the same variable names in the second div ". You can use the this variable to access the element the click was invoked on. From this element you can traverse the DOM if needed, for example with .parent().
$('div').on( 'change', function( e ) {
console.log( $(this).val() );
} );

How can I create an element that flips between two values on click?

Given two spans like this:
<span>Click for info</span>
<span style="display: none">Here is a big long string of info blah blah</span>
...I'd like to have an onclick function attached to each so that the visitor sees "Click for info", and then when they click it, the first span is hidden and the second is unhidden. And, of course, when the second is clicked, things go back to the way they were originally.
I don't have a way of easily generating unique IDs, so I'd prefer to avoid the getElementByID() route, and I'd rather not use jQuery or any other heavyweight dependency. Is there an elegant way to do this?
The best idea I have so far is to write a toggleAllSiblings() function, set onclick to that function for both elements in the pair, and then wrap each pair in a parent element.
Can it be done without the parent node?
If you really want to go without ids you could do something like this:
<script>
function togglePrevious(sender) {
sender.previousSibling.style.display = "inline";
sender.style.display = "none";
}
function toggleNext(sender) {
sender.nextSibling.style.display = "inline";
sender.style.display = "none";
}
</script>
<span onclick="javascript:toggleNext(this);">Click for info</span>
<span onclick="javascript:togglePrevious(this);" style="display:none">Info blablabla</span>
And please not that you should really use "inline" instead of "block" if you are using spans as they are inline elements. Setting their display style to block will force them to be divs.
Yet another version, a la progressive enhancement — will properly show the full info when JavaScript is off.
<span class="details">Here is a big long string of info blah blah</span>
<script type="text/javascript">
// Open/close span behaviour
//
function infoToggle(span) {
var ersatz= document.createElement('span');
ersatz.appendChild(document.createTextNode('Click for info...'));
span.parentNode.insertBefore(ersatz, span);
span.style.display= 'none';
span.onclick= function() {
ersatz.style.display= 'inline';
span.style.display= 'none';
};
ersatz.onclick= function() {
ersatz.style.display= 'none';
span.style.display= 'inline';
};
}
// Bind to all spans with class="details"
//
var spans= document.getElementsByTagName('span');
for (var i= spans.length; i-->0;)
if (spans[i].className=='details')
infoToggle(spans[i]);
</script>
I'm not sure of the implementation, but the logic will look similiar to
Get all spans
Hide adjacent spans
beneath (leave them visible for non
JS users by default)
Attach even
handler to first spans
Event handler
function - show next span if next
span invisible, otherwise hide it
This is off the top of my head & untested. It should get you going at least.
<script>
function toggle(id)
{
var display = document.getElementById(id).style.display;
if ( display == "block" )
document.getElementById(id).style.display = "none";
else
document.getElementById(id).style.display = "block";
}
</script>
<span onclick="javascript: toggle('span_to_toggle');" id="clickable_span">click here</span>
<span id='span_to_toggle' style="diplay:none">foooooooooooooooooooooo</span>
quick rework of #Jason:
<script>
function toggle(targetId, sender)
{
var show = document.getElementById(targetId);
show.style.display = "block";
sender.style.display = "none";
}
</script>
<span onclick="javascript: toggle('more', this);" id="less">click here</span>
<span style="display:none;" id="more" onclick="javascript: toggle('less', this);" >foooooooooooooooooooooo</span>
Just as a side note for when you're developing javascript stuff which involves creating elements in the DOM. If you're not going to use something like jQuery (I'm not a fan of frameworks, too heavy and non-specific) try and use a function to make your elements for you, that way you don't have too many redundant lines as it tends to make your scripts really heavy.
I personally use a code snippet i found here www.dev-explorer.com/articles/create-dom-object but you might find something that suits you better. If your site downloads quicker the user doesn't have to wait as long for onload events etc and generally doesn't get annoyed as easily.
Hope this made sense
Thanks,
Scarlet
I'd rather not use jQuery or any other heavyweight dependency.
I don't know if that is a good approach. Unless you can attribute any real performance problem to using jQuery or prototype.js (which are both not really that heavy), you should use them.
Otherwise you will just spend a lot of time with repetitive typing and on fixing nasty browser bugs and incompatibilites.
I don't have a way of easily generating unique IDs
Again, you really want $$('div span[someParam=something]'). And since the libraries dispatch this to native browser query functions where available, it is probably not even slower than a hand-coded solution. Definitely more maintainable.

Categories

Resources