Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
I am currently working on a Worlde clone written in JavaScript. I used the rapid API to fetch the five letter word in a function called getWord.
I also used a function called onceADay so the getWord function only gets called once. At the end of the onceAday function, I call location.reload(), so once a new word has been loaded, the website should refresh itself, hence you can start the game again. My problem is that the reload page function runs so quickly that it doesn’t let the fetch get a new word. I tried async/await but it did not work. I also tried to delay to refresh.. but it doesn't work reliably. I also tried to save the last word in a localObject and implement a while loop in the onceADay function.. so while the previousword is equal to current word it should repeat the fetch. but it just crashed the whole site. At this point I am clueless about how I could fix it. I just run out of options here. I am quite new to JavaScript, so I am hoping maybe someone who has more experience could give me a solution. I got the whole project on my git repo ( https://github.com/dodoo86/WordleJS )
Also, here’s the functions I mentioned above.
This is how I fetch the word using async await
async function fetchWordJSON() {
const response = await fetch('https://squirrelle.onrender.com/word');
const word = await response.json();
return word;
}
Than I check if a day passed
function hasOneDayPassed() {
var date = new Date().toLocaleDateString();
if (localStorage.yourapp_date == date)
return false;
localStorage.yourapp_date = date;
return true;
}
Than if so, it should run the following things once a day
function runOncePerDay() {
if (!hasOneDayPassed()) return false;
fetchWordJSON().then(word => {
word;
localStorage.setItem("wor", word)
});
console.log("Word ", localStorage.getItem("wor"));
localStorage.setItem("Won", "false");
wordle = localStorage.getItem("wor").toUpperCase();
console.log("WordUPSCALE ", wordle);
checkLastWinDates();
localStorage.setItem("gamePlayed", "false");
location.reload();
}
In this way it refreshes the site before it could fetch, so the word remains the same when i set the clock to a next day. If I do the reset with a delay, it works quite unreliably. I added 2000 minisec delay and if the backend is a bit slower then usual it doesn’t refresh the word if its quicker it does. So I would need a bulletproof method to make sure the word always refresh before the page.
You should put the reload inside the then block, so it will be executed after fetching.
function runOncePerDay() {
if (!hasOneDayPassed()) return false;
fetchWordJSON().then(word => {
word;
localStorage.setItem("wor", word);
console.log("Word ", localStorage.getItem("wor"));
localStorage.setItem("Won", "false");
wordle = localStorage.getItem("wor").toUpperCase();
console.log("WordUPSCALE ", wordle);
checkLastWinDates();
localStorage.setItem("gamePlayed", "false");
location.reload();
});
}
Promises run asynchronously. In your code here:
function runOncePerDay() {
...
fetchWordJSON().then(word => {
word;
localStorage.setItem("wor", word)
});
...
location.reload();
}
The callback passed to .then() is waiting on the fetch, but the execution in the rest of the runOncePerDay function continues, and location.reload() gets called, thus reloading the page before the fetch has complete. (It's a race condition)
To fix this, put the location.reload() after the logic in the .then() callback. So everything in your localStorage gets set before the reload happens.
Related
I have a pop up prompt asking for a users year group, as I have databases for each year group I would like to call a function after the value of userInfo changed to true.
My JS knowledge is quite elementary and I have only dealt with async calls and promises in the contexts of API fetching. What I have right now is.
example:
onMount(async function check() {
// check if user has entered thieir information
if ($userInfo) {
getYearGroupSchedule($yeargroup, weekdates);
} else {
// await for userinfo to be true
}
});
I don't know if this the right way to approach it but I am very lost and would like some help please. If there is any clarifying questions needed please comment bellow.
Logic in onMount is only executed once. If you want to wait for a condition, you probably would want to use a reactive statement:
$: if ($userInfo) {
getYearGroupSchedule($yeargroup, weekdates);
}
This will get checked and executed whenever a dependency changes, note that this will take all used variables into account (in this case including $yeargroup and weekdates). If you only want to trigger on a specific condition, call a function and thus "hide" the other variables. E.g.
$: if ($userInfo) update();
I am working on a E2E test for a single-page web application in Angular2.
There are lots of clickable tags (not redirected to other pages but has some css effect when clicking) on the page, with some logic between them. What I am trying to do is,
randomly click a tag,
check to see the the response from the page is correct or not (need to grab many components from the web to do this),
then unclick it.
I set two const as totalRound and ITER, which I would load the webpage totalRound times, then within each loading page, I would randomly choose and click button ITER times.
My code structure is like:
let totalRound: number = 10;
let ITER: number = 100;
describe('XX Test', () => {
let page: AppPage;
beforeEach(() => {
page = new AppPage();
});
describe('Simulate User\'s Click & Unclick',() => {
for(let round = 0; round < totalRound; round++){
it('Click Simulation Round ' + round, () =>{
page.navigateTo('');
let allTagFinder = element.all(by.css('someCSS'));
allTagFinder.getText().then(function(tags){
let isMatched: boolean = True;
let innerTurn = 0;
for(let i = 0; i < ITER; i++){
/* Randomly select a button from allTagFinder,
using async func. eg. getText() to get more info
about the page, then check if the logic is correct or not.
If not correct, set isMatchTemp, a local variable to False*/
isMatched = isMatched && isMatchTemp;
innerTurn += 1;
if(innerTurn == ITER - 1){
expect(isMatched).toEqual(true);
}
}
});
});
}
});
});
I want to get a result after every ITER button checks from a loading page. Inside the for loop, the code is nested for async functions like getText(), etc..
In most time, the code performs correctly (looks the button checkings are in sequential). But still sometimes, it seems 2 iterations' information were conflicted. I guess there is some problem with my code structure for the async.
I thought JS is single-thread. (didn't take OS, correct me if wrong) So in the for loop, after all async. function finish initialization, all nested async. function (one for each loop) still has to run one by one, as what I wish? So in the most, the code still perform as what I hope?
I tried to add a lock in the for loop,
like:
while(i > innerTurn){
;
}
I wish this could force the loop to be run sequentially. So for the async. func from index 1 to ITER-1, it has to wait the first async. finish its work and increment the innerTurn by 1. But it just cannot even get the first async. (i=0) back...
Finally I used promise to solve the problem.
Basically, I put every small sync/async function into separate promises then use chaining to make sure the later function will only be called after the previous was resolved.
For the ITER for loop problem, I used a recursion plus promise approach:
var clickTest = function(prefix, numLeft, ITER, tagList, tagGsLen){
if(numLeft == 0){
return Promise.resolve();
}
return singleClickTest(prefix, numLeft, ITER, tagList, tagGsLen).then(function(){
clickTest(prefix, numLeft - 1, ITER, tagList, tagGsLen);
}).catch((hasError) => { expect(hasError).toEqual(false); });
}
So, each single clicking test will return a resolve signal when finished. Only then, the next round will be run, and the numLeft will decrease by 1. The whole test will end when numLeft gets to 0.
Also, I tried to use Python to rewrite the whole program. It seems the code can run in sequential easily. I didn't met the problems in Protractor and everything works for my first try. The application I need to test has a relatively simple logic so native Selenium seemed to be a better choice for me since it does not require to run with Frond-end code(just visit the webapp url and grab data and do process) and I am more confident with Python.
Some of the scripts that I run take a long time and users might get concerned that a script stopped working if they can't see the status/step. I have added a spinner to the Sidebar to at least indicate that the script started running, but I would like to do more than that.
Ideally, I would be able to directly update the Sidebar contents from the GAS, but I gather than is not possible because of sandboxing. I have seen other questions and answers that discuss using success handlers in a daisy chain like this:
function uploadActivities(){
google.script.run.withSuccessHandler(onSuccess).activities_upload();
}
function onSuccess(lastStatus){
$('#codestatus').text(lastStatus);
google.script.run.step_two();
}
It is a hack and it would require me to split the code into smaller steps and pass values to the UI, which don't belong in the UI, and back to the code. I really don't like that approach and maintenance could be a bear.
I have tried creating a var in GAS and updating that value as the code progresses. However, I can't find a way to get the UI to periodically check until the code execution is complete AND to successfully update the UI after each step.
Here is the code I have created:
function uploadActivities(){
google.script.run.activities_upload();
getStatus();
}
function getStatus(){
var isActive = true;
while(isActive){
var lastStatus = google.script.run.getStatus();
$('#codestatus').text(lastStatus);
if(lastStatus === 'Complete'){ isActive = false; }
}
}
In GAS I use this code:
var codeStatus = 'start';
function getStatus(){
return codeStatus;
}
function activities_upload(){
codeStatus = 'Started Execution';
...
codeStatus = 'Extracting Values';
...
codeStatus = 'Uploading Activities';
...
codeStatus = 'Complete';
}
It runs the required code, and even updates the #codestatus div with the first value, but it doesn't get any values beyond the first value. Additionally, it creates a continuous loop if there is an error in the code execution, so that isn't good either.
Is there a good, efficient, and safe way to complete this approach? Or, is there a better way to notify the user of the code execution status so they don't get worried if it takes a while, and can tell if there has been an issue?
I have struggled with this for some time. Unfortunately, I don't have a good fix for your approach, but I can show what I finally did and it seems to be working.
First, create an easy way to send a toast to your users.
function updateStatus_(alert,title){
var ui = SpreadsheetApp.getActiveSpreadsheet();
var title_ = title!=""?title:"";
ui.toast(alert,title_);
}
Second, as required, use the toast to update the user.
function activities_upload(){
updateStatus_('Started Execution');
...
updateStatus_('Extracting Values');
...
updateStatus_('Uploading Activities');
...
updateStatus_('Complete');
}
This will alert the user with a temporary message as the code progresses and not require the user to clear an alert.
Please note that if the steps progress rapidly the user will see the toast flash on the screen only to be quickly replaced by the next toast. So, make sure you don't have too many throughout your execution.
I use hack.chat a bit, and I saw that they have a bot, but the bot program wasn't working for me so I decided to make my own.
var finderBinder;
var searchFor = function(command){
finderBinder = window.find(command, true, true);
if(finderBinder){
if(command === "/hello"){
ws.send(JSON.stringify({cmd: "chat", text: "hello!"}));
}
else if(command === "/cry"){
ws.send(JSON.stringify({cmd: "chat", text: "wah waha wahhh"}));
}
else
{
console.log("it was found but it was not a command.")
}
}
else
{
console.log("Did not find the command");
}
}
var loopdeloop = 0;
while(loopdeloop === 0){
searchFor("/hello");
searchFor("/cry");
}
Now, the first part works if I just run that by itself on the page, and enter searchFor("/hello"); that would work, but if I wanted it to just automatically do that whenever a message popped up, I attempted the loop,(In a empty chatroom so it wouldn't spam a used room if it did) and it crashed my browser. I know why it did that. because it just checked forever, and it saw it forever so it kept on trying to do the code forever..
But how would I make it only run the searchFor when a new text showed up so it would run the text in it and if it was a command it would do the command? Or is there a better way to do this?
The simplest way to stop your function from looping to infinity (and beyond!) would be to call it once every X seconds/minutes/hours/lightyears.
Using setInterval(searchFor, 1000); where the second parameter is the time interval in milliseconds.
To pass a parameter to your searchFor function, you must create an anonymous function so it doesn't get called right away.
setInterval( function() { searchFor ("/hello"); }, 1000 );
This will call your function every ~1 second, although keep in mind there is some overhead to javascript and there will be a slight delay. Also be careful of looping your function too often, as it will be expensive, and browsers have a built in delay, for example, you will not be able to setInterval to 2 ms and have it function normally cross browser.
Edit: The more elegant solution of binding an event to a change in the textbox is also possible, depending on how the page is setup and your access to it, hard to answer without that structure known.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I want return the var "Page" in a Jquery function :
var Page ;
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
return Page = 'Crea_Bouton';
});
alert(Page); //does not work
But its does not work.
The goal is not to make an alert of the var Page.
In a other page i have : if(Page == 'Crea_Bouton') { //Action }
So, Page must be a global var
Can you help me, please?
There's several issues here. First of all, Page and page are two different variables, but let's assume you've named them the same - your code still won't work.
The problem is, your event handler is not run immediately, it's only run when the double click occurs. Defining page outside of the event doesn't make any sense in this context. What happens is it hits var page; first, then it registers an event (but DOES NOT run the event function), then alerts an empty variable (because the event has not been triggered yet).
When you do trigger the dblclick event, that alert doesn't get executed.
Try this:
var page;
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
page = 'Crea_Bouton';
});
$('#anotherdiv').click(function(){
if(page === 'Crea_Bouton'){
alert("yep!");
}else{
alert("Something else")
}
})
Now, when your #anotherdiv is clicked, it will only alert 'yep!' if the original Montant div has been double clicked first. Otherwise it'll do something else (or nothing at all if you omit the else).
Here's an example jsfiddle:
http://jsfiddle.net/Wb9Ba/
If you click the second button right away, it says "Something else", but if you double click the first button, and then click the second button, it says "yep!"
Use a "callback" function as jQuery does:
function onReturn(page) {
// Process your returned value
if (page == 'Crea_Bouton') {
// Action
alert(page);
}
}
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
var page = 'Crea_Bouton';
onReturn(page);
});
Or process your value inside the dblclick callback:
$('#Montant').dblclick(function(){
$("#Encadrement_Encaissement_Menu_Creation").show();
var page = 'Crea_Bouton';
// Do something with my page
if (page == 'Crea_Bouton') {
// Action
alert(page);
}
});
Since the anonymous method inside dblclick is asynchronous, it's impossible to return something.
Instead, you may create a new function:
var page;
$('#Montant').dblclick(function () {
$("#Encadrement_Encaissement_Menu_Creation").show();
display('Crea_Bouton');
});
function display(page) {
alert(page);
// ...
}