Using ForEach and getting repeated elements in JavaScript - javascript

What I am trying to do is with an input add words into an array, then as you add the words I want them to be displayed in a list. So I did a function to render the list, and used a for each, then used that function inside the function that push the words into the array. The thing is that when you add the words the for each executes and duplicates all the words.
if you add tree as a word you get the output: tree
if you add rabbit you get the output : tree, tree, rabbit
lets say you want to add falcon and you get: tree, tree, rabbit, tree, tree, rabbit, falcon
Here is the code
const renderPass = function (array, location) {
array.forEach((element) => {
let html = `<li class="k">${element}</li>`;
location.insertAdjacentHTML("afterbegin", html);
});
};
const savingKeyWords = function (e) {
e.preventDefault();
keyWords.push(keyWord.value);
renderPass(keyWords, listOfKeys);
console.log(keyWords);
clear(keyWord);
};
could you help me with this??

That is because you seem to be using the same array defined in the global context over and over on every invocation.
Just create a new array when ever saving keywords is invoked.
const savingKeyWords = function (e) {
let keyWords = [];
e.preventDefault();
keyWords.push(keyWord.value);
renderPass(keyWords, listOfKeys);
console.log(keyWords);
clear(keyWord);
};

I think 'keyWords' has to be replaced with 'keyWord.value' in here:
renderPass(keyWords, listOfKeys);
And
const renderPass = function (keyWord, location) {
let html = `<li class="k">${keyWord}</li>`;
location.insertAdjacentHTML("afterbegin", html);
};
I hope this will be helpful for you. Thanks

Related

Function call using previous value?

// The global variable
var bookList = ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"];
// Change code below this line
function add (bookName, test) {
console.log('t', bookName)
let newB = bookName;
newB.push(test)
return newB;
// Change code above this line
}
// Change code below this line
function remove (bookName) {
var book_index = bookList.indexOf(bookName);
if (book_index >= 0) {
bookName.splice(book_index, 1);
return bookName;
// Change code above this line
}
}
var newBookList = add(bookList, 'A Brief History of Time');
var newerBookList = remove(bookList, 'On The Electrodynamics of Moving Bodies');
var newestBookList = remove(add(bookList, 'A Brief History of Time'), 'On The Electrodynamics of Moving Bodies');
console.log(newBookList, newerBookList, newestBookList)
console.log(bookList);
t [ "The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae" ] t [ "The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae", "A Brief History of Time"
How come there is the two strings; "A Brief History of Time" and "A Brief
History of Time" is it saving the value and using it again? How would it
remember that there was a brief history in time in the last function call?
The function call in the third global variable is add(bookList, 'A Brief
History of Time') so what is happening?
If you don't understand what I am saying, basically, I am trying to fix the
add() function and it's working but it's run twice because it's assigned to
two variables and the problem is that in the newestBookList, the add()
function added the string, but it added the string to the array that I made
before in the add() function.
By the way you have named your variable in the line: let newB = bookName;, this line of code is not doing what you think it's doing. It is not creating a new instance of bookName, it is just assigning to newB the existing array reference passed in on the bookName parameter, which is bookList.
Since you continue to pass in bookList and do not get a new array reference with something like [...bookName] or bookName.slice(), it keeps using that same array with each subsequent call. So it will continue to push values onto the same array. That's why you're getting the output you're getting.
One example of how you can return a new array reference each time is like so:
function add (bookName, test) {
console.log('t', bookName)
let newB = bookName.slice(); // generates a new array with the same elements
newB.push(test)
return newB;
}
The problem is that when you reassign your array in the add function your just passing on the array reference. This causes the original array to be
If you intent to use your bookList as an initial state and add and remove to change and return the new state. Another problem I see in your code is that on your remove you are also changing the original array with the splice function. If you intent to follow this approach I recommend the following changes to make sure you're not overriding the original state.
// The global variable
const initialBookList = ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"];
function add(prev, bookName) {
return [...prev, bookName];
}
function remove(prev, bookName) {
const idx = prev.indexOf(bookName);
if (idx === -1) return [...prev];
return [
...prev.slice(0, idx),
...prev.slice(idx + 1, prev.length),
];
}
const bookList1 = add(initialBookList, 'A Brief History of Time');
const bookList2 = remove(initialBookList, 'On The Electrodynamics of Moving Bodies');
var bookList3 = remove(add(initialBookList, 'A Brief History of Time'), 'On The Electrodynamics of Moving Bodies');
console.log({
initialBookList,
bookList1,
bookList2,
bookList3,
})

On click, loop through each object key

I'm still learning JS and something is harder to understand than others.
Like so:
I am trying to change the theme of google maps by allowing users to click on a custom button.
I was using if else which works great but i wanted to add more themes and using a loop. Each time a user clicks, it selects:
object key 0,
then click again object key 2
and object key 3
and repeat
I can get the object keys and values how I'm lost after that.
This is the theme object
let theme = {
default: null,
night: [multiple objects with nested arrays],
dark: [multiple objects with nested arrays]
}
creating button inside google maps then addEventListener
let themeToggle = document.createElement('button');
themeToggle.classList.add('controlUI');
themeToggle.innerHTML = ('Mode');
themeToggle.title = 'Change map theme';
map.controls[google.maps.ControlPosition.TOP_LEFT].push(themeToggle);
let mode = true;
themeToggle.addEventListener('click', () => {
if (mode) {
map.setOptions({styles: theme.night});
} else {
map.setOptions({styles: theme.default});
}
mode = !mode;
});
Above Works Fine
Im struggling to convert the if else to a loop and select each object key and then adding that to:
map.setOptions({styles: theme.night})
and then on click it loops through each key and repeat
themeToggle.addEventListener('click', () => {
for ( let key in theme) {
map.setOptions({styles: theme[key]});
console.log(theme[key])
}
});
it selects the last one by default and i cant toggle.
Any help would e really appreciated, just trying add all the puzzle together.
Collect the object values into an array, then increment an index with modulo on every click:
const vals = Object.values(theme);
let i = 0;
themeToggle.addEventListener('click', () => {
map.setOptions({styles: vals[i]});
i = (i + 1) % vals.length;
});
While most environments will result in an object's Object.values in ascending numeric followed by insertion order, it's not guaranteed. If you need a guaranteed predictable ordering, use Reflect.ownKeys (or Object.getOwnPropertyNames) instead:
const vals = Reflect.ownKeys(theme)
.map(key => theme[key]);
You can loop through an object like this
var invoice = {
name: 'anik',
age: 29,
designation: 'Full Stack Developer'
}
Object.keys(invoice).map((d,i)=>{
console.log(d +' : '+invoice[d]);
})

What's the best way to delete specific characters in a JavaScript array?

Currently, I have a huge JavaScript array where each element is like this:
[{"open":235.86,
"high":247.13,
"low":231.5,
"close":244.1,
"volume":55025735,
"date":"2019-05-01T21:00:00.000Z"}
...
I need to remove everything except the price after high. What is the most efficient way I can do this?
I've tried popping the individual elements, but I can't help but feel as if there is a more efficient/easier way to do this.
So hopefully the ending array would just be [235.86].
The below code should work. It's efficient enough :D
for (i in arrayName){
// Loops through array
delete arrayName[i].high
delete arrayName[i].low
delete arrayName[i].close
delete arrayName[i].volume
delete arrayName[i].date
// Deletes unwanted properties
}
console.log(arrayName)
// Print output
One potential solution would be to map the array to a new array like so:
const yourArray = [
{"open":235.86, "high":247.13, "low":231.5, "close":244.1, "volume":55025735},
{"open":257.52, "high":234.53, "low":220.2, "close":274.1, "volume":23534060},
]
const mappedArray = yourArray.map(el => el.open);
// mappedArray = [235.86, 257.52]
Check out the MDN documentation for the map method, Array.prototype.map()
Note: The above example uses ECMAScript 6 arrow functions and implicit returns. It is functionally equivalent to:
const yourArray = [
{"open":235.86, "high":247.13, "low":231.5, "close":244.1, "volume":55025735},
{"open":257.52, "high":234.53, "low":220.2, "close":274.1, "volume":23534060},
]
const mappedArray = yourArray.map(function(el){
return el.open
});
You can use reduce for this scenario. Example
var temp = [{"open":235.86, "high":247.13, "low":231.5, "close":244.1, "volume":55025735, "date":"2019-05-01T21:00:00.000Z"}];
var highValArray = temp.reduce((arr, t) => {
return arr.concat(t['high']);
}, []);
You can learn more about reduce function at the MDN website.
This should work:
your_array.map((item) => {
return item.high
})

Filter one ag-grid based on event from another one

I want to select one row in my first grid grid1 and the event function would then filter my other grid grid2 based on the values found in the selected row. I am using the pure javascript version of the library.
Something like
gridOptions:{
onRowSelected:my_event_filter_func,
rowData: [...],
columnDefs:[...]
}
grid1 = new agGrid.Grid(document.querySelector("#the_place"),gridOptions)
(grid2 is defined the same way based on different data and w/o the event function)
where my_event_filter_func is
my_event_filter_func = function(event) {
let my_name = event.data.name
// filter grid2 to show only the rows where the 'name' column matches my_name
}
Any help is appreciated.
I can't give you a line by line answer, and I am assuming that you are able to get your selected rows. But what I can suggest is, first, you create a copy of your the data that is on your grid2.
function copyData() {
rowData = [];
gridApi.forEachNode(node => rowData.push(node.data));
// temp is the copy of your full data in grid2
temp = [...rowData];
}
Next, on your my_event_filter_func, you can filter out the rows to be shown on grid2, based on the filtered value from grid1.
function my_event_filter_func(event) {
let my_name = event.data.name
// get the rows that do not have the matching value
const rowsToBeRemoved = temp.filter(row => row['name'] !== my_name);
// remove the rows from grid2 that do not have the matching names
gridOptions.api.updateRowData({remove: rowsToBeRemoved});
}
The source for the 2 grids is the underlying data for grid1 so it made my life easier. If that is not the case, you do need to save your base data for grid2 somewhere so that you can access it when the event gets triggered.
I ended up declaring my 2 grids as global variables and using the function below as event function :
var onSelectionChanged = function(event) {
let name = grid1.gridOptions.api.getSelectedRows()[0].name; // we know there is only one
let newRowData = grid1.gridOptions.rowData
.filter(x => x.name===name)
.map(x => {
return {
'name': x.name
// other fields...
}
})
// this overwrites grid2 data so need to save original data somewhere.
grid2.gridOptions.api.setRowData(newRowData);
grid2.gridOptions.api.refreshCells({force:true});
};

how to print a javascript object's elements

i am new to javascript and i currently have an object printed to console when i use the following code:
clickEvents: {
click:function(target) {
console.log(target);
}
}
when i view console i can see the following object:
i am banging my head against a wall to write code that takes the object and prints it to a div using the .append() method. i am extermely new to working with javascript objects, and would appreciate any help trying to tease out an object and/or print the object data.
is events the object name? would i tease out the eventDate using something like events->eventDate?
I've made this over ~15 minutes so it's imperfect; there are types and edge cases surely unaccounted for and the design of the function could be better - not to mention that performing all of this as a giant string and then setting that as HTML is likely bad practice (I'm used to React now, ha!). Regardless, this will iterate over any array or object you pass to it and print it all in a big <ul> recursively.
const targetEl = document.querySelector('.js-target')
if (!targetEl) return
// Small helper functions
const isObj = data => typeof data === 'object' && !Array.isArray(data) && data !== null
const isArr = data => Array.isArray(data)
const dataToHTML = (data, noNode = false) => {
if (isObj(data)) {
const accumulator = Object.entries(data).reduce((acc, set) => acc + `<li><strong>${set[0]}</strong>: ${dataToHTML(set[1], true)}</li>`, '')
return `<ul>${accumulator}</ul>`
}
else if (isArr(data)) {
const accumulator = data.reduce((acc, item) => acc + dataToHTML(item), '')
return `<ul>${accumulator}</ul>`
}
else return noNode ? data : `<li>${data}</li>`
}
const logHTML = dataToHTML(exampleData)
targetEl.innerHTML = logHTML
Assuming that your data/variable is named exampleData.
Any questions pop them in the comments :-)
I'm not sure if you have a div that you want to append to already, but you would do something like this ->
document.getElementById("toBeAppendedTo").innerHTML = target.events[0].eventDate; where toBeAppendedTo is the id of the div you're trying to add this text to.
append() is a jquery function, not a javascript function.
That won't have any formatting and will just be the string value 07-28-2017 in a div.

Categories

Resources