Checking multiple variables' values to make sure they all match - javascript

How do I efficiently check to see if multiple variables' values all match? The following function should return true if they match and false if they don't:
function projectIsLocked (data) {
if (data.ArchiveSnapshotID === data.CurrentSnapshotID === data.LiveSnapshotID) {
return true;
}
return false;
}
I thought I could just use if (data.ArchiveSnapshotID === data.CurrentSnapshotID === data.LiveSnapshotID) but it doesn't seem to work.
Ideas for something simple?

If there are just 3 comparisons , then this should be enough.
function projectIsLocked (data) {
var archive = data.ArchiveSnapshotID;
var current = data.CurrentSnapshotID;
var live = data.LiveSnapshotID;
return (archive === current && current === live)
}

Why not push them all to an array. This way you can use as many.
function check_for_equal_array_elements(my_array){
if (my_array.length == 1 || my_array.length == 0) {
return true;
}
for (i=0;i<my_array.length;i++){
if (i > 0 && my_array[i] !== my_array[i-1]) {
return false;
}
}
return true;
}
//Example:
var my_array = [];
my_array.push(5);
my_array.push(5);
// will alert "true"
alert("all elements equal? "+check_for_equal_array_elements(my_array));
my_array.push(6);
// will alert "false"
alert("all elements equal? "+check_for_equal_array_elements(my_array));

The problem here is, that a part of the logical expression is evaluated and then compared, so data.ArchiveSnapshotID === data.CurrentSnapshotID evaluated to "true" and data.LiveSnapshotID is checked against true, which you can see here (LiveSnapshotID was changed to boolean true):
function projectIsLocked (data) {
if (data.ArchiveSnapshotID === data.CurrentSnapshotID === data.LiveSnapshotID) {
return true;
}
return false;
}
var data = { ArchiveSnapshotID: "foo", CurrentSnapshotID: "foo", LiveSnapshotID: true };
alert(projectIsLocked (data));
You might want to use something like this, which is quite extensible for even more properties.
function projectIsLocked (data) {
var props = ["ArchiveSnapshotID", "CurrentSnapshotID", "LiveSnapshotID"];
for (var i = 1; i < props.length; i++)
{
if (data[props[i]] !== data[props[i - 1]])
return false;
}
return true;
}

Related

Breaking from a recursive function and returning a value in Javascript

I have written a javascript function like this . But I want when a cretain condition meet the function will not execute means it will break and return a true false like status.My code is like this
var ActionAttributes = function (data)
{
var status = true;
var attrKey = data.AttributeKey();
//Condition to exit
if (attrKey==''||attrKey==null)
{
status = false;
return false;
}
for (var i = 0; i < data.Children().length; i++)
{
var childData = data.Children()[i];
ActionAttributes(childData);
}
return status;
}
You need break condition in the for loop. You are just invoking it, handle the returned status.
var ActionAttributes = function(data) {
var status = true;
var attrKey = data.AttributeKey();
//Condition to exit
if (attrKey == '' || attrKey == null) {
status = false;
return false;
}
for (var i = 0; i < data.Children().length; i++) {
var childData = data.Children()[i];
//You need to break loop here
//Add appropriate condition here
if (ActionAttributes(childData) == false) {
return false;
}
}
return status;
}
well, that recursion is not very useful to begin with.
you call a recursion of ActionAttributes inside the loop, but never handle the returned status. So the first caller will always receive true unless the exit condition meets on the first object.
you shoul store the return from ActionAttributes into status, and then break out of the loop as soon as it's false.

how to return value inside of forEach loop in JavaScript

I got stuck with my code.
I wrote this sample code only for the purpose to reproduce my problem, so this code is not practical at all but I hope you get my point.
In the code below, for the last value to be output, I expect it to be 3, but it's undefined.
How am I supposed to write if I want the last value to be 3 in this case??
This is just a sample code, but in the actual code, I fetch content from amazon api and when it returns api error, I want to run the same function again after 1000 milli seconds.
var list = [1,2,3];
var someClass = new SomeClass();
list.forEach(function(value) {
var result = someClass.getSomething(value);
console.log("outside: " + result);
});
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
this.getSomething(something);
//I need to return here, so the succeeding code is not read.
return;
}
console.log("inside: " + String(something));
return something;
}
}
Log
inside: 1
outside: 1
inside: 2
outside: 2
inside: 3
outside: undefined // I expect this value to be 3!!!
You have a test:
if (something === 3 && flag === false) {
//...
return;
If you want to return 3 then don't have a return statement with nothing after it. return means return undefined. Put return 3 or return something.
You probably want to return from your recursive call though:
return this.getSomething(something);
Here's the problem:
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
this.getSomething(something); // not returning this
return; // returning undefined
}
console.log("inside: " + String(something));
return something;
}
}
Here's the fix:
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
return this.getSomething(something);
}
console.log("inside: " + String(something));
return something;
}
}
change the code to
if (something === 3 && flag === false)
{
flag = true;
return this.getSomething(something);
}
"return;" returns undefined
It returns undefined in your code because you return; in the if clause.
return this.getSomething(something) within the if clause
var list = [1, 2, 3];
var someClass = new SomeClass();
list.forEach(function(value) {
var result = someClass.getSomething(value);
console.log("outside: " + result);
});
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
return this.getSomething(something);
}
console.log("inside: " + String(something));
return something;
}
}
forEach loop doesn't return a value.
You can create a global variable and assign values to it.

Get only one match with regexp

In the function below I iterate through an array (incidents) which contains of strings. The strings is describing an incident (crime or accidents) that is scrapted from another web app, and what I'm doing is dividing and counting the different crimes / accidents and placing them in an object (INCIDENT_MATCHES).
However, some of the text strings may contain of several of the keywords that I search for (e.g. both "gunfire" and "battery"), but that I don't want. Instead I just want the first found word to be counted, and if more keywords are found they should be ignored.
How could this be done?
var INCIDENT_MATCHES = {
battery: /\w*(bråk)\w*|överfall|slagsmål|slogs|misshandel|misshandlad|\w*(tjuv)\w*/ig,
burglaries: /snattade|snattare|snatta|inbrott|bestulen|stöld|\w*(tjuv)\w*/ig,
robberies: /\w*(rån)\w*|personrån|\w*(ryckning)\w*|väskryckt*/ig,
gunfire: /skottlossning|skjuten|sköt/ig,
drugs: /narkotikabrott/ig,
vandalism: /skadegörelse|klotter|\w*(klottra)\w*/ig,
trafficAccidents: /(trafik|bil)olycka|(trafik|bil)olyckor|\w*(personbil)\w*|singelolycka|kollision|\w*(kollidera)\w*|påkörd|trafik|smitningsolycka/ig,
};
var j = 0,
incidentCounts = {},
incidentTypes = Object.keys(INCIDENT_MATCHES);
incidents.forEach(function(incident) {
matchFound = false;
incidentTypes.forEach(function(type) {
if(typeof incidentCounts[type] === 'undefined') {
incidentCounts[type] = 0;
}
var matchFound = incident.match(INCIDENT_MATCHES[type]);
if(matchFound){
matchFound = true;
incidentCounts[type] += 1;
}
});
j++;
});
You can return false from the "each" handler to stop iteration.
if(matchFound){
matchFound = true;
incidentCounts[type] += 1;
return false;
}
edit — and you'll want (I think) another test outside that, at the end of the outer loop:
j++; // I don't understand what that does ...
if (matchFound) return false;
I found this solution below to work. What I did was the following:
I replaced the second forEach statement with "every"
Put "return false" inside "if(matchFound)"
Added "else { return true; }" so that the loop continues if no match is found.
The code:
incidents[2].forEach(function(incident) {
matchFound = false;
incidentTypes.every(function(type) {
if(typeof crimesPerType[type] === 'undefined') {
crimesPerType[type] = 0;
}
var matchFound = incident.match(INCIDENT_MATCHES[type]);
if(matchFound){
crimesPerType[type] += 1;
if (type == 'trafficAccidents') {
incidents[3][j].push('traffic');
}
else {
incidents[3][j].push('crime');
}
return false;
}
else {
return true;
}
});

Add space between numbers/digits and letters/characters

I have a code like this
(function($, window, document, undefined) {
$.fn.quicksearch = function (target, opt) {
var timeout, cache, rowcache, jq_results, val = '', e = this, options = $.extend({
delay: 100,
selector: null,
stripeRows: null,
loader: null,
noResults: '',
bind: 'keyup',
onBefore: function () {
return;
},
onAfter: function () {
return;
},
show: function () {
this.style.display = "";
},
hide: function () {
this.style.display = "none";
},
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
testQuery: function (query, txt, _row) {
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
}, opt);
this.go = function () {
var i = 0,
noresults = true,
query = options.prepareQuery(val),
val_empty = (val.replace(' ', '').length === 0);
for (var i = 0, len = rowcache.length; i < len; i++) {
if (val_empty || options.testQuery(query, cache[i], rowcache[i])) {
options.show.apply(rowcache[i]);
noresults = false;
} else {
options.hide.apply(rowcache[i]);
}
}
if (noresults) {
this.results(false);
} else {
this.results(true);
this.stripe();
}
this.loader(false);
options.onAfter();
return this;
};
this.stripe = function () {
if (typeof options.stripeRows === "object" && options.stripeRows !== null)
{
var joined = options.stripeRows.join(' ');
var stripeRows_length = options.stripeRows.length;
jq_results.not(':hidden').each(function (i) {
$(this).removeClass(joined).addClass(options.stripeRows[i % stripeRows_length]);
});
}
return this;
};
this.strip_html = function (input) {
var output = input.replace(new RegExp('<[^<]+\>', 'g'), "");
output = $.trim(output.toLowerCase());
return output;
};
this.results = function (bool) {
if (typeof options.noResults === "string" && options.noResults !== "") {
if (bool) {
$(options.noResults).hide();
} else {
$(options.noResults).show();
}
}
return this;
};
this.loader = function (bool) {
if (typeof options.loader === "string" && options.loader !== "") {
(bool) ? $(options.loader).show() : $(options.loader).hide();
}
return this;
};
this.cache = function () {
jq_results = $(target);
if (typeof options.noResults === "string" && options.noResults !== "") {
jq_results = jq_results.not(options.noResults);
}
var t = (typeof options.selector === "string") ? jq_results.find(options.selector) : $(target).not(options.noResults);
cache = t.map(function () {
return e.strip_html(this.innerHTML);
});
rowcache = jq_results.map(function () {
return this;
});
return this.go();
};
this.trigger = function () {
this.loader(true);
options.onBefore();
window.clearTimeout(timeout);
timeout = window.setTimeout(function () {
e.go();
}, options.delay);
return this;
};
this.cache();
this.results(true);
this.stripe();
this.loader(false);
return this.each(function () {
$(this).bind(options.bind, function () {
val = $(this).val();
e.trigger();
});
});
};
}(jQuery, this, document));
I try to figure out where and how I can make a split/add space between numbers and letters. Cause some people type for example "ip1500" and the script cant match the input with an element that is like "ip 1500". My problem ist that Im a js beginner.
I was trying and trying but i cant get it work. I also tried this
I found this spot and I think it can be done here where the everything get splitted by an " " (space):
prepareQuery: function (val) {
return val.toLowerCase().split(' ');
},
Would be very nice if somebody can help me.
If you want "123abc345def" to "123 abc 345 def". The replace function may help. The code is like this.
var str = "123abc345def";
str = str.replace(/(\d+)/g, function (_, num){
console.log(num);
return ' ' + num + ' ';
});
str = str.trim();
The code you linked didn't work mainly because it's using a different programming language to javascript. In theory, it should work, but javascript does not support regular expression lookbehinds (at this present time)..
Instead, I have re-wrote that fragment of code:
prepareQuery: function (val) {
function isNotLetter(a){
return (/[0-9-_ ]/.test(a));
}
var val=val.toLowerCase().split("");
var tempArray=val.join("").split("");
var currentIndex=1;
for (var i=0;i<val.length-1;i++){
if (isNotLetter(val[i]) !== isNotLetter(val[i+1])){
tempArray.splice(i+currentIndex, 0, " ");
currentIndex++;
}
}
return tempArray.join("");
}
Since you're new to javascript, I'm going to explain what it does.
It declares a function in prepareQuery to check whether or not a string contains a letter [this can be moved somewhere else]
It then splits val into an array and copies the content of val into tempArray
An index is declared (explained later)
A loop is made, which goes through every single character in val
The if statement detects whether or not the current character (val[i] as set by the loop) is the same as the character next to it (val[i+1]).
IF either one are different to the other (ie the current character is a letter while the next isn't) then a space is added to the tempArray at that "index"
The index is incremented and used as an offset in #6
The loop finishes, joins the "array" into a string and outputs the result.
DEMO:
http://jsbin.com/ebitus/1/edit
(JSFiddle was down....)
EDIT:
Sorry, but I completely misinterpreted your question... You failed to mention that you were using "quicksearch" and jQuery. In that case I'm assuming that you have a list of elements that have names and you want to search through them with the plugin...
A much easier way to match the user's query (if there is no space) is to strip the space from the search table along with the query itself - though original reverse method will work (just not as efficiently) [aka: expanding the user's query]
In this case, stripping the space from both the search table and user input would be a better method
prepareQuery: function (val) {
return val.toLowerCase().replace(/ /ig,'').split(" ");
},
testQuery: function (query, txt, _row) {
txt=txt.toLowerCase().replace(/ /ig,'');
for (var i = 0; i < query.length; i += 1) {
if (txt.indexOf(query[i]) === -1) {
return false;
}
}
return true;
}
DEMO:
http://jsfiddle.net/q9k9Y/3/
Edit 2:
It seems like your real intent is to create a fully functioning search feature on your website, not to just add spaces between letters and numbers. With this, I suggest using Quicksilver. I would love to work out an algorithm to extend quickSearcher but at the current time I cannot (timezones). Instead, I suggest using Quicksilver
http://jsbin.com/oruhet/12/

Javascript: What is wrong with this conditional?

I'm working on a Chrome extension an I've hit a wall.
function isInQueue(id) {
chrome.extension.sendRequest({getQueueItems: 1}, function(response) {
var items = response.items;
if (items) {
for (var i = 0; i < items.length; i++) {
if ((items[i].id == id) == true) return true;
}
return false;
} else { return false; }
});
}
The request returns 'items' which is an array of objects. I am trying to see if another item outside of the queue already exists inside the queue. For example, there is an item on the outside with an id equal to '198677'. I know I already have an exact copy of that same item in my queue with the exact same id, '198677', however, when I test the two for equality (items[i].id == id) == true, it returns false. I have checked the typeof both and they are both strings. I have tried using === and that hasn't worked. I tried adding zero to each of them to turn them into integers and that made the function return true when it was actually true, however, when I tested for true if (isInQueue(id) == true) the conditional returned false.
This is all very confusing and frustrating for me. They're both strings, why doesn't it work?
Help is very much appreciated.
The problem is chrome.extension.sendRequest is asynchronous - it returns immediately, but the callback function you provide to it will only be called once the request has completed.
The usual way to handle something like this is to pass a callback to your isInQueue method; the callback is called when the asynch operation is completed with the result.
function isInQueue(id, callback) {
chrome.extension.sendRequest({getQueueItems: 1}, function(response) {
var result = false;
var items = response.items;
if (items) {
for (var i = 0; i < items.length; i++) {
if ((items[i].id == id) == true) {
result = true;
break;
}
}
}
callback(result);
});
}
I figured it out:
function isInQueue(id) {
var result = false;
var queue = localStorage["queue_rss"];
if (queue != undefined) {
var items = JSON.parse(queue).items;
if (items) {
for (var i = 0; i < items.length; i++) {
if ((items[i].id == id) == true) {
result = true;
break;
}
}
}
}
return result;
}
I should have done it that way in the first place.
Thanks guys. :D

Categories

Resources