I have a recusive function that is supposed to loop through a json object and output the expression. However, my recusion seems to be off because it's outputting field1 != '' AND field3 == '' when it should be outputting field1 != '' AND field2 == '' AND field3 == ''
I've tried a couple different things and the only way I can get it to work is by creating a global variable outstring instead of passing it to the function. Where am I off? When I step through it, i see a correct result but once the stack reverses, it start resetting outstring and then stack it back up again but leaves out the middle (field2).
JSFiddle
function buildString(json, outstring) {
var andor = json.condition;
for (var rule in json.rules) {
if (json.rules[rule].hasOwnProperty("condition")) {
buildString(json.rules[rule], outstring);
} else {
var field = json.rules[rule].id;
var operator = json.rules[rule].operator;
var value = json.rules[rule].value == null ? '' : json.rules[rule].value;
outstring += field + ' ' + operator + ' ' + value;
if (rule < json.rules.length - 1) {
outstring += ' ' + andor + ' ';
}
}
}
return outstring;
}
var jsonObj = {"condition":"AND","rules":[{"id":"field1","operator":"!= ''","value":null},{"condition":"AND","rules":[{"id":"field2","operator":"== ''","value":null}]},{"id":"field3","operator":"== ''","value":null}]};
$('#mydiv').text(buildString(jsonObj, ""));
The function has a return of a string.
When you call the function recursively from within itself, you aren't doing anything with the returned string from that instance, just calling the function which has nowhere to return to
Change:
if (json.rules[rule].hasOwnProperty("condition")) {
buildString(json.rules[rule], outstring);
}
To
if (json.rules[rule].hasOwnProperty("condition")) {
// include the returned value in concatenated string
outstring += buildString(json.rules[rule], outstring);
}
DEMO
Why so complicated?
function buildString(obj) {
return "condition" in obj?
obj.rules.map(buildString).join(" " + obj.condition + " "):
obj.id + " " + obj.operator + " " + string(obj.value);
}
//this problem occurs quite often, write a utility-function.
function string(v){ return v == null? "": String(v) }
Related
I don't understand why the temp variable is only returning false. I have tried == just to see if using strict comparison was the issue, but it didn't change. Just to double check, I'm making sure the variables are of the same type by printing their type in console.
Another odd thing that is happening is when I use this line, console.log('temp = ' + temp); to see what is inside of temp, nothing but a blank space will print. But if I use console.log(temp);, it will print what is stored in temp. The console.log('temp = ' + temp); seems to have fixed itself, so nevermind with that issue, but it's still not returning true.
var upFormData = formData.toUpperCase();
console.log('Form Data: ' + upFormData);
degrees[str] = [];
degrees[str][0] = data[0];
for(var i = 1; i < data.length; i++)
{
var temp = data[i][5].toUpperCase();
console.log(temp);
//console.log('temp = ' + temp);
console.log('upFormData = ' + upFormData + ' ' + typeof upFormData + ' ' + typeof temp);
if(upFormData === temp)
{
console.log('MATCH');
}
else
{
console.log('NOT A MATCH');
//console.log(temp);
//console.log('upFormData = ' + upFormData + ' ' + typeof upFormData + ' ' + typeof temp);
}
Results of this script:
Can someone help explain what I'm not doing? And please let me know if you need more information.
EDIT:
Looks like you are want to check if the value entered in form (formData) is in data array.
Use some
var upFormData = formData.trim().toUpperCase();
var hasFormData = data.some( s => s[5].trim().toUpperCase() === upFormData ); //hasFormData will return true if any value matches
If you want to filter out data values which matches forData value, use filter
var matchedData = data.filter( s => s[5].trim().toUpperCase() === upFormData );
I'm trying to build a query parameter for when doing a search, I managed to build it with input field however there's a select dropdown menu to select other values.
<input type="text" class="dd">
<select name="" class="sel">
<option value=""></option>
<option value="Prepare">Prepare</option>
<option value="Ready">Ready</option>
<option value="Cancel">Cancel</option>
</select>
<button onclick="buildQuery()">Build query</button>
jQuery code for query building the query param
function buildQuery(){
var result = "?";
var getVal = $('input.dd').val();
console.log('Input > ', getVal);
var getSelectVal = $('select.sel').val();
if (getVal != null && (getVal != "")) {
let inputValues = getVal
.split("\n")
.filter(function (str) { return str !== "" })
.join("&test=");
// then add it to the overall query string for all searches
result = result + 'test' + "=" + inputValues + "&";
console.log('Results > ', result);
}
Not sure how can I get the value from the select and construct it similar way to my input console.log output Results > ?test=f&
So if you fill in the input and select an option it the queryParam should say something like ?test=inputVal&test=selectVal or individual ?test=inputVal or ?test=selectVal
What I can do is copy the whole if() statement and replace the getVal with getSelectVal but it seems inefficient and duplicating the code.
Actual code --
newSearchParams.properties.forEach(function (inputSearch) {
// first reparse the input values to individual key value pairs
// Checks which field is not null and with empty string (space)
var getVal = $('input.input_' + inputSearch.name).val();
var getSelectVal = $('select.select_' + inputSearch.name).val();
if (getVal != null && (getVal != "")) {
let inputValues = getVal
.split("\n")
.filter(function (str) { return str !== "" })
.join("&" + inputSearch.name + "=");
// then add it to the overall query string for all searches
result = result + inputSearch.name + "=" + inputValues + "&";
}
}, this);
// remove trailing '&'
result = result.slice(0, result.length - 1);
return result;
Sample Fiddle
Edit: -- This is what I'm trying to get out of this question,
if(paramMethod == 'path'){
// build parameter api/id/1
} else if(paramMethod =='query'{
// build queryString api/apiPoint?id=1
} else if(paramMethod == 'none') {
// var result = "";
// return result;
}
If you're not worrying about IE < 9:
function buildQuery() {
return $('.dd, .sel')
.toArray()
.reduce(function(str, el) {
return str + (el.value ? el.name + '=' + el.value + '&' : '')
}, '?')
}
Working fiddle: https://jsfiddle.net/qk3d7bq1/2/
If you care about IE < 9:
function buildQuery() {
var query = '?'
$('.dd, .sel').each(function() {
if (this.value) {
query += this.name + '=' + this.value + '&'
}
})
return query
}
Working fiddle: https://jsfiddle.net/d51f5uyw/2/
Update
If you want to make this generically useful, just pass a selector string to buildQuery to select the exact things you want:
function buildQuery(selector) {
return $(selector)
.toArray()
.reduce(function(str, el) {
return str + (el.value ? el.name + '=' + el.value + '&' : '')
}, '?')
}
Fiddle: https://jsfiddle.net/qsxkz4qu/1/
Alternatively you could specify a container and have buildQuery find all of the form fields inside that container:
Fiddle: https://jsfiddle.net/uar5h3xe/1/
But buildQuery itself should not be defining any selection variables. That's configuration that should be passed to it.
Update
If you want to parameterize the whole thing, you could use something like what's shown at this fiddle: https://jsfiddle.net/uar5h3xe/4/
Okay, that title will sound a bit crazy. I have an object, which I build from a bunch of inputs (from the user). I set them according to their value received, but sometimes they are not set at all, which makes them null. What I really want to do, it make an item generator for WoW. The items can have multiple attributes, which all look the same to the user. Here is my example:
+3 Agility
+5 Stamina
+10 Dodge
In theory, that should just grab my object's property name and key value, then output it in the same fashion. However, how do I setup that if-statement?
Here is what my current if-statement MADNESS looks like:
if(property == "agility") {
text = "+" + text + " Agility";
}
if(property == "stamina") {
text = "+" + text + " Stamina";
}
if(property == "dodge") {
text = "+" + text + " Dodge";
}
You get that point right? In WoW there are A TON of attributes, so it would suck that I would have to create an if-statement for each, because there are simply too many. It's basically repeating itself, but still using the property name all the way. Here is what my JSFiddle looks like: http://jsfiddle.net/pm2328hx/ so you can play with it yourself. Thanks!
EDIT: Oh by the way, what I want to do is something like this:
if(property == "agility" || property == "stamina" || ....) {
text = "+" + text + " " + THE_ABOVE_VARIABLE_WHICH_IS_TRUE;
}
Which is hacky as well. I definitely don't want that.
if(['agility','stamina','dodge'].indexOf(property) !== -1){
text = "+" + text + " " + property;
}
If you need the first letter capitalized :
if(['agility','stamina','dodge'].indexOf(property) !== -1){
text = "+" + text + " " + property.charAt(0).toUpperCase() + property.substr(1);
}
UPDATE per comment:
If you already have an array of all the attributes somewhere, use that instead
var myatts = [
'agility',
'stamina',
'dodge'
];
if(myatts.indexOf(property) !== -1){
text = "+" + text + " " + property.charAt(0).toUpperCase() + property.substr(1);
}
UPDATE per next comment:
If you already have an object with the attributes as keys, you can use Object.keys(), but be sure to also employ hasOwnProperty
var item = {};
item.attribute = {
agility:100,
stamina:200,
dodge:300
};
var property = "agility";
var text = "";
if(Object.keys(item.attribute).indexOf(property) !== -1){
if(item.attribute.hasOwnProperty(property)){
text = "+" + text + " " + property.charAt(0).toUpperCase() + property.substr(1);
}
}
Fiddle: http://jsfiddle.net/trex005/rk9j10bx/
UPDATE to answer intended question instead of asked question
How do I expand the following object into following string? Note: the attributes are dynamic.
Object:
var item = {};
item.attribute = {
agility:100,
stamina:200,
dodge:300
};
String:
+ 100 Agility + 200 Stamina + 300 Dodge
Answer:
var text = "";
for(var property in item.attribute){
if(item.attribute.hasOwnProperty(property)){
if(text.length > 0) text += " ";
text += "+ " + item.attribute[property] + " " + property.charAt(0).toUpperCase() + property.substr(1);
}
}
It's unclear how you're getting these values an storing them internally - but assuming you store them in a hash table:
properties = { stamina: 10,
agility: 45,
...
}
Then you could display it something like this:
var text = '';
for (var key in properties) {
// use hasOwnProperty to filter out keys from the Object.prototype
if (h.hasOwnProperty(k)) {
text = text + ' ' h[k] + ' ' + k + '<br/>';
}
}
After chat, code came out as follows:
var item = {};
item.name = "Thunderfury";
item.rarity = "legendary";
item.itemLevel = 80;
item.equip = "Binds when picked up";
item.unique = "Unique";
item.itemType = "Sword";
item.speed = 1.90;
item.slot = "One-handed";
item.damage = "36 - 68";
item.dps = 27.59;
item.attributes = {
agility:100,
stamina:200,
dodge:300
};
item.durability = 130;
item.chanceOnHit = "Blasts your enemy with lightning, dealing 209 Nature damage and then jumping to additional nearby enemies. Each jump reduces that victim's Nature resistance by 17. Affects 5 targets. Your primary target is also consumed by a cyclone, slowing its attack speed by 20% for 12 sec.";
item.levelRequirement = 60;
function build() {
box = $('<div id="box">'); //builds in memory
for (var key in item) {
if (item.hasOwnProperty(key)) {
if (key === 'attributes') {
for (var k in item.attributes) {
if (item.attributes.hasOwnProperty(k)) {
box.append('<span class="' + k + '">+' + item.attributes[k] + ' ' + k + '</span>');
}
}
} else {
box.append('<span id="' + key + '" class="' + item[key] + '">' + item[key] + '</span>');
}
}
}
$("#box").replaceWith(box);
}
build();
http://jsfiddle.net/gp0qfwfr/5/
console.log(index + ",\"" + array+ "\"");
This produces:
Name "Tree"
Name "Undefined"
Name "park"
How can I have an output for
Name "Tree"
Name
Name "park"
where if the array variable is undefined then not print it
Create a function for logging.
function logValue(index, value) {
var val = ('"' + value + '"') || "";
index = '"' + index + '"';
console.log(index + " " + val);
}
Then use it like so.
logValue(index, array);
var i;
for(i=0;i<array.length; i += 1){
if(typeof array[i] !== "undefined"){
console.log(i + " " + Name);
}
}
your array probably contains names or not so...
no need to write functions for this simple check.
console.log(index+(array?' "'+array+'"':''));
example
http://jsfiddle.net/3znzY/
I use this function to validate one input element :
function validerInput(qte, qtemax) {
var floatRegex = /^((\d+(\.\d *)?)|((\d*\.)?\d+))$/;
if (floatRegex.test(qte.value)) {
var a = qte.value;
var b = qtemax;
if (a > b) {
alert('if qtemax : ' + qtemax + ', qte : ' + qte.value);
qte.value = '';
}
else {
alert('else qtemax : ' + qtemax + ', qte : ' + qte.value);
}
}
else {
qte.value = '';
}
}
but the problem is always the alert of else is launched and the first never I don't know the problem
do you have any idea :
the alert that is launched contains for example 234 and 5.66
The value property of an input element is stored as a string, so if you want to treat it as a number you'll need to convert it to one. You may have a similar issue with the value of qtemax too, it's impossible to say. Comparing strings alphabetically "234" comes before "5.66", then though numerically it's (much) greater. Use the parseFloat function:
var a = parseFloat(qte.value),
b = parseFloat(qtemax);