JS - Array (Fuse 2 arrays into one) - javascript

Alright so I stuck on the code reading docs.
Iam starting with JS so go easy one me =].
I've got and array calld Area
which contains few arguments
let Area = ["Kanig Village", "Fort Chune", "Shadowy Heights", ...];
I cannot change this array till specific part of my code is executed but after I wish to add to every position another value. How to I do that to get exacly like that :
let Area = ["Kanig Village 14:30", "Fort Chune 15:30", "Shadowy Heights 16:30", ...];

I THINK this is what you want to do:
https://jsfiddle.net/wxzrpjeL/
//Declare 2 arrays
let Area = ["Kanig Village", "Fort Chune", "Shadowy Heights"];
let b = ["1", "2", "3"];
//Execute a function for each element in the Area array
Area.forEach(function(val, i) {
//The function appends a space, and the corresponding element in the second array
Area[i] += " " + b[i];
});
// just to illustrate the result, throw the result to the screen as a string...
alert(Area.toString());

i hope this is your answer
let Area = ["Kanig Village", "Fort Chune", "Shadowy Heights"];
for(i=0;i<Area.length;i++)
{
var hour=14+i;
Area[i]+=" "+hour+" : 30";
}

Related

Fetching objects using a variable from user input

I have been looking for the answer to this problem, but I haven't found exactly a similar issue.
I have created several objects (ob0, ob1, ob2) they all contain the same entries.. but on each object the value of the entries is different. i.e. ob0.brand has one value but oj1.brand has a different value.
I want to visualize the info of the objs on a website. there is a radio button that returns ob0, ob1, or ob2 accordingly to what is chosen.. and on one div class, the text content of the value of the entries is to be displayed.
the radio buttons value is named a var objSelc and try to use documentselctor to display ojbSelc.brand so that whatever the user selects would represent obj0.brand or obj1.brand etc. However, this returns an error.
Maybe it's not possible to use a var as the name of an object? or what workaround would there me??
btw I am a level 0.1 first month of learning, Any help will be appreciated.
here is the snippet of code in question:
so here is for example an inventory of a bike and the different components, brake pads, tires, chain etc. I have made different copies of these but replaced the content info.
let UA = {
brakes: "shimano b10s",
backTire: " Bigben 26",
frontTire: "bigben 20",
bikeChain: " 1/32 single speed",
motorBrand: " Bosch Intuvia, cargoline",
};
let cargoCarla = {
breaks: "shimano b10s",
backTire: "big apple 24",
frontTire: "big apple 20",
bikeChain: "na",
motorBrand: "na",
};
Here comes some user input from the radio buttons from the HTML site
var form = document.querySelector("form");
var log = document.querySelector("#log");
form.addEventListener(
"submit",
function (event) {
var data = new FormData(form);
var output = "";
for (const entry of data) {
output = output + entry[0] + "=" + entry[1] + "\r";
}
// log.innerText = output;
event.preventDefault();
var splitOut = output.split("=");
var bikeSelc = splitOut[1].toString();
showComponent.textContent = bikeSelc.brakes;
},
false
);
In fact, bikeSelc does produce either UA or cargoCarla depending on which was selected. but bikeSelc.brakes do not produce a result so JS is not reading the value of bikeSelc when added to.brakes. even though consel.log does give the proper variable.
showComponent.textContent = UA.brakes;
This was just me hardcodingto see what it would look like on the DOM

Select Random Item (shown in pairs) from Array & Remove It, Restart Once Array is Empty

I'm super newbie in coding and I need help to achieve this code.
I'm trying to get a random item (in pairs) from an array and then remove it from this array until user gets to the last item or 60 days have gone from using the service (cookie?)... I have build a script with the help of other questions here in stackoverflow and here is my results so far.
`<script>
var randomizer = document.getElementById("getImgBut");
var dog1 = '/app/wp-content/mediaApp/yo-creo-mi-realidad/01F.jpg';
var dog2 = '/app/wp-content/mediaApp/yo-creo-mi-realidad/01B.jpg';
var dogpics=[dog1,dog2];
var yourPics = [
dogpics,
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/02F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/02B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/03F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/03B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/04F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/04B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/05F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/05B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/06F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/06B.jpg' ] //This array has 52 cards but I cutted it for example purposes
];
function get_random_number(array){
return Math.floor(Math.random() * array.length |0);
} // here is where I have tried to modify with other scripts like the one in this page https://stackoverflow.com/questions/38882487/select-random-item-from-array-remove-it-restart-once-array-is-empty with no success
randomizer.addEventListener("click", function() {
var rand_number = get_random_number(yourPics);
console.log(rand_number);
document.getElementById('img1').src = yourPics[rand_number][0];
document.getElementById('img2').src = yourPics[rand_number][1];
});
var card = document.querySelector('.card');
card.addEventListener( 'click', function() {
card.classList.toggle('is-flipped');
});
</script>`
Thank you for your help!
I don't fully understand what you mean by "remove in pairs", but I'll answer presuming you mean you wish to remove the image ending in 02F.jpg at the same time as removing the image ending in 02B.jpg, and then 03F.jpg at the same time as 03B.jpg.
The solution to this that I will propose is that we will structure your data a bit differently to begin with. That is, if those images, the "B image" and "F image" are linked, we could keep them in the same `javascript object. This would look like:
var yourPics = [
{
bImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/02F.jpg',
fImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/02B.jpg'
},
{
bImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/03F.jpg',
fImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/03B.jpg'
}...]
This would then be an array of objects, rather than strings. We can access the bImage property of an object with just
myObject = yourPics[0]
myObject.bImage
We could delete one of those objects those at random via splice.
myRandomlyRemovedObject = yourPics.splice(myIndexToDeleteFrom, 1) would remove 1 object from yourPics at position of myIndexToDeleteFrom, which you presumably would choose randomly. myRandomlyRemovedObject would be assigned to the one object we removed.
I think this object based approach is safer since you will know for a fact that you will removed both matching strings at the same time.

The object referred to by string isn't being displayed

My Intent: Making a CYOA Using Objects
I'm quite new to Javascript and have been trying to make a simple CYOA game, using this code from this Reddit comment as a template. However, I want to use objects (whose values are intended to be constant) to store the various string values for the messages and the object each choice points to, as opposed to having all the objects in arrays and having to point to them using using their index in the array. My reasoning is that it'd be (theoretically) simpler for me to organize using strings like "msg_001" or "story5_28" rather than having to change a bunch of numbers in the event I inserted some new set of messages in the middle of an array.
My Problem: The First Message Isn't Displayed Again
Basically, I want to loop back to the first message and its set of answers, but it won't.
The initial printCurrentMsg() works (changing the content of the "message" divs to the values of msgText, and looping through the object's choices array to set the buttons in the "choices" div, based on the object specified in currentMsg) and the buttons' respective onlick attributes seem to work, until they're set to show msg_000.
It appears to be that whatever the value of currentMsg is, printCurrentMsg won't show the object the string refers to, other than when it does initially. Additionally, after using console.log at various points in the script, I noticed that currentMsg isn't changed, and using console.log(typeof) for both currentMsg and window[currentMsg] shows that the former is a string and the latter is an object. Am I unintentionally creating two separate variables?
I've tried...
...using parameters in printCurrentMessage.
...using currentMsg in the functions instead of window[currentMsg].
...using dot notation instead of bracket notation.
...using this[] instead of window[].
I'm not sure whether this has to do with asynchronicity, I'm accessing object properties incorrectly, my comprehension of scope is flawed, or if I'm erroneously using global variables. Should I be using some sort of callback?
Using a "dummy" msg_000—making another object with a different name but the same properties—serves as a stopgap solution, but I still wouldn't understand what the problem is. Having all the msg_*** objects in an array and referring to them by index number instead of string would also work, but I'm hesitant to rely on that for both the aforementioned tediousness and the fact that I still don't understand why the value of currentMsg remains unchanged.
In order to better articulate my problem, here is a jsfiddle with my code, and I shall post it below as well.
//messages
var msg_000 = { //Starts with this one, I want to be able to go back to it
msgName: "msg_000",
msgText: "Sup! Choose an option!",
choices: [
ans_000 = {
ansText: "Climb a hill!",
ansGoto: "msg_001" //this works
},
ans_001 = {
ansText: "Skin a cat!",
ansGoto: "msg_002" //this works
},
ans_002 = {
ansText: "Build a birdhouse!",
ansGoto: "msg_003" //this works
}
]
};
var msg_001 = {
msgName: "msg_001",
msgText: "You summit the great snowy peaks!",
choices: [
ans_000 = {
ansText: "Talk to the Recursion Guru!",
ansGoto: "msg_000" //this doesn't work
}
]
};
var msg_002 = {
msgName: "msg_002",
msgText: "You suffer severe lacerations to the face!",
choices: [
ans_000 = {
ansText: "Start Over",
ansGoto: "msg_000" //this doesn't work
}
]
};
var msg_003 = {
msgText: "You build a pretty average looking birdhouse. Some grackles have moved in nonetheless, placing their various knicknacks, bedding materials, and chrono-gateways within their new abode.",
choices: [
ans_000 = {
ansText: "Step through the chrono-gateway!",
ansGoto: "msg_000" //this doesn't work
},
ans_001 = {
ansText: "I think I wanna climb that mountain over there.",
ansGoto: "msg_001" //this works
}
]
}
var currentMsg = "msg_000"; //the first message is "msg_000"
printCurrentMsg = function() {
document.getElementById("message").innerHTML =
window[currentMsg].msgText;
//sets the message (the div with the id of "message")
//based on the "currentMsg" variable. "currentMsg.msgText"
//doesn't seem to work.
var choices = "";
for (var i = 0, l = window[currentMsg].choices.length; i < l; i++) {
choices += "<p><button onclick='setMessage(" +
window[currentMsg].choices[i].ansGoto + ")'>" +
window[currentMsg].choices[i].ansText + "<br>Goto " +
window[currentMsg].choices[i].ansGoto + "</button></p>";
//make the buttons, sets the button's onclick
//"setMessage" function's parameter to the the value of
//the "ansGoto" property -> in the answers object at the
//i/th index of the choices property array -> in the
//"msg_(number)" object."
};
document.getElementById("choices").innerHTML = choices;
//takes the value of the "choices" [local?] variable and puts
//it in the "choices" div.
};
setMessage = function(msg) {
window[currentMsg] = msg; //I think this is the source of all
//my problems, it's supposed to set "currentMsg" to the value
//of the "msg" parameter, but when I check it with
//console.log(currentMsg) it hasn't been changed (i.e., still
//it's initial value of "msg_000") and when I use
//console.log(window[currentMsg]) it returns "[Object
//object]"; using typeof shows me that "currentMsg" is a
//string and "window[currentMsg]" is an object. I thought
//they both were the same object, am I unintentionally
//creating two different objects?
printCurrentMsg(); //runs that function, seems to display the
//messages except the ones from object "msg_000".
};
printCurrentMsg(); //Displays the initial message and choices
//from "msg_000", but after a new message is chosen it won't
//display "msg_000" if it's pointed to from an "ansGoto"
//property.
<!DOCTYPE html>
<html>
<body>
<div id="message"></div>
<!-- "msgText" goes here -->
<div id="choices"></div>
<!-- "choices" go here -->
</body>
</html>
Thank you for your time.
When setMessage() does window[currentMsg] = msg;, it replaces the value of the variable holding a message. E.g. if the current message is msg_000, and you do setMessage(msg_002), it's equivalent to writing msg_000 = msg_002;.
What you really want to do is change the value of currentMsg to be the name of the new message. So you should do: currentMsg = msg.msgName;.
You were also missing the msgName property in msg_003.
As a best practice, you shouldn't use global variables for all this. Create your own object messages, and use messages[currentMsg].
//messages
var msg_000 = { //Starts with this one, I want to be able to go back to it
msgName: "msg_000",
msgText: "Sup! Choose an option!",
choices: [
ans_000 = {
ansText: "Climb a hill!",
ansGoto: "msg_001" //this works
},
ans_001 = {
ansText: "Skin a cat!",
ansGoto: "msg_002" //this works
},
ans_002 = {
ansText: "Build a birdhouse!",
ansGoto: "msg_003" //this works
}
]
};
var msg_001 = {
msgName: "msg_001",
msgText: "You summit the great snowy peaks!",
choices: [
ans_000 = {
ansText: "Talk to the Recursion Guru!",
ansGoto: "msg_000" //this doesn't work
}
]
};
var msg_002 = {
msgName: "msg_002",
msgText: "You suffer severe lacerations to the face!",
choices: [
ans_000 = {
ansText: "Start Over",
ansGoto: "msg_000" //this doesn't work
}
]
};
var msg_003 = {
msgName: "msg_003",
msgText: "You build a pretty average looking birdhouse. Some grackles have moved in nonetheless, placing their various knicknacks, bedding materials, and chrono-gateways within their new abode.",
choices: [
ans_000 = {
ansText: "Step through the chrono-gateway!",
ansGoto: "msg_000" //this doesn't work
},
ans_001 = {
ansText: "I think I wanna climb that mountain over there.",
ansGoto: "msg_001" //this works
}
]
}
var currentMsg = "msg_000"; //the first message is "msg_000"
printCurrentMsg = function() {
document.getElementById("message").innerHTML =
window[currentMsg].msgText;
//sets the message (the div with the id of "message")
//based on the "currentMsg" variable. "currentMsg.msgText"
//doesn't seem to work.
var choices = "";
for (var i = 0, l = window[currentMsg].choices.length; i < l; i++) {
choices += "<p><button onclick='setMessage(" +
window[currentMsg].choices[i].ansGoto + ")'>" +
window[currentMsg].choices[i].ansText + "<br>Goto " +
window[currentMsg].choices[i].ansGoto + "</button></p>";
//make the buttons, sets the button's onclick
//"setMessage" function's parameter to the the value of
//the "ansGoto" property -> in the answers object at the
//i/th index of the choices property array -> in the
//"msg_(number)" object."
};
document.getElementById("choices").innerHTML = choices;
//takes the value of the "choices" [local?] variable and puts
//it in the "choices" div.
};
setMessage = function(msg) {
currentMsg = msg.msgName;
printCurrentMsg(); //runs that function, seems to display the
//messages except the ones from object "msg_000".
};
printCurrentMsg(); //Displays the initial message and choices
//from "msg_000", but after a new message is chosen it won't
//display "msg_000" if it's pointed to from an "ansGoto"
//property.
<!DOCTYPE html>
<html>
<body>
<div id="message"></div>
<!-- "msgText" goes here -->
<div id="choices"></div>
<!-- "choices" go here -->
</body>
</html>

Search through json with keywords

I need some help with a small thing I am struggeling with. I have to create a general search input that searches though a json of music numbers. The user has to be able to type an album/track or artist in the searchbar and then he'll get the result. Like any other search bar does. Only this one searches based on keypresses instead of a submit button.
The part where I'm stuck is that I've received a large JSON file with more than 5000 entries. And my search bar has to be able to identify entries based on partially typed "keywords". So for instance if I want to search for madonna and I type in "mado" I should already get some madonna in my results ( of course its possible to get other entries that have mado in their title or someting! ).
Sorry for my lack of good grammar but I try my best to explain the situation as good as possible!
Now for the question! The thing I'm struggeling with is how I loop through a json file to search for these keywords. This is a small portion of the json I receive:
{
"1": {
"track": "Dani California",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"2": {
"track": "Tell me baby",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"3": {
"track": "Snow (Hey Oh)",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
}}
Normally I would create a function that is something like this:
for(var i = 0; i < data.length; i++){
if(data[i].album == 'red hot'){
console.log(data[i].album)
}}
But in this case I want to loop through the json, looking for enties that contain the search value an save it to an object for later usage
Is it possible to do this all at once? So to check the artist/title/album at once, or would it be better to create a small filter?
If something is not clear about my explanation please met me know I tried my best to be as clear as I could be!
I dont think searching 5000 entries should cause performance issues.
Check out this code which should return the desired entries when you call search('text')
var data = JSON.parse('JSON DATA HERE') // dataset
var search_fields = ['track','artist','album'] //key fields to search for in dataset
function search(keyword){
if(keyword.length<1) // skip if input is empty
return
var results = []
for(var i in data){ // iterate through dataset
for(var u=0;u<search_fields.length;u++){ // iterate through each key in dataset
var rel = getRelevance(data[i][search_fields[u]],keyword) // check if there are matches
if(rel==0) // no matches...
continue // ...skip
results.push({relevance:rel,entry:data[i]}) // matches found, add to results and store relevance
}
}
results.sort(compareRelevance) // sort by relevance
for(i=0;i<results.length;i++){
results[i] = results[i].entry // remove relevance since it is no longer needed
}
return results
}
function getRelevance(value,keyword){
value = value.toLowerCase() // lowercase to make search not case sensitive
keyword = keyword.toLowerCase()
var index = value.indexOf(keyword) // index of the keyword
var word_index = value.indexOf(' '+keyword) // index of the keyword if it is not on the first index, but a word
if(index==0) // value starts with keyword (eg. for 'Dani California' -> searched 'Dan')
return 3 // highest relevance
else if(word_index!=-1) // value doesnt start with keyword, but has the same word somewhere else (eg. 'Dani California' -> searched 'Cali')
return 2 // medium relevance
else if(index!=-1) // value contains keyword somewhere (eg. 'Dani California' -> searched 'forn')
return 1 // low relevance
else
return 0 // no matches, no relevance
}
function compareRelevance(a, b) {
return b.relevance - a.relevance
}
Since it's not an array you can't use Array.prototype.filter() unless you turn your object into an array. You could do this every time you get a new Json, no need to do this with every search.
var myArray = [];
for(var elementName in data) //We iterate over the Object to get the names of the nested objects
myArray.push(data[elementName]); //We get the objects of the json and push them inside our array.
Then you can use .filter to filter your data, I recommend using regex:
var userQuery = 'Mado' //user input
var myRegex = new RegExp('.*' + userQuery + '.*','gi'); //We create a new regular expression, this one tests if the text is contained within a string.
var filteredArray = myArray.filter(function(item){
//We test each element of the object to see if one string matches the regexp.
return (myRegex.test(item.track) || myRegex.test(item.artist) || myRegex.test(item.album))
});
filteredArray should be the elements of the json you need.
Array.prototype.filter MDN
RegeExp MDN
Here's a pattern I often use for filter functionalities. Some key points are:
Always build an index property that contains the appended string of the filterable values. For example, if the values of 'track','artist' and 'album' can be filtered on, then join their values into a string, and add that string as one of the properties to the original object.
This helps quickly search using indexOf, rather than having to iterate through each object when filtering. It significantly improves the performance as those iterations and additional number of properties*number of objects comparisons are no longer required. In your case, you'd be saving roughly 10k comparisons and 15k iterations with every filter operation.
If the filter operation is case-insensitive, use toLowerCase while appending the values to build indexes. It also saves you from performing those many toLowerCase operations every time filter is called.
Always create an array of objects, rather than an object with object properties. I don't have specific stats on whether this improves performance or not, but it provides you some array methods such as array.filter or array.sort that you could utilize to improve UX. I haven't done that in the snippet, but you can do that quite easily while preparing the data.
var data = {
"1": {
"track": "Dani California",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"2": {
"track": "Tell me baby",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
},
"3": {
"track": "Snow (Hey Oh)",
"artist": "Red Hot Chili Peppers",
"album": "Stadium Arcadium"
}};
// One time activity!
// Build search indexes, for every object.
for(var prop in data) {
if(data.hasOwnProperty(prop)) {
var index = "";
var item = data[prop];
// Iterate over each object and build the index by appending the values of each property.
for(var attr in item) {
if(item.hasOwnProperty(attr)) {
// Note: Different values are separated by a hash as hash # is unlikely to come into the search query.
index = index + item[attr] + "#";
}
}
// Insert the index property into the object.
// Also notice the toLowerCase that allows for case insenstive searches later on.
item.index = index.toLowerCase();
}
}
console.log("Prepared data:" ,data);
// Filter process.
var key = "Sn";
var keyLowerCase = key.toLowerCase();
// Iterate over the objects and compare the index prpoerty to match with the search string.
var filteredData = [];
for(var prop in data) {
if(data.hasOwnProperty(prop)) {
var item = data[prop];
if(item.index.indexOf(keyLowerCase) >= 0 ){
filteredData.push(item);
}
}
}
console.log("Filtered data:", filteredData);

Using concatenation and a passed parameter to loop through an array

var Animals = {
"Europe": { "weasel.jpg": "squeak", "cow.jpg": "moo"},
"Africa": { "lion.jpg": "roar", "gazelle.jpg": "bark"},
};
function region(a){
var b = "Animals."+a;
for(var index in b) {
var target = document.getElementById('div1');
var newnode = document.createElement('img');
newnode.src = index;
target.appendChild(newnode)
}
}
RELEVANT HTML
<li onclick="europe('Europe')">Europe</li>
Goal: on the click of the Europe <li>, pass the word Europe into my region function where it is then concatenated to produce Animals.Europe
This is in order to identify an array within the object structure at the top using the for(var index in Animals.Europe) loop. Why is the concatenation which produces Animals.Europe not treated in the same way as if I had typed this out?
In addition, you can see that I have used arrays to store an image source and description for different animals. Using my limited coding knowledge this was all I could think of. Is there an easier way to store image/description data in order to produce in HTML?
"Animals." + a is just a string value, e.g. "Animals.Europe", which is not the same thing as Animals.Europe. If you change the first line to var b = Animals[a];, you should be all set.
Edit: and as elclanrs pointed out, it should be region('Europe'), not europe('Europe').
Why is the concatenation which produces Animals.Europe not treated in the same way as if i had typed this out?
In this case the variable b is just a string ("Animals.Europe"), which is treated like any other string (i.e. a list of characters). This means that when you attempt to loop through it (for(index in b)) you will be looping over a simple list of characters.
What you can do instead is use the square brace notation of accessing an objects properties. This means you can instead write var b = Animals[a], retrieving attribute a from Animals. You can read more about working with objects in this way on this MDN page
You can access the europe property using the following
Animals[a]
Also you're calling a "europe" function when you should be calling "region"
You're not storing animals in arrays here, but in objects with the image names as keys. Usually you'll want to use relevant names as keys. For example if you want arrays of animals for each continent
var Animals = {
"Europe": [{
imageSrc: "weasel.jpg",
cry: "squeak"
},{
imageSrc: "cow.jpg",
cry: "moo"
}],
"Africa": [{
imageSrc: "lion.jpg",
cry: "roar"
},{
imageSrc: "gazelle.jpg",
cry: "bark"
}]
};
Now Animals['Europe'] gives an array of objects, where you could eventually store other properties. So if b is an array your loop will now look like:
var b = Animals['Europe'];
for(var i=0; i < b.length; i++) {
var target = document.getElementById('div1');
var newnode = document.createElement('img');
var animalData = b[i]; // The array item is now an object
newnode.src = animalData.imageSrc;
target.appendChild(newnode)
}

Categories