I'm writing code where there will be several actions in an array.
var randomStringsWriting = [
'Write about ' + randomObjectsPlural,
'Think about ' + randomObjectsPlural,
'Love ' + randomObjectsPlural
the "randomObjectsPlural" variable is another array with nouns
var randomObjectsPluralList = [
'cats',
'dogs',
'people',
]
In order to make it easier for me to write one variable instead of an equation, I set this initially (Note that THIS is the variable in the initial array, and not "randomObjectsPluralList")
var randomObjectsPlural = randomObjectsPluralList[0]
I would like the text to update whenever I click, so I wrote this function:
$("#screen" ).click(function(){
randomObjectsPlural = randomObjectsPluralList[Math.floor(Math.random()*randomObjectsPluralList.length)];
});
Oddly, when I click to randomize, the same "randomObjectsPlural" variable is kept, despite the click to randomize. For example, the screen would eventually display...
Write about cats
Think about cats
Love cats
...when I would want something more like
Write about cats
Think about people
Love dogs
The only way that the noun would change is if I refreshed the page. What exactly is happening here?
I'm not sure how you have wired all this up but when you click you have to randomise each item again and again.
What you have shown so far would indicate that you only set the randomStringsWriting array ones at the start, hence you only update it ones at page load.
You are also setting each item to randomObjectsPlural but it seems you are only setting the variable up ones. You would need to randomise a new randomObjectsPlural for each one.
Again, as I have no idea how you have actually wired it all up below is a demo to achieve what you are looking for.
The below is an example. You still will need to take the logic and adapt it into your own implementation.
Assuming the following HTML:
<button id="screen">Click</button>
<div id="output"></div>
The following JavaScript would do the trick:
var getRandomListItem = function () {
return randomObjectsPluralList[Math.floor(Math.random() * randomObjectsPluralList.length)]
};
var randomObjectsPluralList = [
'cats',
'dogs',
'people']
$("#screen").click(function () {
var randomStringsWriting = [
'Write about ' + getRandomListItem(),
'Think about ' + getRandomListItem(),
'Love ' + getRandomListItem()]
$('#output').html(randomStringsWriting.join('<br />'));
});
DEMO - Randomizing the string values
As you are only picking a random value out of a possible 3 it is very likely off course that you still get all 3 random values to be the same.
If you want random + different then you also need to keep track of each value which already has been selected until all have been picked, then re-set the tracker but that is a slightly more involved process.
Related
I am trying to build a logic where we click a button and save an ID in localStorage. We could have 2 ids max. However, we can also remove an ID from it and add a new one. Finally, we cannot add more than 2 and these ids must be unique. These IDs will be then set as an input value in a form.
So I have four steps page:
Homepage page
Search result page
Single article page
Form result page
Each page has:
<form id="post_form_id" method="post" action="/test/compare/">
<input id="input_post_id" type="hidden" name="varPostId" value="">
<button type="submit" class="btn btn-link nav-link" id="jikubox"></i>
<span class="badge badge-secondary">0</span></button>
</form>
Saved IDs will be set in name="varPostId" value=""
Now the tricky part which is confusing me, so localStorage can only have strings so first of all on each page load I do:
var lines = localStorage.getItem("lines") ?
JSON.parse(localStorage.getItem("lines")) : [];
Then since in the article page I have a save button to add the current article id in the array, I do:
<button type="button" class="save_post">SAVE</button>
JS
$(".save_post").on("click", function(e) {
e.stopImmediatePropagation();
if (localStorage.getItem("attempts") >= 2) {
alert('nope');
return;
} else {
// Here I set the id for each article which I saved before via php in a span
var thisId = $(".my_post_id").attr("data-id");
var lines = localStorage.getItem("lines") ? JSON.parse(localStorage.getItem("lines")) : [];
lines.push(thisId);
localStorage.setItem("lines", JSON.stringify(lines));
console.log(lines);
$("#input_post_id").val(JSON.parse(localStorage.getItem("lines")));
var attempts = Number(localStorage.getItem("attempts"));
localStorage.setItem("attempts", ++attempts);
console.log(localStorage.getItem("attempts"));
$("#jikubox span").text(localStorage.getItem("attempts"));
}
});
Notice I have another localStorage: attempts, that is used to add or remove a number I set in a counter badge, basically an indicator which tells how many items I have in my "bag". Remember: max 2 and unique.
So finally on the form result page I have a button to remove added items and the following js is used:
$(".removeJiku").on("click", function(){
// Here I set the id for each article, I do that with php
// <span class="removeId" data-thisPostId="<?php echo $idThisPost; ?>"></span>
var removeThisId = $(".removeId").attr("data-thisPostId");
$(this).parent().fadeOut();
var attempts = Number(localStorage.getItem("attempts"));
localStorage.setItem("attempts", --attempts);
$("#jikubox span").text(localStorage.getItem("attempts"));
lines.splice($.inArray(removeThisId, lines), 1);
localStorage.getItem("lines", lines);
localStorage.setItem("lines", lines);
console.log(localStorage.getItem("lines"));
});
The logic is kinda ok but after I try few times, I eventually get empty lines array and the ids are not set to the input value. I think I over complicated the logic and I was wondering where and how I could simplify and correct it. I am looking into a single general bit of code which handles all of this without complicating the logic.
UPDATE
Thanks to an answer, one bit of code has been simplified and the counter will be set by checking the length of the ids in lines array so We can remove the whole code for the attempts local storage logic
$("#jikubox span").text(lines.length);
Assume you store your IDs in an array-
var idList=["123","456"];
You can store IDs like this -
localStorage.setItem("idList",JSON.stringify(idList));
and fetch idList like this-
JSON.parse(localStorage.getItem("idList")).length
Just make sure to put validations all around.
P.S. No need to count the "attempts" as you can anytime use the below code to find the length of the idList, which can be 2 or any number you want
JSON.parse(localStorage.getItem("idList")).length
UPDATE:
To remove IDs-
function removeId(array, element) {
const index = array.indexOf(element);
array.splice(index, 1);
}
Fetch array from localStorage and pass it into this function -
idList = JSON.parse(localStorage.getItem("idList"))
and call the function like this -
removeId(idList,idToBeDeleted)
This block isn't doing what you want:
lines.splice($.inArray(removeThisId, lines), 1);
localStorage.getItem("lines", lines);
localStorage.setItem("lines", lines);
The second line is getting something from localStorage but isn't doing anything with it. It could be the equivalent of
lines.splice($.inArray(removeThisId, lines), 1);
['one line', 'another line'];
localStorage.setItem("lines", lines);
Just some random value that proceeds to get ignored by the interpreter.
The other problem is that you're setting localStorage.lines to the plain lines variable, not to JSON.stringify(lines).
Note that you can simplify your syntax noise just by doing
localStorage.lines = JSON.stringify(lines);
and
const lines = JSON.parse(localStorage.lines || '[]');
localStorage.getItem('item') only accepts one parameter, which will return the value if it exists in the local storage and will return null item doesn't exist.
localStorage.setItem(item, value) accepts two parameters. item which is a key and the value which is to be saved for the key. If item is already set it will overwrite the value.
I am working on a project where I need to contain a lot of functions within an object so that I can access them with variables that combine in different ways to access different ones. I haven't written this in my main project yet, just tested it as a method and I'll put that test code below to hopefully better explain what I'm talking about. There will be a lot of functions in this object, and the aim is to have one of them randomly run when a button is pressed.
A key part of what I'm trying to make is that the user can exclude whichever functions they want from being randomly selected, and this is what is causing me some problems. I read through a lot of solutions for other problems, but all of them are just a little off (or at least I don't know how to apply them to this just yet). The first thing I tried was using an array and, depending on what option the user ticks, excluding or adding items to it and then randomly selecting from within that to get the random number, but I'm worried that an array of around 300 items would just slow things down or cause more problems than is really useful so I stepped away from this. I looked up how I could exclude numbers from the random generation too, but this tended to use for loops and only worked for a few numbers being excluded - after that I imagine that would cause problems too. I looked into excluding ranges of numbers from random generation as well, but the items that users exclude aren't guaranteed to be next to each other in the object, so that causes problems.
The plan in my head was to add a number at the end of the object key; the random number generator would choose from all non-excluded numbers (exclusion based on other parts of the key, such as excluding all 'salad' options in the test below), and then that number, along with the two or three other variables that make up the key bring us to an actual thing. So, in the theme of the below, "bacon" + "burger" + "lettuce" + "17" might be chosen based on the options the user chooses and the random number respectively and might lead to the 17th baconburgerlettuce based alert - I'm not making some kind of food shouting app, by the way, this really is just a demo...
This is... Hopefully less complicated than it sounds. I imagine I have explained it awfully, so if I can even just clarify something please let me know. Alternatively, if nesting functions inside an object for this purpose is straight up dumb, tell me! I want to learn the best way of doing things, rather than fumble through something ugly and inelegant!
var food;
var type;
var func = {
cheeseburger: function() {alert("This is CHEESE BURGER");},
baconburger: function() {alert("BACON BURGER reigns supreme!");},
cheesesalad: function() {alert("CHEESE SALAD hahahaha");},
baconsalad: function() {alert("BACON SALAD! That's right!");}
};
$(".cheese").click(function() {
food = "cheese";
$(".test").html(food);
});
$(".bacon").click(function() {
food = "bacon";
$(".test").html(food);
});
$(".burger").click(function() {
type = "burger";
$(".test2").html(type);
});
$(".salad").click(function() {
type = "salad";
$(".test2").html(type);
});
$(".go").click(function() {
func [food + type]();
});
const funcs = [
v => alert(v),
v => console.log(v),
v => alert( v + 1)
];
const excluded = new Set();
//to exclude a function
excluded.add(2);
function random(...args){
do {
var i = Math.floor( Math.random() * funcs.length );
} while( excluded.has( i ) );
funcs[i](...args);
}
//test it
random("test");
First of all you need some property to enable or disable functions.
var func = {
cheeseburger: {f: function() {...}, enabled: true},
baconburger: {f: function() {...}, enabled: true},
cheesesalad: {f: function() {...}, enabled: true},
baconsalad: {f: function() {...}, enabled: true},
...
};
Then a function to pick random one ignoring disabled ones.
Here arises first problem: If you just randomly pick one until you find one
which is not disabled, as the amount of disabled ones grows, the it will take
longer to find enabled one.
The easier solution is to use a cache like:
var cache;
function updateCache(){ // Using function we can update it when needed.
cache = Object.keys(func).filter(k=>func[k].enabled);
};
updateCache();
Then you need enable / disable methods too:
function enable(fn) {
func[fn].enabled = true;
updateCache();
};
function disable(fn) {
func[fn].enabled = false;
updateCache();
};
And, finally you just need to pick function keys from the cache:
function callRandomFn(){
var k = Math.floor(Math.random() * cache.length);
return fn[cache[k]]();
};
I've modified a survey-multi-choice plugin from JsPsych, in order to get responses in the form of checkboxes, instead of radio-buttons, since I need to present an image to the user, followed by 4 alternatives, like this:
Where A, B, C and D are also images, with their respective checkbox below each one. This structure must be presented more than once, like this:
So in this example, the expected output would be:
{"Q0":["Option A","Option B"]} //this is the first "question" displayed
{"Q1":["Option B","Option C"]} //second one
{"Q2":["Option B","Option D"]} //third one
But instead I get the first answer replicated for the rest of the questions:
{"Q0":["Option A","Option B"]} //this is the first "question" displayed
{"Q1":["Option A","Option B"]} //second one
{"Q2":["Option A","Option B"]} //third one
My code is provided below:
$("div." + plugin_id_name + "-question").each(function(index) {
var id = "Q" + index;
var val = [];
var a = $(".jspsych-survey-multi-choicemrbeta-option");
$("input:checkbox:checked").each(function(){
val.push($(this).attr("value"));
});
var obje = {};
obje[id] = val;
$.extend(question_data, obje);
});
I've tried tracking down the values generated on each step by printing them on console, so I'm guessing the problem is how I'm implementing those nested loops, thus the name of this question.
I've tried different approaches when implementing this loop, without better results:
for (var j = 0; j < trial.options[index].length; j++) {
if ($('jspsych-survey-multi-choicemrbeta-response-' + j).is(':checked')) {
val.push($(this).attr("value"));
}
}
A working example of my full code can be found here, for you to test it (look for the jspsych-survey-multi-choicemrbeta.js file, from line #141). CSS isn't included so it'll look slightly different.
Please note that the output of this code is a CSV file, and the full set of responses is given on a single cell, since all those questions belongs to the same JsPsych "trial".
Thanks for your help.
The inner loop iterates over all checkboxes, not only the ones belonging to the question.
Assuming the checkboxes are descendants of the div for the associated question, you should change the inner loop from this:
$("input:checkbox:checked").each( ...
to this:
$(this).find("input:checkbox:checked").each( ...
var reset = function ()
{
var p = parseFloat($("#IA").val());
var q = parseFloat($("#IB").val());
var m = parseFloat($("#CGCD").val());
var aR = [];
aR += ["GCD(" + p + "," + q + ")=" + m];
document.getElementById("PGCD").innerHTML = aR + "\n";
document.getElementById("IA-error").innerHTML="";
document.getElementById("IB-error").innerHTML="";
$("#IA").focus();
};
The code above is only for a 'reset' function, a part of additional code (not present), the purpose which is to find the Greatest Common Denominator, GCD.
My 'reset' function is connected to a button, #reset, the purpose of which is to do four things:
add and store the string GCD(p,q)=m to the array 'aR'; p/q/m are variable stand-ins for the values of the input text areas #IA, #IB, and #CGCD (the GCD of #IA and #IB);
display the array 'aR' in a text-area #PGCD each time the reset button is clicked; this is why I used an array;
clear the two input text areas #IA and #IB;
clear the one output text area;
As it stands, all four objectives are completed successfully, with one exception: for the second objective, only the most recent GCD calculation is outputted; none of the previous calculations output.
I cannot get the array to list the different saved calculations within it. I think (?) the new calculations are being added to the array, but I am not sure.
I've tried a 'for' statement, and an 'if' statement, neither of which worked. I don't know whether I coded it wrong, or if it wasn't the right solution for my issue.
I tried to search the forums (here) for a solution, but was unable to find one.
Thank you.
If I'm understanding what you are describing, I believe your problem is that you are attempting to use += to add elements to an array. You should use
aR.push("GCD(" + p + "," + q + ")=" + m);
The += operator is used for addition of a value to itself as well as string concatenation.
Edit: per comments below, the main issue was declaration of aR as a local variable. It needs to be either global or declared within the same scope.
I have the following code.
var stackMapIn = [];
var stackMapOut = [];
var stackBack = [];
stackMapOut.push("m1");
$scope.clickLinks = function(initialOut,initialIn,extra,backIn,backOut,name){
$('div#'+initialOut+'Map,'+extra).fadeOut('slow',function(){
$('.'+initialOut+'Details,.bkbtn'+backOut).css("display","none");
$('.'+initialIn+'Details,.bkbtn'+backIn).css("display","block");
$('.noQuery').css("display","none");
$("#buildingHeader").html(name);
$('div#'+initialIn+'Map').fadeIn('slow');
})
stackMapOut.push(initialIn);
stackMapIn.push(initialOut);
stackBack.push(backIn);
}
$scope.clickBack = function(bkbtnCheck){
alert(stackBack[0]);
mapOut = stackMapOut.pop();
mapIn = stackMapIn.pop();
stackBack.pop();
backIn = stackBack[0];
alert(backIn);
$('div#'+mapOut+'Map').fadeOut('slow',function(){
$('.'+ mapOut + 'Details,.bkbtn').css("display", "none");
$('.' + mapIn + 'Details,.bkbtn'+backIn).css("display", "block");
$(".noQuery").css("display","none");
$("#buildingHeader").html("Name");
$('div#' + mapIn + 'Map').fadeIn('slow');
})
}
Now I am going to do a quick run-through of what happens as this code runs.
The first time clickLinks runs:
initialIn = 'm2'
initialOut = 'm1'
backIn = 'Home'
clickBack has not run yet.
The second time clickLinks runs:
initialIn = 'm7'
initialOut = 'm2'
backIn = 'CentralPortfolio'
Ok so at this point things should be looking like this (I expect):
stackMapOut = ['m1','m2','m7']
stackMapIn = ['m1','m2']
stackback = ['Home','CentralPortfolio']
Now we run clickBack... Why does the alert output "Home"??
What I am trying to do here is, I have a series of things appearing and disappearing when clickLinks runs. Sometimes, the user can run clickBack in order to return to the previous state(status). So, I am using JavaScript stack to keep track of what state it is on and thus where it needs to return.
The problem is, I can run clickLinks once, clickBack once consecutively without issue. I can even run clickLinks a second time and still click the back button 2 times (to return to start) without issue. But I still don't understand why stackBack[0] (which should be the top of the stack ?) = "Home" at this point instead of "CentralPortfolio".
Because the real problem that I run into is now if I run clickLinks a third time: still stackBack[0] = 'Home' (when I expect it to be 'CentralCampus' at this point) and thus, it is the "Home" back button that is showing (while the correct other stuff is showing in accordance to mapOut and mapIn) instead of CentralPortfolio' back button to be showing; since I have 'CentralCampus' "popped" off before I use it.
Please, if any other information is needed or you need more clarification let me know. I tried my best to provide any needed information and make it as clear as possible.
Now we run clickBack... Why does the alert output "Home"??`
because stackBack[0] is Home. What would you expect it to do? You even have it in your question:
stackback = ['Home','CentralPortfolio']
The index 0 is the first element in your array, which is Home. The last element is stackBack[stackBack.length - 1]
using JavaScript stack
No, you are using a javascript array, but using it like a stack. Except when you index it like an array - which is the root of your confusion. You can use it as a stack with pop and push, but then don't try and index it with []
When you push on an array, you add an element to the end of the array. In other words, it ends up as the last element at the index yourArray.length - 1. When you pop, you take that last element off the array again. So popping stackback would give you back CentralPortfolio, and, of course, the first element is unchanged.