If else condition Javascript - javascript

I have four TextFields on my UI page.I get the input values of the user from all textfields for example values Textfield1.getvalue(),Textfield2.getvalue(),Textfield3.getvalue(),Textfield4.getvalue().
Now on a button click, I need to check which textfields are actually filled by the user and attach those values I need to send a http request to the server to query on the database. These values are used to filter values from a table. SO basically the values are "TABLE COLUMN" values. For this, I thought of using old school combinations like:
if (Textfield1.getvalue()=="" && Textfield2.getvalue()!=""){
//do something
}
else if (Textfield2.getvalue()=="" && Textfield3.getvalue()!=""){
//do something
}
else if (Textfield3.getvalue()=="" && Textfield4getvalue()!=""){
//do something
}
......
and so on.
This, I personally feel is not efficient and not a good programming way. I am pretty sure there might be some other way of doing it which I am not aware of and couldnt find googling it either. Can anyone share some ideas for a better solution.
Thanks in advance.

If you want to do something based on first field that has a value, at least that is what it looks like from your sample, you could do something like:
» Simple Fiddle. «
var do_something = {
0 : function(val) { console.log("Doing x width " + val)},
1 : function(val) { console.log("Doing y width " + val)},
2 : function(val) { console.log("Doing z width " + val)},
3 : function(val) { console.log("Doing w width " + val)},
}
$("#post").on("click", function() {
var val;
$(".test").each(function(i) {
val = $(this).val();
if (val) {
do_something[i](val);
return false; // Break
// (Or omit the break if you want to "do_something" with all fields
// having a value.)
}
});
});
Or, depending on various, a better solution could be:
var do_something2 = {
act1 : function(k, val) { console.log("Doing x width " + val + " k=" + k) },
act2 : function(k, val) { console.log("Doing y width " + val + " k=" + k) },
act3 : function(k, val) { console.log("Doing z width " + val + " k=" + k) }
};
$("#post2").on("click", function() {
var val;
$(".test").each(function(i) {
val = $(this).val();
if (val) {
do_something2[$(this).data("act")](i, val);
return false; // Break
}
});
});
Where you have input fields like this (dynamically or otherwise created):
<input type="text" data-act="act1" class="test" value="one" />
<input type="text" data-act="act2" class="test" value="two" />
This way you can also easily change what action is taken per field simply by setting the data-act value to wanted function.

One idea - check individual fields once and combine into a single unique value:
var c=0;
if (condition1) c+=1;
if (condition2) c+=2;
if (condition3) c+=4;
Etc. now every combination of conditions has a unique value associated with it and you can use a switch statement for cleaner flow.

Think of data instead of control flow. I'd suggest thinking of the problem this way:
Data -> Validation -> Side effects
All those steps must be uncoupled. Here's example, you may have to re-think your data to adapt your code:
// Data
var fields = [Textfield1, Textfield2, Textfield3, Textfield4];
// Validation
var valid = fields.filter(function(x) {
return x.getvalue();
});
// Side effects
valid.forEach(function(field) {
var value = field.getvalue();
// do something
});

Related

Check value against array and return another value

I'm building a click type game and I need to see if the answer the user selected is correct by comparing it to an array.
This is the JSON
{
quiztitle: "Select the States",
correct_answers: "9",
states: [
{
state_name: "Alabama",
image: "alabama_image",
answer: "correct"
},
{
state_name: "Alberta",
image: "alberta_image",
answer: "incorrect"
},
ect...
When a user clicks a button, it takes the value and needs to check if it's correct. What is the best way to do this.
This is my attempt so far:
$('body').on('click', '.matchBtns', function(){
var value = $(this.innerHTML);
if($.inArray(value, data.states)){
//its in the array
}else{
//its not
}
});
I'm unsure how to access the value 'answer' to check if correct or not
This is the html button
<button class="matchBtns">*State Name Here*</button>
You've got a bit of the way, but there's still a lot to do. First off, you don't want a jQuery object of the text inside the button; you just want the text. So you can do something like this:
var value = $(this).text();
Secondly. $.inArray won't work for two reasons. One - It's a multidimensional array of objects. Two - you don't just want to check if it's in the array; you want to check if it's in the array and has the correct property.
So, you could iterate over the array and see if any of the answers are correct:
$('body').on('click', '.matchBtns', function() {
var value = $(this).text();
var correct = false;
$.each(data.states, function(i, state) {
if ( state.state_name == value && state.answer == 'correct' ) {
correct = true;
return false; // break out of $.each()
}
});
if ( correct ) {
// true
}
else {
// false
}
});
Here's a working jsFiddle: https://jsfiddle.net/s0gtqjcL/
You could simplify this by storing answer (or correct) as a boolean, not a string. That way, you could do something like this:
if ( state.state_name == value && state.correct )
if you like underscore you may try:
$('body').on('click', '.matchBtns', function(){
var value = $(this.innerHTML);
if(_.contains(_.pluck(data.states, "answer"), value)) {
//is in the array
}
else{
//is not
}
});
_.pluck(array, "x") is a shorthand for _.map(array, function(x){return x.x;), so that you won't try to compare string and object
You are going to have to loop through the answers.
$('body').on('click', '.matchBtns', function(){
...
var value = this.innerHTML;
for (var i = 0,l = data.states.length; i< l; i++){
if (data.states[i].state_name === value && data.states[i].answer === 'correct'){
/// is correct
break; // to stop the loop
}else {
// not correct, continue
}
}
...
}

.each() function does not loop through my object

I have the following jquery function and it seems that the .each function never loop through my object (it goes right to the "$("#AppConnect").val(appConnectString);" line without iterating).
Here's the code :
$("input").focusin(function () {
if (!$(this).hasClass("appConnectData")) {
var key, value, appConnectString = "";
$(".appConnectData").each(function (index, element) {
if ($(element).hasClass("key")) {
key = $(element).val();
} else {
value = $(element).val();
}
if (!key && !value) {
appConnectString += key + "." + value + ";";
}
});
$("#AppConnect").val(appConnectString);
}
//alert($("#AppConnect").val());
});
What I've done to find the problem with no success so far :
Check if the $(".appConnectData") is empty
Check the .each syntax (you never know :p)
Insert a breakpoint to see if I have some errors
Put the content of $(".appConnectData") in a var and then loop through the said var
Maybe it is because my .each is inside a focusin function, or maybe I did something else wrong but I can't seem to find what.
I thank you all in advance for the help provided :)
I think the problem is the if condition, you should check key && value if you want to make sure key & value has a value.
if (key && value) {
appConnectString += key + "." + value + ";";
}
Demo: Fiddle
In each case, if key exists then value will not exist and vice-versa. so the correct logical operator would be or. even this is not enough!
You can separate if to test both key and value existence:
$("input").focusin(function () {
if (!$(this).hasClass("appConnectData")) {
var key, value, appConnectString = "";
$(".appConnectData").each(function (index, element) {
if ($(element).hasClass("key")) {
key = $(element).val();
} else {
value = $(element).val();
}
if (key) {
appConnectString += key".";
}
if(value){
appConnectString +=value;
}
if(key||value){
appConnectString +=";";
}
});
$("#AppConnect").val(appConnectString);
}
//alert($("#AppConnect").val());
});

Knockout Extension Issue - Better Solution?

I'm new to knockout, and still learning how best to work with it. I have a few input fields in an app which are tied to a bunch of calculations that update in real time. The fields on their own work great, and all is fine...
EXCEPT, I need to format the input as the user enters it, for display only (the raw data must be retained for the calculations, but 3 should appear as 3% or in another field 3000000 should appear as 3,000,000 etc.). I have this somewhat working, but I think there's a major flaw with my solution as the result is consistently buggy and it's possible to break the input field entirely.
So, an example of one of the input fields, which ties to another field to always equal 100%:
<input id='sm' data-bind='textInput: s_smixe' readonly='true'>
Is bound to:
self.s_smixebase = ko.observable(30);
self.s_smixe = ko.pureComputed({
read: function(){
return this.s_smixebase();
},
write: function(value){
if (parseFloat(value)<100) {
var otherValue = 100 - parseFloat(value);
this.s_smixebase(value);
this.s_rmixebase(otherValue);
} else {
value = 100;
this.s_smixebase(value);
this.s_rmixebase(0);
}
},
owner: this
}).extend({percent:{}});
self.s_smixeraw = self.s_smixe.raw;
Which is then extended by:
ko.extenders.percent = function(target) {
var raw = ko.observable();
var result = ko.computed({
read: function() {
var value = target();
if (value.toString().indexOf('%')===-1){
raw(parseFloat(value));
value = value + '%';
return value;
} else {
value = value.replace('%','');
raw(parseFloat(value));
value = value + '%';
return value;
}
},
write: target
}).extend({notify:'always'});
result.raw = raw;
return result;
};
So, what happens here, is that the first character input by the user formats correctly, the second character input by the user disappears, and the third joins the first and formats correctly. This happens the same if the field is computed or a regular observable, and the computed code is working fine without the extension applied. So to input 77% you would have to type 7 - X - 7 (where X can be any value since it gets lost to the process somewhere).
It should also be noted that I am using a virtual javascript numeric keyboard in this app so I am adding values via javascript (though this has not affected any of the other functionality, so I'm not sure why it would here).
Can anyone offer suggestions on what I'm doing wrong? What am I missing that is causing the input to be so buggy? I'm really determined not to ditch this notion of real-time input formatting as it makes for much cleaner presentation, but I if I have to I'll just format on blur.
Thanks in advance for any suggestions.
Because it's tricky to position the cursor properly when the formatting function replaces what you're typing as you type, I'd recommend having a field that has two modes: one where you're typing in it, and the other where it's displaying the formatted value. Which displays depends on cursor focus.
<div data-bind="with:pctInput">
<label>Value</label>
<input class="activeInput" data-bind='textInput: base, event:{blur:toggle}, visible:editing, hasFocus:editing' />
<input data-bind='textInput: formatted, event:{focus:toggle}, visible:!editing()' readonly='true' />
</div>
A working example is here:
http://jsfiddle.net/q473mu4w/1/
So, for anyone who comes across this later, I ended up using a modified version of #RoyJ 's solution from the thread mentioned in the initial comments. I do need to come up with a way to make this scale if I'm ever going to use it in larger projects, but it's sufficient for something with a small number of inputs. Also, in my case there are many formatted fields calculating their values based on the inputs, hence the multPercent and multNumber computed values. I wanted to ensure that all the inputs were carrying over properly to calculations. Here's a sample of the code with a working jsfiddle below:
<input data-bind="textInput:textPercent" />
<div data-bind="text:multPercent"></div>
<input data-bind="textInput:textNumber" />
<div data-bind="text:multNumber"></div>
and the accompanying javascript:
function dataBindings() {
var self = this;
self.percent = function(str){
var splice = str.toString().replace('%','');
splice = splice + '%';
return splice;
};
self.number = function(numStr){
var formatted;
if (Number(numStr) % 1) {
var integer = numStr.toString().replace(/\.\d+/g,'');
var decimal = numStr.toString().replace(/\d+\./g,'');
integer = integer.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,"); //add comma formatting
formatted = integer + '.' + decimal;
console.log('formatted = '+formatted);
return formatted;
} else {
formatted = numStr.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
return formatted;
}
};
self.displayPercent = ko.observable('5%');
self.rawPercent = ko.observable(5);
self.formattedPercent = ko.computed({
read: function() {
return self.displayPercent();
},
write: function(newValue) {
if (newValue==='') {
newValue = 0;
self.rawPercent(0);
var f = self.percent(newValue);
self.displayPercent(f);
} else {
if (newValue.charAt(0)==='0') {
newValue = newValue.slice(1);
}
self.rawPercent(parseFloat(newValue.toString().replace('%','')));
var f = self.percent(newValue);
self.displayPercent(f);
}
}
});
self.displayNumber = ko.observable('3,000');
self.rawNumber = ko.observable(3000);
self.formattedNumber = ko.computed({
read: function(){
return self.displayNumber();
},
write: function(newValue) {
if (newValue==='') {
newValue = 0;
self.rawNumber(0);
self.displayNumber('0');
} else {
if (newValue.charAt(0)==='0') {
newValue = newValue.slice(1);
}
newValue = newValue.replace(/(,)+/g,'');
self.rawNumber(parseFloat(newValue));
var n = self.number(newValue);
self.displayNumber(n);
}
}
});
self.multPercent = ko.computed(function(){
return self.percent(self.rawPercent() * self.rawPercent());
});
self.multNumber = ko.computed(function(){
return self.number(self.rawNumber() * self.rawNumber());
});
return {
textPercent: self.formattedPercent,
multPercent: self.multPercent,
textNumber: self.formattedNumber,
multNumber: self.multNumber
};
}
ko.applyBindings(new dataBindings());
http://jsfiddle.net/jschevling/mwbzp55t/

How do I dynamically add controls on a hierarchical structure using JavaScript?

I am trying to create a form dynamically . I should have categories and subcategories and questions . Here is a simple example where I am adding question elements dynamically:
var i = 1; // to hold increment
$('#add').click(function() {
var p = $(this).closest('p'),
i = $(p).length;
$(p).before('<p> <label> Question ' + i + ': <input type="text" id="question_' + i + '"> </label> </p>');
return false;
});
$('#del').click(function() {
$("p label").last().remove();
i -= 1;
return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<div>
<p> <label> Question 1: <input type="text" id="question_1"> </label> </p>
<p> Add Question </p>
<p> Del Question </p>
</div>
How can I add categories, so that a category can contain multiple subcategories, which in return can also contain subcategories. Each category should also be able to contain questions. So that my form looks like this :
Test Form
Investment // a category
Real Estate // a subcategory
How much was spent ? // a question
What is the time frame ? // a question
Automobiles // a subcategory
How many vehicles ? // a question
What is the total? // a question
Charity // a category
How much was spent ? // a question
Donations // a subcategory
When started ? // a question
Other // a subcategory
What is the timeframe ? // a question
My current code only creates questions. I tried to create categories but got stuck with the recursion bugs . I tried to read the jtree API but I am not sure it is what I need. I also tried to find a website that would allow to create such a form so that I could take a look at their JavaScript, but could not find such a website. Can someone help me understand how to accomplish this?
The way I would design this would be to have a class(by using a constrcutor function) called "category" in JS such that it can contain other "categories" within itself, maybe in an array. I would make this class also hold a a questions array. Now, without thinking about the html too much, I have a nice and clear model of what the world looks like. In the next step, I will write a single function that can take one of these category instances and generate the dom. This function drawCategory will use a helper function that can probably be an inner function in JS that knows how to generate the dom for a category that does not contain any categories(leaf node in other words), drawCategory uses that helper function intelligently and returns the entire dom for a single category instance. Next I simply iterate over how many ever category instances I have and keep passing the category instance to drawCategory which automagically does the right thing and returns the right dom each time. To avoid multiple dom updates, I would just generate the dom for each of the categories, hold it somewhere, build the entire dom just once and append it to some target element.
edit: Second prototype delivered.
The answer really depends on what you're creating "dynamically", which I'm not clear on. Since I'm not allowed to request clarification until I provide useful answers for rep, here's a jscript that does something useful sorta like what you're saying.
If I really did this myself, I'd integrate an XML file and generate the html entirely from JSON or something. Or at least populate the initial page from js. The solution you see here is horribly sloppy and tightly couples the html to the js.
http://jsfiddle.net/P8X3B/109/ (prototype question adder, other controls present, not implemented)
NEW: http://jsfiddle.net/y29vc5k0/28/ (prototype question and category adder)
/**
***
* questions and categories example
* by Jason D'Aquila
* 23 Jan 2015
* created as prototype of answer to stackoverflow question posted at: http://stackoverflow.com/questions/27772009/
*
* relies on at least jQuery 1.4 ; browsers supporting getter definitions with Object.defineProperty
*/
/* GLOBAL */
function cleaner(text) {
var s = text.replace(/(<|>)/g, '\\$1')
.replace(/ /g, '_')
.replace(/[!"#$%&'()*+,.\/:;<=>?#[\\\]^`{|}~]/g, '');
return s; //can't split a return line
}
/* injective function jQuery objs => String; compact output
* not actually achieved, but this function isn't called in this program anyway
*/
function injectJQueryObjToStr(jqueryObj) {
return ("" + jqueryObj.length) + jqueryObj.attr("id") ? " id: " + jqueryObj.attr("id") : jqueryObj;
//can definitely improve this function
}
canon = ({
/* contract: No enumerable property of canon has the name of an html tag
*/
outputField: $('#out'),
categoriesList: $('#categories'),
/* cannot actually canonize this; see below */
//questionsDropdown: (function () { //references must be invocations ofc
// return $('#questions_del');
//}),
init: function (undef) {
//* //single slash comment toggle
//this.questionsDropDown = (function(nothing) {return nothing;}());
Object.defineProperty(this, "questionsDropdown", {
//cannot actually canonize this
//a setter is only way to "store" a function lookup used with variable access syntax
configurable: true,
enumerable: true,
get: function () {
return $('#questions_del');
}
});
//*/
this.init = undef;
return this;
}
}).init(); //self-initializing object canon
/* CLOSURES */
/* referencing contexts:
* A -- the anonymous function in $('#add') .click
* B -- the anonymous function in $('#cat') .click
*/
//referred by: A, B
var addCategoryIfNotExists = function (desiredName) {
var category_in = desiredName;
var f = cleaner;
//var FF = _compose_ function(x){return 'cat_'+x; } # cleaner
if ($('#cat_' + f(category_in)).length) {
return $('#cat_' + f(category_in));
} else {
$("<p></p>").attr({
id: 'cat_' + f(category_in)
}).html('<label class="cat_' + f(category_in) + '">' + f(category_in) + '</label>').prependTo(canon.outputField);
//another option is .clone()
canon.categoriesList.append($('<option value="' + f(category_in) + '" />'));
return $('#cat_' + f(category_in));
}
};
function inputFieldAt(locale) {
//return $('input', $(locale).closest('p'));
return $(locale).closest('p').find('input');
}
//consts
var QUESTION_PARENT_ELEMENT_TYPE = "p"; //ideally a preprocessor subs this
/* /CLOSURES */
$('#add').click(
//create closure for i=question #
(function () {
var i = 1;
return function () {
var qid, qidlitl;
var category_input;
i = i + 1;
qidlitl = 'question_' + i;
qid = '"question_' + i + '"'; //quotes for HTML attr setting
var category_el;
//* //single-slash comment toggle
//category_input = $('input', $(this).closest('p')).val();
category_input = inputFieldAt(this).val();
category_el = addCategoryIfNotExists(category_input);
//check category_el === canon.outputField.find('#' + 'cat_' + cleaner(category_input) )
/*/
category_el = document.getElementById("out");
//*/
$('<' + QUESTION_PARENT_ELEMENT_TYPE + '></' + QUESTION_PARENT_ELEMENT_TYPE + '>').html('<label for=' + qid + '> Question ' + i + ': </label><input type="text" id=' + qid + '>').appendTo(category_el);
$("<option></option>").attr({
"class": "questions_options",
value: qidlitl
}).text('Question ' + i + '').appendTo(canon.questionsDropdown);
return false; //callback contract
};
})() //SIF to get closure for i = 1 + number of questions ever generated
); //$('#add').click
$('#del').click(function () {
var qselect = canon.questionsDropdown[0]; //This [0] is the inelegance of mixing frameworks
$('#' + qselect.options[qselect.selectedIndex].value + '')
.closest(QUESTION_PARENT_ELEMENT_TYPE).remove();
qselect.remove(qselect.selectedIndex);
return false;
});
$('#cat').click(function () {
//add category and return false exit signal unless add_category returned literal not false (i.e. true)
var category_input;
//category_input = $('input', $(this).closest('p')).val();
category_input = inputFieldAt(this).val();
var res = addCategoryIfNotExists(category_input);
//return !!(res && (res === true)); //!! might get eliminated by compiler?
return res && (res === true) ? true : false; //equality < logical AND < ternary
});
//EOF
The html changed slightly. See the jsfiddle.
So, weeks later, I learn that you actually cannot canonicalize most DOM lookups or jqueries. Here is a jsfiddle with categories and questions. The next prototype will have subcategories, and the final answer will let you delete categories and subcategories with no subcategories or questions.
There is a mystery to me in this jscript. When you add questions, they appear before the one in the html, even though $.appendTo() is used on the containing <\p> .

How can I remember combination states?

I'm having a logic problem with an implementation of combination rules in Javascript.
In short:
I define which checkboxes cannot be 'on' together with eachother in a JSON object.
If I click on measure 1 -> measures 7 and 8 get grayed out, this is correct.
If I click on measure 4 -> measures 8, 9, 10 and 11 get grayed out, this is correct too.
Now, if I click again on measure 4 -> measure 8 gets active again, but shouldn't be, because the JSON 'rules' state that since measure 1 is still checked, measure 8 must be grayed.
What's a smart way to solve this logic problem? Thanks in advance!
Basically, how do I remember that clicking 'measure 1' already disabled 'measure 8', so that toggling 'measure 4' won't accidentally re-enable 'measure 8' with 'measure 1' still 'on'?
All code here: https://gist.github.com/1055968
Interactive: http://jsfiddle.net/gnijholt/58zuR/
Well logically i'd do something like this:
when you tick a checkbox, you create
an object which stores the rules that
are applied.
when i untick a checkbox, i will
remove that rule from the memory
object and before unticking each
checkboxes i'll go through the memory
object to see if there are any
conflicting rules. If there is one
conflicting rules, i do not gray out
the checkbox.
I'm trying to implement this.
EDIT - i'v implemented my idea. here is a fiddle http://jsfiddle.net/Tvs7E/1/
function createObjectsWithRules(rulesApplied){
var presentBlock = {};
for (var checkboxid in rulesApplied){
var presentCombos = rulesApplied[checkboxid];
for(var key in presentCombos) {
var obj = presentCombos[key];
for(var prop in obj) {
var s = obj[prop];
presentBlock[s] = true;
}
}
}
return presentBlock;
}
$(document).ready(function() {
var rulesApplied= {};
$('input').change(function() {
current_cb = this;
if ($(this).attr("checked")) {
// toggle on
console.log("You ticked on " + current_cb.id);
combos = JSONSelect.match("." + current_cb.id, combinations);
rulesApplied[current_cb.id] = combos;
for(var key in combos) {
var obj = combos[key];
for(var prop in obj) {
var s = obj[prop];
$('#' + s).attr('disabled', 'disabled');
console.log("I disable " + obj[prop]);
}
}
console.log(rulesApplied);
return;
}
// toggle off
console.log("You ticked off " + current_cb.id);
combos = JSONSelect.match("." + current_cb.id, combinations);
console.log(combos);
delete rulesApplied[current_cb.id];
console.log(rulesApplied);
presentRules = createObjectsWithRules(rulesApplied);
console.log(presentRules);
for(var key in combos) {
var obj = combos[key];
for(var prop in obj) {
var s = obj[prop];
if (!presentRules[s]){
$('#' + s).removeAttr('disabled');
console.log("I enable " + obj[prop]);
}
}
}
return;
});
});
Try changing your .change event to this
http://paste.pocoo.org/show/424704/
It does what it did before, only without using empty returns to emulate an if-else.
Then when it is done with the clicked input, it loops through all the input to "re-disable" whatever needs to be disabled.
Only tested it lightly
And I can see that while I was writing this, davin was making the same suggestion in the comments. It's the same thing, just with a code example.

Categories