Javascript string in array or a part - javascript

I have a Javascript array with multiple values:
var filterClasses = ['col-sm-12', 'hidden-xs', 'hidden-sm', 'hidden-lg', 'hidden-md', 'active', 'btn-'];
I have a function that gets all css classes in the DOM. But i want to check if this class should be added to a new array or not. So i can use indexOf for this:
return filterClasses.indexOf('col-sm-12');
This returns a true, so this class should be ignored.
But now i have a class that is btn-primary. As you see in my array i have the btn- added in it. I want to exclude all classes that contains the word btn-. How can i achieve this?
Current function:
function setupShouldAddClass( cssClass, filterClasses )
{
// If the cssClass exists in the filterClasses then false
if ( filterClasses.indexOf(cssClass) > 0 )
{
return true;
}
filterClasses.forEach(function ( item )
{
if ( stringContains(item, cssClass) )
{
return true;
}
});
return false;
}
function stringContains( needle, haystack )
{
return (haystack.indexOf(needle) !== -1);
}

Maybe you can solve your issue using regular expressions instead of using imperative code:
var classBlackListRegExp = /(col-sm-12|hidden-xs|hidden-sm|hidden-lg|hidden-md|active|^btn-.+)/i;
var result = classBlackListRegExp.test("btn-whatever");
console.log(result);
Check the ^btn-.+ part. This matches anything starting with "btn-".
I believe that your scenario is the ideal use case of regular expressions!
OP concerns if class black list is very large
OP said:
what im wondering is, that if i add more then 100 classes, how does
this handle the line breaks?
You can join the whole array of black-listed strings and create a RegExp object with it as follows:
// I use a templated string and String.prototype.join
// to create a regular expression from a given array:
var classBlackListRegExp = new RegExp(`(${[
'col-sm-12',
'hidden-xs',
'hidden-sm',
'hidden-lg',
'hidden-md',
'active',
'^btn-.+'
].join("|")})`, "i");
var result = classBlackListRegExp.test("btn-whatever");
console.log(result);

You need to use Array#some and check against each value and return true if found.
function setupShouldAddClass(cssClass, filterClasses) {
return filterClasses.indexOf(cssClass) !== -1 || filterClasses.some(function (item) {
return stringContains(item, cssClass);
});
}

I would loop over them like this.
function setupShouldAddClass( cssClass, filterClasses )
{
// If the cssClass exists in the filterClasses then false
var ret = true;
filterClasses.forEach(function(el) {
if (cssClass.indexOf(el) >= 0) {
ret = false;
}
});
return ret;
}

How about bringing the cssClass to what you needed to be compared to:
var transformedToMyNeedsCSS = "btn-primary".replace(/^(btn[-])(?:.*)/,"$1");
// --> Output "bnt-"
And then you compare as you are doing it now:
if ( filterClasses.indexOf(transformedToMyNeedsCSS) > 0 )
{
return true;
}

There's a whole host going wrong here. Let's deal with it step by step:
First
if ( filterClasses.indexOf(cssClass) > 0 )
That is incorrect because indexOf returns -1 if the search term is not found. It returns 0 if it is the first item in the array. So you want >= 0.
Second, the forEach loop:
filterClasses.forEach(function ( item )
{
if ( stringContains(item, cssClass) )
{
return true;
}
});
This achieves nothing. As in, genuinely nothing. Because you are inside a new function (the callback to forEach) return only returns from the inner function. And the return value is then discarded. What this code actually does is loop all the way through the array and do nothing. What you actually want is a clever function called Array.prototype.some. This loops through the array and tests each element. If you return true on any of the elements, some returns true. Otherwise it returns false.
So your code could look like this:
return filterClasses.some(function(element) {
return stringContains(item, cssClass);
}
Now we want to ignore all classes where they begin with btn-. I presume this means that you want to return false if the class begins with btn-.
if (cssClass.indexOf('btn-') === 0) {
return false;
}
So your function now looks like:
function setupShouldAddClass( cssClass, filterClasses )
{
if (cssClass.indexOf('btn-') === 0) {
return false;
}
// If the cssClass exists in the filterClasses then false
if ( filterClasses.indexOf(cssClass) >= 0 )
{
return true;
}
return filterClasses.some(function(element) {
return stringContains(item, cssClass);
});
}

Related

How to check if a value exists in a select box using vanilla JS?

I want to create a function that accepts an argument of check that will loop through select box options and values and check to see if the value exists or not. I have it working (kinda) but it only checks the first option. If you run checkOption('red), you get an alert that Option Exists. However, if you run checkOption('green'), nothing happens.
I'm doing something simple here, but I can't figure it out. Thanks for any and all help.
Working CodePen:
CodePen
JavaScript:
let selectBox = document.querySelector("select");
let options = selectBox.querySelectorAll("option");
function checkOption(check) {
options.forEach((o) => {
if (o.value === check) {
return true; // returns undefined either way.
}
});
}
}
Edit: I am now able to get console.log() to print to the console, but I'm trying to return either True or False. How would I amend the above function to return True or False? So far, this only returns undefined.
You need to loop through the options in your function. You can also shorten by using forEach on the collection:
function checkOption(check) {
options.forEach( o => {
if( o.value === check) {
alert(`${check} is available`);
}
}
}
You could condense even more by using the array filter() function as well. You just need to make treat the options NodeList as an array but sticking it through the Array.from() method first:
function checkOption(check) {
if( Array.from(options).filter( o => o.value === check ).length )
alert(`${check} is available`);
}
or even shorter, let the function returns true or false to indicate the presence of the given option value.
function checkOption(check) {
return Array.from(options).filter( o => o.value === check ).length > 0;
}
You should use options.length in your loop. Besides that, it is good practice to define variables before using them. Your return statement should also be called immediately after a match is found to avoid unnecessary iterations, so you better include it in your if statement.
let selectBox = document.querySelector("select");
let options = selectBox.querySelectorAll("option");
function checkOption(check) {
for (var i = 0; i < options.length; ++i) {
if (selectBox.options[i].value === check) {
alert(`${check} is available`);
return;
}
}
}

How to find an array of strings in a string?

I'd like to search a string for multiple strings, and return true if it finds any of them in there, false otherwise, something like this:
var s = "thing1 thing2"
s.contains(["thing1","thing44444"]) // true
s.contains("1") // true
s.contains("x") // false
Here's what I have so far, but it's getting messier and doesn't really work:
String.prototype.contains = function(xv) {
var t = this
if(xv.isString()){ // isString/isArray are functions I made elsewhere in my code, they work.
if(t.indexOf(xv) > -1)
return true;
} else if(xv.isArray()) {
if(xv.contains(t)){
return true
}
for(v in xv){
if(t.indexOf(xv[v]) > -1){
return true
}
}
} else {
return false
}
}
As of now, it will return undefined if it makes it through the for loop without finding anything. I had return false after the for loop, but it would run before the for finished.
I feel like there's gotta be an easier way to do this.
I've already tried How do you search multiple strings with the .search() Method? but I couldn't send an array to .search().
Frameworks I'm using: angular 1.5.8, jquery 1.11.1
You can use Array.some and String.indexOf or String.includes
var s1 = "thing1 thing2";
var s2 = "Hello Kitty";
var r1 = ["thing1","thing44444"].some( x => s1.includes(x));
var r2 = ["Travis","Heeeeeeter"].some( x => s2.includes(x));
console.log(r1, r2); // true, false

Javascript Basic algorithm

Return true if the string in the first element of the array contains all of the letters of the string in the second element of the array. No case-sensitivity and order doesn't matter only the letters matter. For ex - ["Hello","hello"] returns true and so does ["Alien","lien"] and also ["Mary", "Aarmy"]. I think you get it. If not return false.
I could solve it with Array.indexOf() === -1 (in the first for loop) but can it work with this code, it's the opposite. I just can't make it return false. Ultimately, I wanna know, can you make it return false without changing the method.
function mutation(arr) {
var split = arr[1].toLowerCase().split("");
var splitSecond = arr[0].toLowerCase().split("");
for(k=0;k<=arr[0].length;k++){
for(i=0;i<=arr[1].length;i++){
if(split[i]===splitSecond[k]) {
return true
}
}
} return false
}
mutation(["hello", "hney"], "");
If using any other method, explain :)
The problem with your code is that you return true; as soon as one letter matches.
What you need to do is check if all letters match, which is easier achieved by checking if any letter doesn't match.
mainloop:
for(k=0;k<=arr[0].length;k++){
for(i=0;i<=arr[1].length;i++){
if(split[i]===splitSecond[k]) {
continue mainloop; // found the letter, move on to next search
}
}
return false; // failed to find letter, fail here
}
return true; // haven't failed yet and end of input reached. Success!
Another alternative would be:
for(k=0;k<arr[0].length;k++) {
if( arr[1].indexOf(split[k]) < 0) {
// letter not found
return false;
}
}
// not failed yet? Excellent!
return true;
function mutation(arr) {
var test = arr[0].toLowerCase(),
chars = arr[1].toLowerCase(),
len=chars.length;
for(var i=0;i<len;i++)
if(test.indexOf(chars[i])==-1) //this char not exist in test string
return false;
return true;//all chars already checked
}
mutation(["hello", "he"]);
https://jsfiddle.net/hb2rsm2x/115/
Here is an interesting way using regular expressions. escapeRegExp was taken from here.
function mutation(arr){
var matcher = new RegExp('[^'+escapeRegExp(arr[1])+']', "i");
return arr[0].match(matcher) === null;
}
function escapeRegExp(s) {
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}

JavaScript Throws Undefined Error

What it is supposed to do -
Example
url1(pages,"ALT") returns "www.xyz.ac.uk"
url1(pages,"xyz") returns ""
The error - TypeError: Cannot call method 'toUpperCase' of undefined
This is just for some coursework, Im stuck with these errors. Any help would be much appreciated
function index(string,pattern,caseSensitive) {
if(caseSensitive == false) {
var v = string.toUpperCase();
} else {
var v = string;
}
return indexNumber = v.indexOf(pattern);
}
var pages = [ "|www.lboro.ac.uk|Loughborough University offers degree programmes and world class research.", "!www.xyz.ac.uk!An alternative University" , "%www%Yet another University"];
alert(url1(pages, "ALT"));
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
if(pages[i].indexOf(seperator)>0){
siteContent = pages[i].split(pages[i].indexOf(seperator));
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
}
}
if(pages[i].indexOf(seperator)>0){
siteContent = pages[i].split(pages[i].indexOf(seperator));
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
If pages[i].indexOf(seperator)<=0, siteContent is still whatever it was from the last iteration. If that happens on the first iteration, siteContent is still [], and siteContent[2] is undefined.
Another problem: the expression pages[i].indexOf(seperator) returns a number, and pages[i].split expects a delimiting string as an argument. Since the number doesn't appear in your input, you'll always get a single-element array, and siteContent[2] will always be undefined. Get rid of .indexOf(seperator), change it to siteContent = pages[i].split(seperator).
One more: get rid of the else { return ""; }. Add a return ""; after the for loop.
Finally, in the first if statement condition, change .indexOf(seperator) > 0 to .indexOf(seperator, 1) !== -1. Since you're getting seperator from the first character of the string, it will be found at 0. You want the second occurrence, so start the search at 1. In addition, .indexOf returns -1 if it doesn't find the substring. You'll need to account for this in both if conditions.
Side note, as this is not causing your problem: never use == false. JS will coerce stuff like 0 and "" to == false. If that's what you want, just use the ! operator, because the expression has nothing to do with the value false.
My final answer is http://jsfiddle.net/QF237/
Right here:
alert(url1(pages, ALT)); // ALT ISN'T DEFINED
I believe you forgot to quote it:
alert(url1(pages, "ALT"));
You should split the string passing the separator character itself. Your function then will look like:
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
console.log(seperator);
if(pages[i].indexOf(seperator)>=0){
siteContent = pages[i].split(seperator); //fixed here
}
console.log(siteContent);
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}else{
return "";
}
}
}
Tell us if it worked, please.
EDIT: It seeems your index() also has a little problem. Please try the function below.
function index(string,pattern,caseSensitive) {
var v;
if(caseSensitive == false) {
v = string.toUpperCase();
pattern = pattern.toUpperCase(); //to clarify: pattern should be uppercased also if caseSensitiveness is false
} else {
v = string;
}
return v.indexOf(pattern);
}
EDIT 2:
And url1() is finally like this:
function url1(pages,pattern) {
var siteContent = [];
for(i=0;i<pages.length;i++) {
var seperator = pages[i].charAt(0);
if(pages[i].indexOf(seperator)>=0){
siteContent = pages[i].split(seperator);
}
if( index(siteContent[2],pattern,false)>=0){
return siteContent[1];
}
}
return "";
}
In this case, the first occurrence of pattern in all pages will be returned.

If Else Conditionals within Function in JavaScript

I'm having issues with conditionals. I want to return the index where pattern starts in string (or -1 if not found). The search is to be case sensitive if the 3rd parameter is true otherwise it is case insensitive.
Examples
index("abAB12","AB",true) returns 2 but index("abAB12","AB",false) returns 0
index("abAB12","BA",true) returns -1 and index("abAB12","BA",false) returns 1
Any idea how I can accomplish this?
This is my code so far
var s = "abAB12"
var p = "AB"
var cs = true
function index(string, pattern, caseSensitive) {
if (pattern) {
var found = false;
if (caseSensitive = false) {
if (string.indexOf(pattern.) >= 0) {
found = true;
}
return (found);
else {
return ("");
}
} else if (caseSensitive = true) {
if (string.toLowerCase().indexOf(pattern.toLowerCase()) >= 0) {
found = true;
}
return (found);
} else {
return ("");
}
}
}
alert(index(s, p, cs));
Fiddle at http://jsfiddle.net/AfDFb/1/
You have some mistype in your code. On the 15th line you have
}
return (found);
else {
This is not not valid. Change it to
return (found);
}
else {
There is another one.
if (caseSensitive = false) {
= used for assignment. You need to use == in if statements when comparing.
Also on the 13th line, there's an extra . after pattern. Remove it.
if (string.indexOf(pattern.) >= 0) {
Your fiddle example
You can use string.search() with a regular expression to accomplish this in one liner:
function index(input, key, caseMatters) {
return input.search(new RegExp(key, caseMatters ? '' : 'i'));
}
Now you can:
index("abAB12","AB",true); // returns 2
index("abAB12","AB",false); // returns 0
index("abAB12","BA",true); // returns -1
index("abAB12","BA",false); // returns 1
You need to use double equals sign == in your if, else statements.
if(caseSensitive == false)
And
if(caseSensitive == true)
You are assigning value inside if condition instead of comparing it.
Try
if (caseSensitive == false) {
and
if(caseSensitive == true)
You'd better use search :
'abAB12'.search(/AB/); // 2
'abAB12'.search(/AB/i); // 0
'abAB12'.search(/BA/); // -1
'abAB12'.search(/BA/i); // 1
The i flag means "case insensitive" ( insensible à la casse :D ).

Categories