Iterating through an array nested inside of an object - javascript

thank you for the help in advance! Please forgive me if this is a stupid question as I a JS noobie.
I am trying to cycle through an array of URL's that I have nested inside of an object. What I am expecting to happen is for the url's (which are google maps) to show up on my website and for the person using my website to be able to click back and forth between the different map URL's. Right now what's happening is the last item (a google maps url) of myCities.index is being properly displayed, but when I click my previous and next buttons it is going to a blank page. I have looked at my JS console and there are no visible errors there. Can anyone give me some advice as to how to fix this? My code is as follows.
const myCities = {
index:
[url1, url2, url3]
}
const prevButton = document.querySelector('.prevBtn');
const nextButton = document.querySelector('.nextBtn');
const map = document.getElementById("myCitiesss");
nextButton.addEventListener('click', nextCity);
prevButton.addEventListener('click', prevCity);
function prevCity() {
myCities.index--;
updateSrc();
checkButtons();
}
function nextCity() {
myCities.index++;
updateSrc();
checkButtons();
}
function updateSrc() {
map.src = myCities.index;
}
function checkButtons() {
prevButton.disabled = false;
nextButton.disabled = false;
if (myCities.index === 2) {
nextButton.disabled = true;
}if (myCities.index === 0) {
prevButton.disabled = true;
}
}
updateSrc();
checkButtons();

The problem is you're treating myCities.index as both the container of your data and as a counter (hence you're running incrementation/decrementation operations on it).
The counter should be a separate variable.
const myCities = [url1, url2, url3]; //<-- can now be a flat array
let index = 0; //<-- this is our counter, i.e. tracker
The relevant code changes are then: (I also took the opportunity to demonstrate some optimisations and efficiencies you can make)
nextButton.addEventListener('click', () => nextPrevCity('next'));
prevButton.addEventListener('click', () => nextPrevCity('prev'));
function nextPrevCity(which) { //<-- one function to handle both next and prev
which == 'next' ? index++ : index--;
map.src = myCities[index];
checkButtons();
}
function checkButtons() {
prevButton.disabled = false;
nextButton.disabled = false;
if (index === myCities.length - 1) //<-- check against array length, not fixed number 2
nextButton.disabled = true;
if (!index) //<-- because 0 is a falsy value, so same as "if (index === 0)"
prevButton.disabled = true;
}
[ -- EDIT -- ]
Forgot the following at the bottom of the code:
map.src = myCities[0];
checkButtons();

Related

matter.js: collisionStart triggered many times for one collision

I am working on a game app using React native and Matter.js.
I am trying to implement a system that adds points every time a bullet hits a target.
In order to do this, I am trying to use collisionStart to detect the collision.
However, even though the bullet and target collide only once, the event seems to be triggered 41 times.
This is the code:
Matter.Events.on(engine, 'collisionStart', (event) => {
let pairs = event.pairs
for (const pair of pairs) {
if (pair.bodyA.label === 'bullet' && pair.bodyB.label === 'Worm') {
console.log("target hit");
}
}
})
In the end, I'm planning to replace console.log with something that adds points. At the current moment, one collision seems like it would trigger the add points 41 times, which is obviously not ideal.
Any ideas what is happening here and how I can get this to trigger only once for one collision?
Try next example. I take it from my own project [you need little adaptd from ts to js]:
Matter.Events.on(this.starter.getEngine(), "collisionStart", function (event) {
root.collisionCheck(event, true);
});
public collisionCheck(event, ground: boolean) {
const myInstance = this;
const pairs = event.pairs;
for (let i = 0, j = pairs.length; i !== j; ++i) {
const pair = pairs[i];
if (pair.activeContacts) {
if (pair.bodyA.label === "bullet" && pair.bodyB.label === "Worm") {
const collectitem = pair.bodyA;
this.playerDie(collectitem);
} else if (pair.bodyB.label === "bullet" && pair.bodyA.label === "Worm") {
const collectitem = pair.bodyB;
this.playerDie(collectitem);
}
// ....
}
}
}
public destroyBody = (destroyBody) => {
try {
Matter.Composite.remove(this.getWorld(), destroyBody);
} catch(err) {
console.log(err)
}
}
If you still have same problem , we can adapt also with flag PREVENT_DOUBLE_BY_1_SECOUND for example.

How do I use data out of chrome.storage.get function?

I'm trying to grab data from chrome extension storage, but I can use them only in this function.
var help = new Array();
chrome.storage.local.get(null, function(storage){
//get data from extension storage
help = storage;
console.log(storage);
});
console.log(help); // empty
Result in console:
content.js:1 content script running
content.js:11 []
content.js:8 {/in/%E5%BF%97%E9%B9%8F-%E6%99%8F-013799151/: "link", /in/adam-
isaacs-690506ab/: "link", /in/alex-campbell-brown-832a09a0/: "link",
/in/alex-davies-41513a90/: "link", /in/alex-dunne-688a71a8/: "link", …}
Async function has won. I wrote my code again and now function is called hundreds time, i can not do this in dirrefent way
code:
console.log("content script running");
var cards = document.getElementsByClassName("org-alumni-profile-card");
var searchText = "Connect";
function check(exi, cards) {
chrome.storage.local.get(null, function(storage) {
for (var key in storage) {
if (storage[key] == "link" && key == exi) {
cards.style.opacity = "0.3";
}
}
});
}
for (var i = 0; i < cards.length; i++) {
var ctd = cards[i].getElementsByClassName(
"org-alumni-profile-card__link-text"
);
var msg = cards[i].getElementsByClassName(
"org-alumni-profile-card__messaging-button-shrunk"
);
if (ctd.length < 1 || msg.length > 0) {
cards[i].style.display = "none";
} else {
var exi = cards[i]
.getElementsByClassName("org-alumni-profile-card__full-name-link")[0]
.getAttribute("href");
check(exi, cards[i]);
}
}
SOLUTION of my problem
I wanted to delete this topic, but I can not, so instead of doing that, I'll put here what I've done finally.
The code above is wrong becouse, it was taking a list of links from website and for each from them script was grabbing a data from a storage... Which was stupid of course. I didn't see a solution which was so easy:
Put all your file's code in this function - it grabs data from storage just once.
I'm so sorry for messing up this wonderfull forum with topic like this.
Hope u'll forgive.
help will return undefined because it is referencing a asynchronous function and not the return value of that function. The content from storage looks to be printed on content.js:8, i.e. line 8.

Javascript basic loop help - basic

Im learning Javascript now and I got a question that's been bugging me!
So, all I needed to do here is to type a color on this input box, click the button and change the headline to the color typed only if that typed color is in the array specified in the variable.
My code is half working... it does check if whatever color typed is inside the array, but the alert button pops up each time, is there a way to make the alert pop up only if the color typed isn't in the array please?
Working code: https://codepen.io/anon/pen/ddPWLP
Javascript code:
const myHeading = document.getElementById('myHeading');
const myButton = document.getElementById('myButton');
const myTextInput = document.getElementById('myTextInput');
var colors = ["red", "black", "blue"];
myButton.addEventListener('click', () => {
for (var i=0; i<colors.length; i++){
if (myTextInput.value === colors[i]){
myHeading.style.color = myTextInput.value
} else {
alert("no color")
}
}
});
Don't do it inside the loop. Use a variable to flag when you find a match, and then after the loop check that flag and display the alert accordingly. Try this:
myButton.addEventListener('click', () => {
var found = false;
for (var i = 0; i < colors.length; i++) {
if (myTextInput.value === colors[i]) {
myHeading.style.color = myTextInput.value
found = true;
}
}
if (!found)
alert("no color");
});
By the way, you don't need a loop for that. You can simply use the indexOf() methods. If the value exists in the array, it returns its index, otherwise it returns -1. Try this:
myButton.addEventListener('click', () => {
if (colors.indexOf(myTextInput.value) > -1)
myHeading.style.color = myTextInput.value
else
alert("no color");
});

Associative array not filling up in server-sent-event environement

I think I'm on the wrong track here:
I have an event source that gives me updates on the underlying system oprations. The page is intended to show said events in a jquery powered treetable. I receieve the events perfectly but I realized that there were a case I did not handle, the case where an event arrives but is missing it's parent. In this case I need to fetch the missing root plus all potentially missing children of that root node from the database. This works fine too.
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data)
return;
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
});
}
The problem is around the line if (headlessRows[parentEventId]).
When I run it step by step (putting a debugger instruction just before) everything works fine, the headless array is created and filled correctly.
But as soon as I let it run full speed everything breaks.
The logs I printed seems to indicate that the array is not behaving in the way I was expecting it to. If I print the array with a console.log it shows as follow :
(2957754) [empty × 2957754]
length : 2957754
__proto__ : Array(0)
It seems to be missing any actual data. whereas it shows as follow when I execute it step by step:
(2957748) [empty × 2957747, Array(1)]
2957747:[tr.node.UNDETERMINED]
length:2957748
__proto__:Array(0)
I'm missing something but it is still eluding me.
your code is async, you do http request but you treat him as synchronized code.
try this fix
//init fct
//...
eventSource.addEventListener("new_node", onEventSourceNewNodeEvent);
//...
async function onEventSourceNewNodeEvent(event) {
let data = event.data;
if (!data)
return;
let rows = $(data).filter("tr");
rows.each(function (index, row) {
let parentEventId = row.getAttribute("data-tt-parent-id");
let parentNode = _table.treetable("node", parentEventId);
// if headless state is not fully
// resolved yet keep adding new rows to array
if (headlessRows[parentEventId]) {
headlessRows[parentEventId].push(row);
return;
} else if (parentEventId && !parentNode) { // headless state found
if (!headlessRows[parentEventId])
headlessRows[parentEventId] = [];
headlessRows[parentEventId].push(row);
await fetchMissingNodes(parentEventId);
return;
}
insertNode(row, parentNode);
});
}
function fetchMissingNodes(parentEventId) {
return new Promise((resolve,reject) =>{
let url = _table.data("url") + parentEventId;
$.get(url, function (data, textStatus, request) {
if (!data){
resolve()
return;
}
let rows = $(data).filter("tr");
//insert root and children into table
_table.treetable("loadBranch", null, rows);
let parentNode = _table.treetable("node", parentEventId);
let lastLoadedRow = $(rows.last());
let headlessRowsArray = headlessRows[parentEventId];
while (headlessRowsArray && headlessRowsArray.length > 0) {
let row = headlessRowsArray.shift();
let rowId = row.getAttribute("data-tt-id");
if (rowId <= lastLoadedRow) // already loaded event from previous fetch
continue;
insertNode(row, parentNode);
let pendingUpdatesArray = pendingUpdates[rowId];
// shouldn't be more than one but who know future versions
while (pendingUpdatesArray && pendingUpdatesArray.length > 0) {
let updateEvent = headlessRowsArray.shift();
updateNode(updateEvent)
}
delete pendingUpdates[rowId]; // <- something better here?
}
delete headlessRows[parentEventId]; // <- something better here too?
resolve()
});
})
}

Overwrite/Replace Value in multi-dimensional array

So I am currently trying to overwrite a value in my multidimensional array.....where I want to overwrite a value based on the position of where channel.name is and change the value of the mute state if you will.
So what I want to do is:
Mute value in array
When I call the function to unmute it, I want to replace the "Mute" Value with "Unmute".
Then do the same Mute and effectively toggle values.
The problem is I am currently always pushing the values on over and over like so: [ [ '1447682617.29', 'SIP/487-0000000b', 'Mute', 'Unmute' ] ]
I simply just want to overwrite Mute and Replace it with Unmute.
I have the index part fine its just being able to overwrite that value.
The code I have so far is:
//ARI function to mute channels.
function mute(mutval,mutestate) {
console.log("Muting:" + mutval);
var index = 0;
var findex = false;
for (var i in channelArr) {
var channelArrEle = channelArr[i];
if (channelArrEle[0] == mutval) {
index = i;
findex = true;
console.log("First Part works!")
}
}
if (findex) {
channelArr[index].push(mutestate);
console.log(channelArr);
} else {
console.log("Error")
}
}
//ARI function to unmute channels which have been muted.
function unmute(unval,mutestate) {
console.log("Unmuting: " + unval);
var index = 0;
var findex = false;
for (var i in channelArr) {
var channelArrEle = channelArr[i];
if (channelArrEle[0] == unval) {
index = i;
findex = true;
console.log("First Part works!")
}
}
if (findex) {
channelArr[index].push(mutestate);
//Just added this to see what would happen!
channelArr[index] = mutestate;
console.log(channelArr);
} else {
console.log("Error")
}
}
Any suggestions no doubt its something minor question is what.
Try change (in both occurence)
channelArr[index].push(mutestate);
with
var channelData = channelArr[index];
channelData[2] = mutestate;
channelArr[index] = channelData;
And if it works, you can try to shorten the code like this
channelArr[index][2] = mutestate;

Categories

Resources