Strange jQuery behaviour - javascript

I know that $("#SendingType").val(2) sets the value of the select to 2.
So, why does this goes to else??
$(function () {
$("#calculate").click(function () {
var result = $("#SendingType").val();
var day1 = eval(result) + 3;
var day2 = eval(result) + 10;
var day3 = eval(result) + 2;
if ($("#SendingType").val(2)) {
$("#result").text(day1 + " and " + day2 + " days.");
} else {
$("#result").text(day1 + " and " + day3 + " days.");
}
});
});
I am aware that this is not correct way to code if statement.
SOLVED: Thank you Jason and Juhana. The code does not go to else, I thought it would because the value of the select influences the if result. Always if but with different results because of the new select value.
FIDDLE

Looks to me like it runs the true branch regardless:
http://jsfiddle.net/tMwRV/
Which makes sense. You are setting the value to 2, not checking the value. The statement $("#SendingType").val(2) returns a jQuery object, which is "truthy".

Related

javascript variables not being passed

Can anyone tell me why the variables current and at do not pass to the function but when I sue the console the correct value comes up? I am completely clueless on this one which means it must be simple!
records = [118571, 118666, 118693, 118791, 118827, 118942, 119041, 119144, 119265, 119310, 119430, 119570, 119617, 119726, 119762, 120030, 120086, 120103, 120129, 120145, 120219, 120365, 120441, 120562, 120607, 120932, 121072, 121232, 121260, 121667, 121725, 121764, 121876, 122007, 122008, 122009, 122131, 122458, 122804, 123081, 123156, 123239, 123320, 123413, 123624, 123715, 123842, 123953];
x = 48;
y = 48;
current = 123953;
function changerecord(change) {
var at = records.indexOf(current);
if (change == -1) {
var next = current;//current because we are going back one
var previous = records[at - 3];//-2 because we started on record and are moving 2 back
var moveto = records[at - 2];
x = x - 1;
document.getElementById("count").innerHTML = x + ' of ' + y;
alert("AT : " + at + "\n" + "Previous : " + previous + "\n" + "Next : " + next + "\n" + "x : " + x + "\n" + "y : " + y + "\n" + "moveto : " + moveto + "\n");
var current = moveto;
//document.getElementById('iframe_records').src='recordtemplate.php?flight=' + moveto;
}
else if (change == +1) {
var previous = current;//current because we are going back one
var next = records[at + 2];//-2 because we started on record and are moving 2 back
var moveto = records[at + 1];
x = x + 1;
alert("AT : " + at + "\n" + "Previous : " + previous + "\n" + "Next : " + next + "\n" + "x : " + x + "\n" + "y : " + y + "\n" + "moveto : " + moveto + "\n");
document.getElementById("count").innerHTML = x + ' of ' + y;
var current = moveto;
//document.getElementById('iframe_records').src='recordtemplate.php?flight=' + moveto;
}
}; // lookup
You have some scoping and variable name problems in there:
First of, try to declare variables with var
var records = [...]
var variable = ...
so this is global in the current scope and you also can use it in the function, if the function is also in the scope.
You are just changing the value of current and than inside the function scope, you are using var current = ... Use another name, it's not like they are limited.
var test = 1;
function test() {
console.log(test); // Output: 1
var test = 2;
var oktopus = 8;
console.log(test); // Output: 2
console.log(oktopus); // Output: 8
}
console.log(test); // Output: 1
console.log(oktopus); // undefined oktopus
You can pass current as a parameters, to avoid this problem:
then when you call changerecord, it will be like this:
changerecord(change, 123953)
You have assigned a value to the variable current without declaring it with var keyword. When you do such this, i.e. assign a value to a non-declared variable, that variable become a property on global object (i.e. window).
Another point that you should know is when you declare a local variable with the same name as another variable in parent function scope, the most localized variable will be used in the inner function scope.
// ...
current = 123953; // Global variable
function changerecord(change) { // Local variable
var at = records.indexOf(current); // Local variable will be used
if (change==-1) // Also local one
{
var next = current; // Still local one!
// ...
Note that window.current should work.
try:
$(document).ready(function(){
changerecord(change);
});

toMatch Not Working

Does anyone know why this isn't passing?
function correctColorDisplay(message, player_turn, selector) {
if ((message > 0) && (player_turn != 0)) {
return $(selector).append("<li>" + message + " " + "color(s) are present but not in the correct position in Round " + player_turn + ".</li>");
}
}
Jasmine:
describe('#correctColorDisplay', function(){
it('returns a message to the user displaying if a correct color (not positions) was chosen', function(){
var message = 2
var playerTurn = 2
var selector = $('<li></li>')
correctColorDisplay(message,playerTurn, selector)
expect(selector).toMatch("<li>" + message + " " + "color(s) are present but not in the correct position in Round " + playerTurn + ".</li>")
});
});
The error I keep getting is this giant message: Expected { 0 : HTMLNode, length : 1, jquery : '1.11.0', constructor : Function, selector : '', toArray : Function, get : Function, pushStack : Function, each, etc (it goes on much longer)
You are trying to match a newly created HTMLNode with a regular expression (that is basically just a string in this case).
The toMatch function of Jasmine is for regular expressions.
I'm not entirely familiar with Jasmine, but I'm guessing you're looking for something like:
describe('#correctColorDisplay', function(){
it('returns a message to the user displaying if a correct color (not positions) was chosen', function() {
var message = 2;
var playerTurn = 2;
var selector = $('<li></li>');
selector = correctColorDisplay(message, playerTurn, selector);
expect(selector).toEqual( $("<li><li>" + message + " " + "color(s) are present but not in the correct position in Round " + playerTurn + ".</li></li>") );
});
});
If that doesn't work, I suggest you look into jasmine-jquery.

Javascript - Count the number of instances of a particular string from a variable

I am having trouble getting my code to count the number of times the word 'Yes' appears in a variable. It works if I replace the variable with the string 'YesYesYes.' The result is 3. I want to do the same, but from a variable instead.
Here is my code.
function getAllAnswers() {
var var_allAnswers = document.querySelector('input[name="Q1"]:checked').value + document.querySelector('input[name="Q2"]:checked').value + document.querySelector('input[name="Q3"]:checked').value + document.querySelector('input[name="Q4"]:checked').value + document.querySelector('input[name="Q5"]:checked').value + document.querySelector('input[name="Q6"]:checked').value + document.querySelector('input[name="Q7"]:checked').value + document.querySelector('input[name="Q8"]:checked').value + document.querySelector('input[name="Q9"]:checked').value + document.querySelector('input[name="Q10"]:checked').value + document.querySelector('input[name="Q11"]:checked').value + document.querySelector('input[name="Q12"]:checked').value + document.querySelector('input[name="Q13"]:checked').value + document.querySelector('input[name="Q14"]:checked').value + document.querySelector('input[name="Q15"]:checked').value + document.querySelector('input[name="Q16"]:checked').value + document.querySelector('input[name="Q17"]:checked').value + document.querySelector('input[name="Q18"]:checked').value + document.querySelector('input[name="Q19"]:checked').value + document.querySelector('input[name="Q20"]:checked').value;
document.getElementById("AllAnswers").innerHTML = var_allAnswers;
}
function yesCount() {
var var_yesCount = var_allAnswers.split("Yes").length - 1;
document.getElementById("YesCount").innerHTML = var_yesCount;
}
function noCount() {
var var_noCount = var_allAnswers.split("No").length - 1;
document.getElementById("NoCount").innerHTML = var_noCount;
}
Here is my markup.
<button onclick="yesCount()">Yes Count</button><br/>
Yes Count: <p id="YesCount"></p><br/><br/>
<button onclick="noCount()">No Count</button><br/>
No Count: <p id="NoCount"></p><br/><br/>
All Answers: <p id="AllAnswers"></p><br/><br/>
Does anyone have any ideas?
The variable var_allAnswers called in the yesCount and noCount functions is out of scope, meaning it's inaccessible to your functions. A somewhat hackish fix:
(function()
{
var var_allAnswers;
function getAllAnswers() {
var_allAnswers = document.querySelector('input[name="Q1"]:checked').value + document.querySelector('input[name="Q2"]:checked').value + document.querySelector('input[name="Q3"]:checked').value + document.querySelector('input[name="Q4"]:checked').value + document.querySelector('input[name="Q5"]:checked').value + document.querySelector('input[name="Q6"]:checked').value + document.querySelector('input[name="Q7"]:checked').value + document.querySelector('input[name="Q8"]:checked').value + document.querySelector('input[name="Q9"]:checked').value + document.querySelector('input[name="Q10"]:checked').value + document.querySelector('input[name="Q11"]:checked').value + document.querySelector('input[name="Q12"]:checked').value + document.querySelector('input[name="Q13"]:checked').value + document.querySelector('input[name="Q14"]:checked').value + document.querySelector('input[name="Q15"]:checked').value + document.querySelector('input[name="Q16"]:checked').value + document.querySelector('input[name="Q17"]:checked').value + document.querySelector('input[name="Q18"]:checked').value + document.querySelector('input[name="Q19"]:checked').value + document.querySelector('input[name="Q20"]:checked').value;
document.getElementById("AllAnswers").innerHTML = var_allAnswers;
}
function yesCount() {
var var_yesCount = var_allAnswers.split("Yes").length - 1;
document.getElementById("YesCount").innerHTML = var_yesCount;
}
function noCount() {
var var_noCount = var_allAnswers.split("No").length - 1;
document.getElementById("NoCount").innerHTML = var_noCount;
}
})();
Though you should really be passing the var_allAnswers variable around in your function calls as an argument.
The local variable var_allAnswers you declared in getAllAnswers() can't be used in another function, instead you shoud declare your variable as Global or create a function that returns the variable to deal with. Ex:
var var_allAnswers;
function getAllAnswers() {
var_allAnswers = document.querySelector('...
document.getElementById("AllAnswers").innerHTML = var_allAnswers;
}
getAllAnswers();
It appears you have a problem of scope here.
A var defines a varable which is available only in the block containing it { }
So, when you exit getAllAnswers() your variable var_allAnswers is discarded.
You need to reinitialize it before you could reuse it
function yesCount() {
var_allAnswers = document.querySelector('input[name="Q1"]:checked').value
var var_yesCount = var_allAnswers.split("Yes").length - 1 ;
document.getElementById("YesCount").innerHTML = var_yesCount;
}
I also think it's a problem of scope. In the yesCount() and noCount() functions, the variable var_allAnswers cannot be referred. Marcel's answer is right.
You may want to learn about the block scope in javascript. Here is an article about that:
http://danbeam.org/blog/2011/05/23/turns-out-there-is-block-scope-in-javascript-kinda/

Avoiding use of eval() to dynamically build event handlers

I'm struggling with managing dynamically built event handlers in javascript.
In several places, I build forms, or controls in which specific events (mainly mouseovers, mouse-outs, clicks) need to be handled.
The trick is that in a significant number of cases, the event handler itself needs to incorporate data that is either generated by, or is passed-into the function that is building the form or control.
As such, I've been using "eval()" to construct the events and incorporate the appropriate data, and this has worked somewhat well.
The problem is I keep seeing/hearing things like "You should never use eval()!" as well as a couple of increasingly ugly implementations where my dynamically-built event handler needs to dynamically build other event handlers and the nested evals are pretty obtuse (to put it mildly).
So I'm here, asking if someone can please show me the better way (native javascript only please, I'm not implementing any third-party libraries!).
Here's a crude example to illustrate what I'm talking about:
function CreateInput(controlName,type,activeStyle,dormantStyle,whenClicked)
{
var inp = document.createElement('input');
inp.id = controlName;
inp.type = type;
inp.style.cssText = dormantStyle;
eval("inp.onfocus = function() { this.style.cssText = '" + activeStyle + "'; }");
eval("inp.onblur = function() { this.style.cssText = '" + dormantStyle + "'; }");
eval("inp.onclick = function() { " + whenClicked + "; }");
return inp;
}
This function obviously would let me easily create lots of different INPUT tags and specify a number of unique attributes and event actions, with just a single function call for each. Again, this is an extremely simplified example, just to demonstrate what I'm talking about, in some cases with the project I'm on currently, the events can incorporate dozens of lines, they might even make dynamic ajax calls based on a passed parameter or other dynamically generated data. In more extreme cases I construct tables, whose individual rows/columns/cells may need to process events based on the dynamically generated contents of the handler, or the handler's handler.
Initially, I had built functions like the above as so:
function CreateInput(controlName,type,activeStyle,dormantStyle,whenClicked)
{
var inp = document.createElement('input');
inp.id = controlName;
inp.type = type;
inp.style.cssText = dormantStyle;
inp.onfocus = function() { this.style.cssText = activeStyle; };
inp.onblur = function() { this.style.cssText = dormantStyle; };
eval("inp.onclick = function() { " + whenClicked + "; }");
return inp;
}
...but I found that whatever the last assigned value had been for "activeStyle", and "dormantStyle" became the value used by all of the handlers thusly created (instead of each retaining its own unique set of styles, for example). That is what lead me to using eval() to "lock-in" the values of the variables when the function was created, but this has lead me into nightmares such as the following:
(This is a sample of one dynamically-built event-handler that I'm currently working on and which uses a nested eval() function):
eval("input.onkeyup = function() { " +
"InputParse(this,'ucwords'); " +
"var tId = '" + myName + This.nodeName + "SearchTable" + uidNo + "'; " +
"var table = document.getElementById(tId); " +
"if (this.value.length>2) { " +
"var val = (this.value.indexOf(',') >=0 ) ? this.value.substr(0,this.value.indexOf(',')) : this.value; " +
"var search = Global.LoadData('?fn=citySearch&limit=3&value=' + encodeURI(val)); " +
"if (table) { " +
"while (table.rows.length>0) { table.deleteRow(0); } " +
"table.style.display='block'; " +
"} else { " +
"table = document.createElement('table'); " +
"table.id = tId; " +
"ApplyStyleString('" + baseStyle + ";position=absolute;top=20px;left=0px;display=block;border=1px solid black;backgroundColor=rgba(224,224,224,0.90);zIndex=1000;',table); " +
"var div = document.getElementById('" + divName + "'); " +
"if (div) { div.appendChild(table); } " +
"} " +
"if (search.rowCount()>0) { " +
"for (var i=0; i<search.rowCount(); i++) { " +
"var tr = document.createElement('tr'); " +
"tr.id = 'SearchRow' + i + '" + uidNo + "'; " +
"tr.onmouseover = function() { ApplyStyleString('cursor=pointer;color=yellow;backgroundColor=rgba(40,40,40,0.90);',this); }; " +
"tr.onmouseout = function() { ApplyStyleString('cursor=default;color=black;backgroundColor=rgba(224,224,224,0.90);',this); }; " +
"eval(\"tr.onclick = function() { " +
"function set(id,value) { " +
"var o = document.getElementById(id); " +
"if (o && o.value) { o.value = value; } else { alert('Could not find ' + id); } " +
"} " +
"set('" + myName + This.nodeName + "CityId" + uidNo + "','\" + search.id(i)+ \"'); " +
"set('" + myName + This.nodeName + "ProvId" + uidNo + "','\" + search.provId(i)+ \"'); " +
"set('" + myName + This.nodeName + "CountryId" + uidNo + "','\" + search.countryId(i) + \"'); " +
"set('" + input.id + "','\" + search.name(i)+ \"'); " +
"}\"); " +
"var td = document.createElement('td'); " +
"var re = new RegExp('('+val+')', 'gi'); " +
"td.innerHTML = search.name(i).replace(re,'<span style=\"font-weight:bold;\">$1</span>') + ', ' + search.provinceName(i) + ', ' + search.countryName(i); " +
"tr.appendChild(td); " +
"table.appendChild(tr); " +
"} " +
"} else { " +
"var tr = document.createElement('tr'); " +
"var td = document.createElement('td'); " +
"td.innerHTML = 'No matches found...';" +
"tr.appendChild(td); " +
"table.appendChild(tr); " +
"} " +
"} else { " +
"if (table) table.style.display = 'none'; " +
"} " +
"} ");
Currently, I'm having problems getting the nested eval() to bind the ".onclick" event to the table-row, and, as you can see, figuring out the code is getting pretty hairy (debugging too, for all the known reasons)... So, I'd really appreciate it if someone could point me in the direction of being able to accomplish these same goals while avoiding the dreaded use of the "eval()" statement!
Thanks!
And this, among many other reasons, is why you should never use eval. (What if those values you're "baking" in contain quotes? Oops.) And more generally, try to figure out why the right way doesn't work instead of beating the wrong way into submission. :)
Also, it's not a good idea to assign to on* attributes; they don't scale particularly well. The new hotness is to use element.addEventListener, which allows multiple handlers for the same event. (For older IE, you need attachEvent. This kind of IE nonsense is the primary reason we started using libraries like jQuery in the first place.)
The code you pasted, which uses closures, should work just fine. The part you didn't include is that you must have been doing this in a loop.
JavaScript variables are function-scoped, not block-scoped, so when you do this:
var callbacks = [];
for (var i = 0; i < 10; i++) {
callbacks.push(function() { alert(i) });
}
for (var index in callbacks) {
callbacks[index]();
}
...you'll get 9 ten times. Each run of the loop creates a function that closes over the same variable i, and then on the next iteration, the value of i changes.
What you want is a factory function: either inline or independently.
for (var i = 0; i < 10; i++) {
(function(i) {
callbacks.push(function() { alert(i) });
})(i);
}
This creates a separate function and executes it immediately. The i inside the function is a different variable each time (because it's scoped to the function), so this effectively captures the value of the outer i and ignores any further changes to it.
You can break this out explicitly:
function make_function(i) {
return function() { alert(i) };
}
// ...
for (var i = 0; i < 10; i++) {
callbacks.push(make_function(i));
}
Exactly the same thing, but with the function defined independently rather than inline.
This has come up before, but it's a little tricky to spot what's causing the surprise.
Even your "right way" code still uses strings for the contents of functions or styles. I would pass that click behavior as a function, and I would use classes instead of embedding chunks of CSS in my JavaScript. (I doubt I'd add an ID to every single input, either.)
So I'd write something like this:
function create_input(id, type, active_class, onclick) {
var inp = document.createElement('input');
inp.id = id;
inp.type = type;
inp.addEventListener('focus', function() {
this.className = active_class;
});
inp.addEventListener('blur', function() {
this.className = '';
});
inp.addEventListener('click', onclick);
return inp;
}
// Called as:
var textbox = create_input('unique-id', 'text', 'focused', function() { alert("hi!") });
This has some problems still: it doesn't work in older IE, and it will remove any class names you try to add later. Which is why jQuery is popular:
function create_input(id, type, active_class, onclick) {
var inp = $('<input>', { id: id, type: type });
inp.on('focus', function() {
$(this).addClass(active_class);
});
inp.on('blur', function() {
$(this).removeClass(active_class);
});
inp.on('click', onclick);
return inp;
}
Of course, even most of this is unnecessary—you can just use the :focus CSS selector, and not bother with focus and blur events at all!
You don't need eval to "lock in" a value.
It's not clear from the posted code why you're seeing the values change after CreateInput returns. If CreateInput implemented a loop, then I would expect the last values assigned to activeStyle and dormantStyle to be used. But even calling CreateInput from a loop will not cause the misbehavior you describe, contrary to the commenter.
Anyway, the solution to this kind of stale data is to use a closure. JavaScript local variables are all bound to the function call scope, no matter if they're declared deep inside the function or in a loop. So you add a function call to force new variables to be created.
function CreateInput(controlName,type,activeStyle,dormantStyle,whenClicked)
{
while ( something ) {
activeStyle += "blah"; // modify local vars
function ( activeStyle, dormantStyle ) { // make copies of local vars
var inp = document.createElement('input');
inp.id = controlName;
inp.type = type;
inp.style.cssText = dormantStyle;
inp.onfocus = function() { this.style.cssText = activeStyle; };
inp.onblur = function() { this.style.cssText = dormantStyle; };
inp.onclick = whenClicked;
}( activeStyle, dormantStyle ); // specify values for copies
}
return inp;
}

dateformat is divided and i get totally different value

i have a little javascript that should bring some values to change the link, but the problem is that date format is written like: dd/mm/year thus the day is divided by month then by year :) here is the function:
function show_sales(employee_id,start_date,finish_date)
{
var url_str = "#request.self#?fuseaction=objects2.popup_showsales_emp"
url_str = url_str + '&employee_id=' + employee_id;
url_str = url_str + '&start_date=' + start_date;
url_str = url_str + '&finish_date=' + finish_date;
AjaxPageLoad(url_str,'salesdiv_' + employee_id,1,'Yükleniyor');
}
as u can see i want to get the start date and finish date to change the link, but instead it counts the value )) so instead of getting: 02/01/2012 i get: 0.0009940357852882703 :) thank you all for the help!
i hope there is a prob in function call
function show_sales(1,'12/3/2008','15/5/2012');
make sure that date is formatted as string
I am not quite sure if I have understand you but this may help:
function show_sales(employee_id,start_date,finish_date)
{
var url_str = "#request.self#?fuseaction=objects2.popup_showsales_emp"
url_str = url_str + '&employee_id=' + encodeURIComponent(employee_id);
url_str = url_str + '&start_date=' + encodeURIComponent(start_date);
url_str = url_str + '&finish_date=' + encodeURIComponent(finish_date);
AjaxPageLoad(url_str,'salesdiv_' + employee_id,1,'Yükleniyor');
}

Categories