This one really has me scratching my head.
I'm building a calculator using JavaScript as an exercise. Said calculator is up and running here on Codepen. In the lower left you will see a "+-" button, which simply takes the content of the input field, and reverses it's sign (positive becomes negative, negative becomes positive.) Then when the user presses an operation button this is pulled and used in the calculation. Simple right?
The function which actually changes the sign is as follows:
function toggleSign() {
if(getCurrentDispVal()[0] === "-") {
currentNumStr = currentNumStr.slice(1, currentNumStr.length);
} else {
currentNumStr = "-" + currentNumStr;
}
updateDisplay(currentNumStr);
}
and is called in just one place, a function which takes input from the user and decides what to do with it:
function useInput(input) {
if(input.match(/(\d|\.)/)) {
handleDigitInput(input);
} else if(input.match(/(X|\/|-|\+)/)) {
handleBinaryOperation(input);
} else if(input.match(/=/)) {
handleEqualsOperation();
} else if(input.match(/^c$/)) {
clearCurrentNumStr();
} else if(input.match(/^ac$/)) {
allClear();
} else if(input.match(/^shorten$/)) {
shortenCurrentNumStr();
} else if(input.match(/^plusmin$/)) {
toggleSign();
}
}
Now sometimes, and only sometimes, this works as expected. For instance, enter the following:
1 on keyboard, not the screen
Click the "+-" button
+ on keyboard
5 on keyboard
enter on keyboard
Sometimes this runs properly, and spits "4" as the result. Sometimes, and this is baffling me, when you hit enter it flips the sign on "5" making it "-5" and then returns "-6" as the answer." I've done some checking and can see that when this occurs, in the useInput function both the /=/ and /^plusmin$/ conditionals are being triggered. Thus toggleSign is being called prior to handleEqualsOperation and this is lousing up the results. Strangely, if you don't use the keyboard, and just click the screen buttons directly, this problem doesn't occur.
I'm at a loss here. There doesn't seem to be any pattern as to when this occurs, and I'm using the same input above over and over. I don't understand why this is occurring, and why it isn't occurring consistently.
So for what I can see, there is a problem in the way you handle the "currentNumStr" variable, follow this example, to find another problem:
press 5
press the +/- button to toggleSign
press the X button
press 6
"It will display -30", but since you made an operation (handleBinaryOperation, handleEqualsOperation) "currentNumStr" will be empty"
press the +/- button to toggleSign
you will get an empty display
If you track this variable you'll get your answer.
Also keep in mind that e.key is not cross-browser compatible, maybe you could use e.keyCode or e.which instead, I got many undefined errors because of this.
EDIT: To exemplify what I added in the comments:
in the HTML change this:
<div class="calc-body>
to this, choose the id you want ( the tabindex is necessary so the div cant get the focus)
<div class="calc-body" id="forFocusId" tabindex="0">
and in the Js file, add a global var to assign the div ( if you dont want to add a variable, you can call document.getElementById("forFocusId") in the next step instead)
var focusElement = document.getElementById("forFocusId");
finally at the end of the function useInput, add
focusElement.focus();
Related
I'm new to learning JavaScript and I took it on myself to build a TicTacToe game for learning purposes.
Here is what the game so far looks like, as you can see it is very basic:
https://rjo.000webhostapp.com/
I'm having the user choose either "X" or "O" to start off. I had a function prviously that was "onclick" within the HTML code but after doing some online research I found out that is bad practice within the industry.
Doing the "onclick" within the HTML such as <div class="XO" onclick="userChoice"> allowed it so my user had to click on the X or O and it behaved exactly how I wanted it to.
Doing this method with an event listener seems to make it messy - the user can click to the far left of the "X" or a tad to the right and it is still chosen as X. Even to the right of the "O" it will choose X. Any suggestions? I uploaded my mini project so you can take a look at what I'm doing.
Here is the JS for the EventListener:
document.addEventListener('DOMContentLoaded', function(domReadyEvent) {
//observe clicks on the document
document.addEventListener('click', function(clickEvent) {
if (clickEvent.target.className.indexOf('X') > -1) {
alert('clicked on X');
//handle click on X
} else if (clickEvent.target.className.indexOf('O') > -1) {
alert('clicked on O');
//handle click on O
}
});
});
I want this to be done in strictly JavaScript as well. I am familiar with HTML, CSS and more complex languages such as C/C++ but little to no experience with JS.
I also had an issue that my "O" wasn't selecting, it was thankfully helped out:
The issue is that you have not set a class for O
Needs to be: O
The issue is that you have not set a class for
<span id="O" )"="">O</span>
Needs to be:
<span id="O" class="0")"="">O</span>
(and ideally use either class or id - not both)
Also to answer your other question, its better to just target elements like:
var naught = document.getElementById('0');
naught.addEventListener('click', function(clickEvent) {
alert('clicked on 0');
// handle 0 event
});
instead of doing those indexOf checks
I am making a text adventure game, which would require user input in the form of a element in html, which would send the user input to JavaScript using the click function:
<!-- HTML CODE -->
<div class="game">
<div id="gamebox">
<a name="game"></a>
<!-- Javascript writes to here (if it works :( ) -->
</div>
<div id="inputbox">
<input type="text" id="userinput" placeholder="Input" value="" />
Go!
</div>
</div>
As you can see above, I have a element and a "Go!" button, which sends it to my JavaScript code. In JavaScript, first I define 3 variables where I would output my text.
//JavaScript Code
var txt_input = $("#userinput");
var btn_quest = $("#btn-quest");
I would than define 2 other functions, which allows me to write into the . I would than have other functions, which are for the storyline of the text adventure game. However, the root of the problem is that I can't seem to progress past the second event. Here are my events:
function wakeUp() {
displayGame("You wake up, at stackoverflow. West or east? [Choose 'west' or 'east']");
btn_quest.on({
"click": function() {
// Begin input preproccessing
var input = txt_input.val().toLowerCase();
// If/else block for choice here
if (input === "west") {
//Paste btn_quest here for new event
goWest();
} else if (input === "east") {
//Paste btn_quest here for new event
goEast();
} else {
//Error handler - do not modify
txt_input.val("Error - enter a valid choice");
}
//End of if else block body
}
});
The first event function would work perfectly, and write to my html, and accept the first user choice. However, at the next event, no matter what it is, (goEast() or goWest()), my program aways displays "Error - enter a valid choice"). Right now, my hypothesis is that the "switch" function isn't working correctly. However, I honestly don't know. What is the issue here, and how can I fix it? The other event functions (etc goEast) are exactly the same as the wakeUp function, except with different displayGame() strings and link to other event functions.
I have not included the full code, in order to keep my code short - but here is the full html/css/javascript if needed: http://plnkr.co/edit/55heHh4k5QEIVYdBrWGB?p=preview
Edit: I tried to implement the suggestion, like this: But It seems that JavaScript doesn't even get the userinput anymore. When I try to submit the user's response, nothing happens. What went wrong? I did the same thing here with all of my functions in the game:
function wakeUp() {
displayGame("You wake up at stackoverflow again, but it didn't work. Go West or east again?");
// btn_quest.off("click").on("click",function()){
btn_quest.off("click").on;
"click", function() {
// Begin input preproccessing
var input = txt_input.val().toLowerCase();
// If/else block for choice here
if (input === "walk") {
//Paste btn_quest here for new event
walkToWork();
} else if (input === "bus") {
//Paste btn_quest here for new event
busToWork();
} else {
//Error handler - do not modify
txt_input.val("Error - enter a valid choice");
}
//End of if else block body
};
//End of function. Copy until line under this comment V
}
What did I do wrong? Can you please show a example using this function?
You need to look at all the code to see the problem. The reason is because you keep binding to the element so multiple click events are being triggered. You need to remove the last click
btn_quest.off("click").on("click",function(){});
I'm trying to write some code that will print either "Spinning left" or "Spinning right" depending on whether the left or right arrow keys are pressed down. At the moment, it seems to continuously print out the statement until the other key is pressed, and then it will just print the other statement many times instead. Heres my code at the moment :
function Update () {
if(Input.GetKey(KeyCode.LeftArrow)){
print("spinning left");
}
if(Input.GetKey(KeyCode.RightArrow)){
print("Spinning right");
}
}
I originally had "left" instead of KeyCode.LeftArrow, but it didn't change the output. I'm new to Javascript, so is there something that I forgot to do to make the program stop registering that the button is pushed?
I guess he's working in Unity...
use if (Input.GetKeyDown ("left")) instead of KeyCode.LeftArrow
this only prints if you hold down the key...
http://docs.unity3d.com/Documentation/ScriptReference/Input.GetKeyDown.html
I want to make a custom made confirmation box in javascipt just like the built in confirm box. the built in confirm box does not allow the code to progress unless the user selects atleast one thing. Below is my code:
*****HTML start*****
<div class = "popUp confirm" style="z-index:40000;" id="confirmBlock">
<div id = "confirmLabel" >Confirm Message</div>
<div style ="border:0px solid red;height:44.56px;">
<input id="Confirm" type="button" value="Confirm" onclick = "confirmAction(1)" />
<input id = "CancelConfirm" type="button" value="Cancel" onclick = "confirmAction(0)" />
</div>
</div>
*****HTML end*****
*****Javascript start*****
var confirmresult = "-1";
function confirmationLoop()
{
alert("If this alert is preesnt it works, seems like the built in alert provides some sort of pause for other parts of code to continue to work");
if(confirmresult == "-1")
confirmationLoop();
return;
}
function confirmAction(val)
{
confirmresult = val;
}
function checkuuu()
{
confirmresult = "1";
}
function confirmMessage(message)
{
document.getElementById("confirmLabel").innerHTML= message;
//var check = setTimeout(function(){confirmAction(1)},5000);
confirmationLoop();
/*
while(1) //using while almost does not allow any other part to run at all hence tried recursion
{
if(confirmresult != "-1")
break;
}
*/
document.getElementById("confirmLabel").innerHTML= "Confirm Message";
var returnVal = confirmresult;
confirmresult = -1;
return returnVal;
}
*****Javascript end*****
*****Sample code start*****
So this i what i expect below:
function example
{
var check = confirmMessage(message);
//the next part of code should not execute untill i press confirm or cancel, using settimeout or settimeinterval is asynchronous and the code flow continues. i want the effect something like alert and confirm built in boxes
}
*****Sample code end*****
I used loop but it keeps the thread completely occupied and does not give me a chance to press any button, which was quite obvious
However recursion gives u the freedom to perform other activities. The problem even though the value of confirmResult will become 1 upon pressing confirm button, which i check through alert. the recursive loop i.e. confirmation loop does not seem read it as 1. it still continues as -1. If i put a alert in that confirmation loop the value wil be read as 1. Can anyone help me to achieve what i started out to??????
P.s.=> sorry for such a huge question!!!
You can't use any sort of loop - as you've found it'll just cause the browser to lock up.
What you need to do is to emulate a "modal" dialog box.
This is usually done by having your dialog box appear on top of another "overlay" element which importantly covers every other element, and prevents any user interaction with them.
It's also pretty hard to implement a confirm function that'll return a value - the window.confirm method can only do that because it's synchronous - it blocks all other JS processing while the dialog is displayed.
The easiest approach is to instead supply a callback function that'll get called once the user has selected the desired value.
Update: I still haven't figured this out, but saw Jquery - Jeditable: How Reset to non-editable without page refresh which looks similar to what I'm wanting to do. Tried to incorporate it but am not sure I'm doing it correctly since it is taking 2 clicks (or 2 ctrl-clicks) for it to behave in the way I'm expecting.
$("div.wanttoedit").click(function(e){
if (e.ctrlKey) {
$('div.wanttoedit').addClass('non_edit').removeClass('edit').unbind('click.editable');
alert('Ctrl was pressed');
} else {
alert('Ctrl was NOT pressed');
$('div.wanttoedit').addClass('edit').removeClass('non_edit');
$('.edit').editable('http://#request.host#/vp/metrics.cfc?method=updateMetrics&returnformat=plain');
}
});
<div id="#results.id#" class="wanttoedit non_edit">#val(value_disp)#</div>
Again, any help is mightily appreciated. Thanks.
I'm still very new to jquery/javascript/jeditable so please be kind and as explicit as possible. :)
I have a table with row labels = Metric Name and column labels = Months. The cells contain the corresponding metric values. I want to be able to single left-click and have the metric value be editable but also be able to ctrl-click (or right-click, shift-click or other) and be able to enter a reason why the metric was missed (if it was). These two things are updated in two different tables in my database, but both are linked back to the metric_id/name and timeframe/month they are associated to.
I have been able to get the single left-click editing of the metric value working through jeditable but I have been unsucessful so far in finding a way to make the field also allow the other-click pop-up of a dialog box to enter the miss information.
Any help would be sincerely appreciated especially if you can make it easy to understand for this rather simple girl.
I'm using Coldfusion (not sure if that is necessary knowledge, but thought I'd mention it just in case) and can provide any code snippets as necessary to allow you to help me get this fixed.
Here is a sample of my code, I'm using jquery tabs, so the editable is in a rather different place than usual (hopefully I'm including everything you need to see...if not just let me know what I might be missing)
$(document).ready(function() {
$("#cymteamtabs").tabs( {
cache: false,
load: function(event,ui) {
$(".editMetric").editable("http://#request.host#/vp/metrics.cfc?method=updateMetrics&returnformat=plain");
},
ajaxOptions: {cache: false}
}
);
<cfloop query="metrics">
<tr>
<td>#metrics.mdisplay#</td>
<cfloop query="dates">
<td id="#results.id#" class="editMetric">#val(value_disp)#</td>
</cfloop>
</tr>
</cfloop>
Oh and just to make sure I was clear on what I want it to do....if I ctrl-click on the field, the pop-up would appear allowing the entry of the miss info (the editing is disabled). Once that dialog is closed, if I left-click on the field it would enable editing of that field so, basically I don't want to ever turn off jeditable completely, I just want it to go into hibernation mode between the time that the user ctrl-clicks on the field and when the dialog box that pops-up because of that is closed.
Thanks in advance.
I'm not certain that this is the best way to do this, nor am I positive that it is doing exactly what I want it to do, but it so far appears to work.
$(document).ready(function()
{
$("#cymteamtabs").tabs(
{
cache: false,
ajaxOptions: {cache: false},
load: function(event,ui)
{
$(".editMetric").click(function(e) {
if (e.ctrlKey) {
var metric_id = $(this).attr('data-metric-id');
var date_type = $(this).attr('data-date-type');
var value_date = $(this).attr('data-value-date');
var url_tf = 'cym';
var url_view = 'edit';
scorecards.display.miss_details(metric_id,date_type,value_date,url_tf,url_view);
e.stopImmediatePropagation();
}
});
$(".editMetric").editable("http://<cfoutput>#request.host#</cfoutput>/vp/metricCFComponents.cfc?method=updateMetrics&returnformat=plain");
}
});
});
This appears to check first for the ctrl-click and if it is pressed, then the non-jeditable code runs and the e.stopImmediatePropagation(); appears to not allow the jeditable code below it to run.
The only way I can think of sorting this is a little bit of a hack.
There doesn't seem to be anyway of running a conditional on the event so what I propose is setting two event types and switching between them when ctrl is pressed
The problem is the event types - unbinding them seems a bit excessive.
The best option would be to set the editable element as the <td /> as you have but have a separate element (like a span) as the trigger.
To continue with your current html you could try this:
$('.editMetric').editable('url1', {
event: "nrmlClick"
}).editable('url2', {
event: "ctrlClick"
}).bind('toggleClick', function(e) {
if (e.ctrley) {
/* modal javascript here */
$(this).trigger('ctrlClick')
} else {
$(this).trigger('nrmlClick')
}
});
I don't have the facilities to test this properly but this should work.
I've never made up event names before so I don't know how good an idea that is (hopefully someone can enlighten us) but I can't see the harm right now.
Hope that helps!