Converting HTML element into array and dealing with null - javascript

I am using javascript to read an HTML element that contains an array, but I suppose it is just a string version of an array. So I have converted this to a javscript array of integers, however I am having a problem when the the HTML array is empty.
HTML: (empty array)
<div id="activelist"> [] </div>
HTML: (array contains values)
<div id="activelist"> [4, 5] </div>
I am using let activeMachines = document.getElementById("activelist").innerHTML; in my script to grab the values from the page.
if I console.log(activeMachines); It will return [] when the array is empty.
if I console.log(activeMachines); It will return [3, 5] when the array contains values.
Now to process this into a javascript array of integers I use:
//trim off the quotes and brackets
activeMachines = activeMachines.slice(2, -2);
//split into different objects
activeMachines = activeMachines.split(', ');
console.log(activeMachines.length);
Now the part I can't figure out:
When the array is empty console.log(activeMachines.length); will return 1
When the array has a value in it console.log(activeMachines); will return 1
when the array has two values in it console.log(activeMachines); will return 2
Is there a way to get the array.length to be 0 when it is empty? Maybe .length is the wrong operator to use?
Thanks for any help!

You could use JSON.parse and return an array.
function getValue(id) {
return JSON.parse(document.getElementById(id).innerHTML);
}
var data = ['activelist0', 'activelist1'].map(getValue);
console.log(data[0].length);
console.log(data[0]);
console.log(data[1].length);
console.log(data[1]);
<div id="activelist0"> [] </div>
<div id="activelist1"> [4, 5] </div>

Using JSON.parse, we can parse the innerHTML and get the actual type that you want to evaluate. Ensure you wrap it around in a try catch or else you will run into an error as there is no validator for the content inside the div.
Here's a quick example:
var activeList = document.querySelectorAll('.active-list');
var debug = document.getElementById('debug');
activeList.forEach(function(elem, index) {
try {
var arr = JSON.parse(elem.textContent);
debug.innerHTML += (index + 1) + ' result length is: ' + arr.length + '<br/>';
} catch (error) {
debug.innerHTML += (index + 1) + ' error';
}
});
<div class="active-list">[4, 5]</div>
<div class="active-list">[1]</div>
<div class="active-list">[]</div>
<div class="active-list">this should invoke an error!</div>
<br/>
<div id="debug"></div>

One further option:
// declaring a named function, using Arrow syntax:
const parseArray = (el) => {
// retrieving the text content of the current element ('el'),
// removing any leading and trailing spaces using
// String.prototype.trim() and then replacing the '['
// and ']' characters using String.prototype.replace,
// along with a regular expression; replacing those
// characters with an empty string:
let values = el.textContent.trim().replace(/\[|]/g, ''),
// if the length of the modified String is zero then we
// return an empty Array; otherwise w split the the
// String using String.prototype.split(), to split
// the String into an Array:
result = values.length === 0 ? [] : values.split(',');
// logging the result:
console.log(result);
// returning the result to the calling context:
return result;
}
// using document.querySelectorAll() to retrieve all <li>
// elements on the page, and then calling NodeList.prototype.forEach()
// in order to call the named function (note the deliberate lack of
// parentheses on the function name):
document.querySelectorAll('li').forEach(parseArray);
const parseArray = (el) => {
let values = el.textContent.trim().replace(/\[|]/g, ''),
result = values.length === 0 ? [] : values.split(',');
console.log(result);
return result;
}
document.querySelectorAll('li').forEach(parseArray);
<ul>
<li>[]</li>
<li>["1","2","3"]</li>
<li>[a,b,,d,e]</li>
</ul>
JS Fiddle demo.
References:
Arrow functions.
document.querySelectorAll().
NodeList.prototype.forEach().
Regular Expressions.
String.prototype.split().

Mixing data model with representation is a bad practice. A better way is to separate the two. For example:
var myData = [1,2,3];
function renderData(data)
{
return data.join(", ");
}
Thus, you can manipulate myData and always get the right result regardless of how data is rendered.

Related

How to filter a string that represents objects

Unfortunately, my web services response is returning me a String like this:
{"valueStr":"Single"|"valueId":"2019"}
{"valueStr":"Married"|"valueId":"2019"}
{"valueStr":"Divorced"|"valueId":"2020"}
{"valueStr":"Widowed"|"valueId":"2020"}
I need to filter out those with the valueId. For example, all the 2019 or all the 2020.
The response isn't JSON so I can't parse it, and it's not delimited correctly. So I'm stuck trying something unelegant like this:
function parseItemByYear(item){
// replace all | with ,
var modifiedObj = item.replace(/\|/g, ',');
// split into array
var newArr = modifiedObj.split('}');
// remove all
var newestArr = newArr.map(function(item){item.replace(/^\{/g,'')});
// JSON.parse the object
// var lovObj = JSON.parse(modifiedFilingStatusObj);
// capture the current tax year
// replace , with |
// rebuild the object
// return the filtered object
return newestArr;
}
But I'm failing where I'm trying to set newestArr. My RegEx is wrong. Is my approach too complicated? Is there an easier way that I'm not seeing? Thanks for any tips.
I think this is simple and will do the trick.
// Assuming it's single or multiline string
let response = `{"valueStr":"Single"|"valueId":"2019"}
{"valueStr":"Married"|"valueId":"2019"}
{"valueStr":"Divorced"|"valueId":"2020"}
{"valueStr":"Widowed"|"valueId":"2020"}`;
function parseItemByYear(response) {
// Replace '|' with ','
response = response.replace(/\|/g, ',');
// Replace '}{' with any whitespace in between to '},{'
response = response.replace(/}\s?{/g, '},{');
// Make it an array
let arr = JSON.parse(`[${response}]`);
// Return an array of valueId attribute of all array elements
return arr.map(item => item.valueId);
}
console.log(parseItemByYear(response));
You should have split it by new line \n and the just use JSON.parse as it resembles JSON enough to be parsed.
const response = `{"valueStr":"Single"|"valueId":"2019"}{"valueStr":"Married"|"valueId":"2019"}{"valueStr":"Divorced"|"valueId":"2020"}{"valueStr":"Widowed"|"valueId":"2020"}`;
function parseItemByYear(response){
// replace all `|` with `,`
response = response.replace(/\|/g, ',');
// replace all `}` with `}**BREAK**`
response = response.replace(/\}/g, '}**BREAK**');
// split into array
const newArr = response.split('**BREAK**');
// Remove last emenet added by regexp
newArr.pop()
try {
return newArr.map(item => JSON.parse(item)/*.valueId*/);
} catch(e) {
return new Error('Coud not be parsed');
}
}
console.log(parseItemByYear(response));
This is a list of data handling to get only valueID.
This code is only here to work without JSON (in case of need) but you should consider use standardised format.
const str = `{"valueStr":"Single"|"valueId":"2019"}
{"valueStr":"Married"|"valueId":"2019"}
{"valueStr":"Divorced"|"valueId":"2020"}
{"valueStr":"Widowed"|"valueId":"2020"}`
const results = str.replace(/[\{\}\"]/g, "").split("\n").map(el => el.split("|").map(kv => kv.split(':')).filter(arr => arr[0] === 'valueId')).map(el => el[0][1])
console.log(results)
It's always better to use valid stanrd like JSON, use this toJSON function to transform your string into a valid JSON object easier to use.
const str = `{"valueStr":"Single"|"valueId":"2019"}
{"valueStr":"Married"|"valueId":"2019"}
{"valueStr":"Divorced"|"valueId":"2020"}
{"valueStr":"Widowed"|"valueId":"2020"}`
const toJSON = (str) => JSON.parse('[' + (str
.replace(/(?:\r\n|\r|\n)/g, '')
.replace(/\|/g, ",")
.replace(/}{/g, "},{")) + ']')
console.log(toJSON(str))
console.log(toJSON(str).map(el => el.valueId))

Array values to a string in loop

I have an object (key value pair) looks like this
I want to get a string of '[100000025]/[100000013]'
I can't use var str = OBJ[0].PC + OBJ[1].PC (which gives me '100000025100000013')
because I need the bracket structure.
The number of items can vary.
Added >> Can it be done without using arrow function?
const string = array.map(({PC}) => `[${PC}]`).join('/')
You could map every string to the string wrapped in brackets, then join that by slashes.
You can use a map() and a join() to get that structure. - this is hte same solution as Puwka's = but without the template literal.
var data = [
{am: 1, ct: "", pc: "1000000025"},
{am: 2, ct: "", pc: "1000000013"}
];
let newArr = data.map(item => "[" + item.pc +"]");
console.log(newArr.join("/")); // gives [1000000025]/[1000000013]
You can always use classic for in loop
let arr = [{PC:'1000'},{PC:'10000'}]
let arrOut = [];
for(let i = 0; i < arr.length; i++) {
arrOut.push('[' + arr[i].PC + ']');
}
now the arrOut is equal ["[1000]", "[10000]"] what we need is to convert it to a string and add '/' between items.
let str = arrOut.join('/');
console.log(str) // "[1000]/[10000]"
So you need a string in the format of: xxxx/yyyyy from a complex object array.
const basedata = [...];
const result = basedata.map( item => `[${item.PC}]` ).join('/')
so i will explain it now. The map function will return a new array with 1 entry per item. I state that I want PC, but i added some flavor using ticks to inject it inbetween some brackets. At this point it looks like: ["[1000000025]","[100000013]"] and then join will join the arrays on a slash, so it will turn into an array.
"[100000025]/[100000013]"
Now, this will expand based on the items in your basedata. So if you have 3 items in your basedata array, it would return:
"[10000000025]/[100000013]/[10000888]"
First if you want to divide the result then it will be better to change it into number and then just do the division.
Example
Number.parseInt("100000025")/Number.parseInt("100000013")
If you want to display it then better to use string interpolation
surround it with back tick
[${[0].PC}]/[${[1].PC}]
Hope this is what are you looking for

Removing an element from a javascript array causing issues

So I'm a little stuck as to why this isn't working. I'm trying to remove all of the empty strings in an array and it keeps giving me back an array that is just one empty string. Any ideas?
function splitNames(){
var names = document.getElementById("1").value.split("\n");
for(var i = 0; i<=names.length; i++){
if(names[i]==""){
names = names.splice(i, 1);
console.log(names);
}
}
console.log(names);
}
The string would look like this by the way.
Hi
Hello
(remove this one)
Bonjour
blah
(remove this one)
(remove this one)
blah
The array comes out to this ["Hi", "Hello","",...]
Perhaps the simplest way to do this is to use the filter function and search for truthy values. By default, empty strings are false.
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
var strings = ["zebras", "trees", "forests", "", "hi", "wizards", "", "", "lizards"];
strings = strings.filter((e) => e);
console.log(strings);
It's important to note that empty strings by default are false. However, strings that contain only whitespace characters are true. In that scenario, my example would not work and you would have to do this
strings.filter((e) => e.trim());
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
function splitNames(){
// var names = document.getElementById("1").value.split("\n");
var names = "Hi\nHello\n \nGoodBye".split("\n");
var filteredNames = names.filter(function(item){
return item.trim() !== "";
});//filter
return filteredNames;
}//splitNames()
console.log( splitNames() );
Create a new array and push what you need.
function splitNames(){
var names = document.getElementById("1").value.split("\n");
var newArr = [];
for(var i = 0; i<=names.length; i++){
if(names[i]){
newArr.push(names[i]);
}
}
return newArr.join('\n');
//console.log(names);
}
try it:
function splitNames(){
var names = document.getElementById("1").value.split("\n");
var newArr = names.filter(function(name){
return name!=="";
});
return newArr;
}

Javascript map method on array of string elements

I am trying to understand how to implement the map method (rather than using a for loop) to check a string for palindromes and return boolean values for whether the mapped array elements reversed are the same as the original array elements. I cannot seem to understand the syntax of the map method. How do I get the map to function on each element in the original array? What is the value? Here is my working code, which is only logging a value of undefined:
function palindromeChecker(string) {
var myString = string.toLowerCase();
var myArray = myString.split(" ");
var newArray = myArray.map(function (item) {
item.split("").reverse().join("");
return newArray === myArray;
});
}
console.log(palindromeChecker("What pop did dad Drink today"));
Here is a link to the fiddle:
https://jsfiddle.net/minditorrey/3s6uqxrh/1/
There is one related question here:
Javascript array map method callback parameters
but it doesn't answer my confusion about the syntax of the map method when using it to perform a function on an array of strings.
The map method will literally 'map' a function call onto each element in the array, take this as a simple example of increasing the value of each integer in an array by 1:
var items = [1,2,3];
items.map(function(item) {
return item + 1;
});
// returns [2,3,4]
In your case, you are trying to use map to accept or reject a string if it's a palindrome, so a simple implementation might be:
var items = ['mum', 'dad', 'brother'];
items.map(function(item) {
return item.split('').reverse().join('') === item;
});
// returns [true, true, false]
I'm not 100% sure of your reasons for using map, because if you were trying to just filter the array and remove the strings that aren't palindromes, you should probably use the filter method instead, which works in the same way, but would remove any that return false:
var items = ['mum', 'dad', 'brother'];
items.filter(function(item) {
return item.split('').reverse().join('') === item;
});
// returns ['mum', dad']
In your case you are splitting a string first to get your array of characters; you may also want to make that string lower case and remove punctuation, so an implementation might be:
var string = 'I live at home with my Mum, my Dad and my Brother!';
var items = string.toLowerCase().replace(/[^a-z0-9-\s]+/, '').split(' ');
items.filter(function(item) {
return item.split('').reverse().join('') === item;
});
// returns ['i', 'mum', dad']
As mentioned in one of the comments on your question, you need to ensure you return a value from your function if you are using a separate function to perform the check, so this is how your function should look:
function checkPalindromes(string) {
var items = string.toLowerCase().replace(/[^a-z0-9-\s]+/, '').split(' ');
items.filter(function(item) {
return item.split('').reverse().join('') === item;
});
return items;
}
And you would call it using:
checkPalindromes('I live at home with my Mum, my Dad and my Brother!'); // ['i', 'mum', 'dad']
try something like this:
let str = 'hello';
let tab = [...str];
tab.map((x)=> {
console.log("|"+x+"|");
return x;
})
newArray should include reversed version of theall items in myArray. After that, newArray should be reversed and joined with space in order to get the reversed version of the input string.
Here is the code:
function palindromeChecker(string) {
var myString = string.toLowerCase();
var myArray = myString.split(" ");
var newArray = myArray.map(function (item) {
return item.split("").reverse().join("");
});
console.log(newArray);
return newArray.reverse().join(" ") === string;
}
console.log(palindromeChecker("dad did what"));
Javascript map method on array of string elements by using split() function.
let str = 'hello';
str.split('').map((x)=> {
console.log("|"+x+"|");
return x;
})
Map is a higher-order function available in ES5. I think your newArraywill contain an array of boolean values.
In essence, map will iterate over every value in your array and apply the function. The return value will be the new value in the array. You can also use map and save the information you need somewhere else, and ignore the result of course.
var arr = [1,2,3,4];
var newArray = arr.map(function(i) {
return i * 2;
});
//newArray = [2,4,6,8]
The map function in javascript (and pretty much in any language) is a great little function that allows you to call a function on each of the items on a list, and thus changing the list itself.
The (anonymous) function you're passing as an argument accepts an argument itself, which is filled by an item of the list it is working on, each time it is called.
So for a list [1,2,3,4], the function
function(item) { return item + 1 }, would give you a list of [2,3,4,5] for a result. The function you passed to $.map() is run over each element of the list, and thus changing the list.
So for your code: in the function you're passing as an argument to $.map(), you're returning whether the old and new array are equal (which is false btw). So since you're returning a boolean value, the list you'll end up with is a list of bools.
What I think you want to do, is extract the newArray == myArray from the function you're passing to $.map(), and putting it after your $.map() call.
Then inside the function you're passing to $.map(), return the item you're splitting and whatnot, so your newArray will be an array of strings like myArray.
Apart from a few minor mistakes in your code, such as scope issues (you're referencing the "newArray" and "myArray" outside of the function in which they where defined, and therefore, getting "undefined")..
The main issue you had is that you addressed the ENTIRE array inside the map function, while the whole concept is breaking things down to single elements (and then the function collects everything back to an array for you).
I've used the "filter" function in my example, because it works in a similar manner and I felt that it does what you wanted, but you can change the "filter" to a "map" and see what happends.
Cheers :)
HTML:
<body>
<p id="bla">
BLA
</p>
<p id="bla2">
BLA2
</p>
</body>
Javascript:
function palindromeChecker(string) {
var myString = string.toLowerCase();
var myArray = myString.split(" ");
var newArray = myArray.filter(function (item) {
var reversedItem = item.split('').reverse().join('');
return item == reversedItem;
});
document.getElementById("bla").innerHTML = myArray;
document.getElementById("bla2").innerHTML = newArray;
}
palindromeChecker("What pop did dad Drink today");
Thanks for your input, all. This is the code I ended up with. I fixed the scope issues in the original post. My main problem was understanding the syntax of the map method. In particular, I could not understand from other online resources how to determine the value in the callback function. So, with much help from above I have placed the map method inside the palindromeChecker, and done all of the work on the array inside the map function.
var palindromeChecker = function(string) {
var newString = string.toLowerCase().split(' ');
newString.map(function(item) {
console.log(item.split('').reverse().join('') === item);
});
};
palindromeChecker("What pop did dad drink today");
//Returns false, true, true, true, false, false

Remove Whitespace-only Array Elements

Since using array.splice modifies the array in-place, how can I remove all whitespace-only elements from an array without throwing an error? With PHP we have preg_grep but I am lost as to how and do this correctly in JS.
The following will not work because of above reason:
for (var i=0, l=src.length; i<l; i++) {
if (src[i].match(/^[\s\t]{2,}$/) !== null) src.splice(i, 1);
}
Error:
Uncaught TypeError: Cannot call method 'match' of undefined
A better way to "remove whitespace-only elements from an array".
var array = ['1', ' ', 'c'];
array = array.filter(function(str) {
return /\S/.test(str);
});
Explanation:
Array.prototype.filter returns a new array, containing only the elements for which the function returns true (or a truthy value).
/\S/ is a regex that matches a non-whitespace character. /\S/.test(str) returns whether str has a non-whitespace character.
Another filter based variation - reusable (function)
function removeWhiteSpaceFromArray(array){
return array.filter((item) => item != ' ');
}
const words = ['spray', 'limit', 'elite', 'exuberant', ' ', ''];
const result = words.filter(word => word.trim().length > 0);
console.log(result);
a="remove white spaces"
a.split(' ').join('').split('');
It returns an array of all characters in {a="remove white spaces"} with no 'space' character.
You can test the output separately for each method: split() and join().
You removed an item from the array which reduced the array's length. Your loop continued, skipped some indexes (those which were down-shifted into the removed index), and eventually attempted to access an index outside of the new range.
Try this instead:
var src = ["1"," ","2","3"];
var i = src.length;
while(i--) !/\S/.test(src[i]) && src.splice(i, 1);
console.log(src);
And for a new generation (namely ES2015):
['1', ' ', 'c'].filter(item => item.trim() !== '')
More on trim()
Just simply do this example
// this is you array
let array = ["foo","bar","",""]
// remove blanks in array
let array_new_value = array.join(" ").trim().split(' ');
// Print to know if really works
console.log(array_new_value);
I hope this helps you!!
Here's another approach.
var data = JSON.parse(arrayval.split(/\s/).join(''));
function clearSpace(arr){
for (var key in arr) {
if (arr[key] == "") {
arr.splice(key, 1)
clearSpace(arr)
}
}
}
var arr = ["","a","b","",""]
clearSpace(arr)
//I hope this helps you!!
//Vu Tien Luong - 3GTEL

Categories

Resources