How to run function after another object reaches certain state - javascript

I have a game. I have 3 files app.js, game.js, modal.js.
The Modal sets an event listener on the 'next' button of the modal, and keeps track of 'currentStep'. That is, the modal has multiple steps. Now, I want in the app.js file to start the game, only after the user has completed the modal. In my modal I have :
constructor(){
this.currentStep = 0;
}
complete() {
return (this.currentStep >= 4 ? true : false);
}
activate() {
....
nextButton.addEventListener( 'click' , (e) => {
if (this.currentStep === 0) {
firstInstructions.classList.add('hideMe');
firstGif.classList.remove("hideMe");
....
}else if (this.currentStep === 4) {
modal.classList.add("hideMe");
}
this.currentStep++;
});
}
Now, the basic point is that I somehow want to let my app.js know when the user has completed the Modal so that I can run game.play();
So something like :
const game = new Game();
const modal = new Modal();
modal.activate();
// game.play() WHEN modal.complete
Can someone suggest the proper way for the Modal to let the App know that it is complete, whenever that happens. I know I can use a while loop and keep checking if modal.complete() and when it is run game.play() but that seems wrong.
Thanks.

I can think of two ways, one is you can just add in the activate the game itself like this.
const game = new Game();
const modal = new Modal();
modal.activate(game);
Then in the activate you can do this:
activate (game) {
....
nextButton.addEventListener( 'click' , (e) => {
if (this.currentStep === 0) {
firstInstructions.classList.add('hideMe');
firstGif.classList.remove("hideMe");
....
} else if (this.currentStep === 4) {
modal.classList.add("hideMe");
// Put it here
game.play();
}
this.currentStep++;
};
That is if the last modal step will start the game. But if you really want to put it in complete method. You can also do this
const game = new Game();
// put the game inside the Modal constructor
const modal = new Modal(game);
modal.activate();
Then you put the game in the constructor method
constructor (game) {
this.currentStep = 0;
// put it here
this._game = game;
}
Then in the complete method you can just invoke play from the game
complete () {
this._game.play();
return (this.currentStep >= 4 ? true : false);
}
Hope this helps

Related

Pop up removed completly from DOM

I have created the below function that uses bootstrapalert where a pop up comes up that holds random data from a database table. But after I trigger the event and close the window I need to refresh the page in order for it to work again. I don't seem to find the issue in the code that causes this problem. Any suggestions for improvement?
<script>
var alertList = document.querySelectorAll(".alert");
alertList.forEach(function (alert) {
new bootstrap.Alert(alert);
});
function randomName() {
if (
document.getElementById("randomNamePopUp").dataset.showned == "false"
) {
document.getElementById("randomNamePopUp").style.display = "block";
document.getElementById("randomNamePopUp").dataset.showned = "true";
} else {
//window.location.href=window.location.href+"?showRandom=true";
}
}
const urlParams1 = new URLSearchParams(window.location.search);
const myParam = urlParams1.get("showRandom");
if (myParam == "true") {
randomName();
}
</script>

this.router.routeReuseStrategy.shouldReuseRoute = () => false;

this.router.routeReuseStrategy.shouldReuseRoute = () => false;
I have applied this sort of line in order to make the component UI updated everytime. But in some other cases it start to refreshing the page event if it should reuse the route.
How can we overcome this issue?
Actually in my application there are three tabs in left panel. In each tab there are some listings clicking on list items opens the content on right panel. But in one of the listing there is a common UI that is getting open on some list item, but the problem is that when we don't apply above sort of code then the UI is not getting updated. But if we apply the code then the UI is updated everytime we click on other list item. But the problem is that when we apply this code it start to refresh the page everytime we click on other list in different tabs also, that should not be the case.
If we apply this code this.router.routeReuseStrategy.shouldReuseRoute = () => false; then how can we revert this functionality under this.router?
To take less risks I'm just reverting it back to what it was once the reload is done:
refresh() {
const prev = this.router.routeReuseStrategy.shouldReuseRoute;
const prevOSN = this.router.onSameUrlNavigation;
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
this.router.onSameUrlNavigation = 'reload';
this.router.navigate([this.router.url]);
setTimeout(() => {
this.router.routeReuseStrategy.shouldReuseRoute = prev;
this.router.onSameUrlNavigation = prevOSN;
}, 0);
}
I have the same issue, I changed that line for this:
// override the route reuse strategy
this.router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
this.router.events.subscribe((evt) => {
if (evt instanceof NavigationEnd) {
// trick the Router into believing it's last link wasn't previously loaded
this.router.navigated = false;
// if you need to scroll back to top, here is the right place
window.scrollTo(0, 0);
}
});
I don't even know if this works well or do the same thing.
private saveRouterStrategyReuseLogic: any;
ngOnInit() {
// Save logic
this.saveRouterStrategyReuseLogic = this.router.routeReuseStrategy.shouldReuseRoute;
this.router.routeReuseStrategy.shouldReuseRoute = (future, curr) => { return false; };
}
ngOnDestroy() {
this.router.routeReuseStrategy.shouldReuseRoute =
this.saveRouterStrategyReuseLogic;
}

How to fix problem with not working updateServing function in JavaScript?

I'm trying to implement a function which would calculate the servings for the ingredients from my website.
That function is in Recipe.js file and looks like that:
updateServings(type) {
// Servings
const newServings = type === 'dec' ? this.servings - 1 : this.servings + 1;
// Ingredients
this.ingredients.forEach((ingr) => {
ingr.count = this.capDecimal(ingr.count * (newServings / this.servings));
});
this.servings = newServings;
}
The problem is that when I console.log(state.recipe); in index.js this event Listener works, it will console log state.recipe after clicking - or + button on the website but it wont change the amount of serving in the recipe object:
elements.recipe.addEventListener('click', e => {
if(e.target.matches('.btn-decrease .btn-decrease *')){
//Decrease button is clicked
if(state.recipe.servings > 1){
state.recipe.updateServings('dec');
}
}else if(e.target.matches('.btn-increase .btn-increase *')){
//Increase button was clicked
state.recipe.updateServings('inc');
}
console.log(state.recipe);
});
I clicked 2 times but property serving still says 4 like here:
https://forum.toshitimes.com/uploads/toshitimes/original/2X/6/6bada9081879db1a14df9bad010382606fda253f.png
It a bigger project so I believe I need to include the whole repository from github: https://github.com/damianjnc/forkifyApp.git
What I need to change to make it work?
You need to update the view after the click event
elements.recipe.addEventListener('click', e => {
//....
try {
recipeView.clearRecipe();
recipeView.renderRecipe(state.recipe);
} catch (error) {
alert('error processing the recipe:(');
}
});
note: you need to declare your class properties
export default class Recipe {
ingredients;
servings;
constructor(id) {
this.id = id;
}
and you need map instead of forEach
this.ingredients = this.ingredients.map((ingr) => {
ingr.count = this.capDecimal(ingr.count * (newServings / this.servings));
return ingr;
});

How to make an audio file wait for the end of another one in order to start them together

I'm trying to build a basic sampler. I have 4 different audio files (1 guitar, 1 drum, 1 piano and 1 bass). The sound kit buttons programmed the way I want, but I cannot get the loops to work the way I want.
What i want to do is this :
if the user clicks on a button it launches the sample
if the user clicks again on the same button it stops the sample
and if the user clicks on another sample it waits for the end of the first sample and then start together
For now i manage to do the first and the second steps but i can't figure how to do the third one.
I tried to use Event Listener to know when a loop ends but i've never managed to make it work.
So my question is : is there an easy to do this third step ?
If you could give me a bit more detail when explaining, that would be great. Thanks!
Here what's my js look like so far :
$(document).ready(function() {
var basse = {
padOne: new Audio('basse2.mp3'),
};
var drum = {
padOne: new Audio('m1_drum1_85.mp3'),
};
var guitar = {
padOne: new Audio('m1_guitare1_85.mp3'),
};
var piano = {
padOne: new Audio('m1_piano_85.mp3'),
};
$('.pad-1').mousedown(function() {
if (basse.padOne.paused) {
basse.padOne.load()
basse.padOne.loop = true;
basse.padOne.play();
} else {
basse.padOne.pause();
basse.padOne.currentTime = 0
}
});
$('.pad-5').mousedown(function() {
if (drum.padOne.paused) {
drum.padOne.load()
drum.padOne.loop = true;
drum.padOne.play();
} else {
drum.padOne.pause();
drum.padOne.currentTime = 0
}
});
$('.pad-9').mousedown(function() {
if (guitar.padOne.paused) {
guitar.padOne.load()
guitar.padOne.loop = true ;
guitar.padOne.play();
} else {
guitar.padOne.pause();
guitar.padOne.currentTime = 0
}
});
$('.pad-13').mousedown(function() {
if (piano.padOne.paused) {
piano.padOne.load()
piano.padOne.loop = true ;
guitar.padOne.play();
} else {
piano.padOne.pause();
piano.padOne.currentTime = 0
}
});
});

WinJS listview iteminvokedHanlder how to

I'm using the iteminvokedHandler and was wonder if there is a better way to interact with the listView.
Currently using this:
WinJS.UI.processAll(root).then(function () {
var listview = document.querySelector('#myNotePad').winControl;
listview.addEventListener("iteminvoked", itemInvokedHandler,false);
function itemInvokedHandler(e) {
e.detail.itemPromise.done(function (invokedItem) {
myEdit();
});
};
});
The problem is that everytime I click on the listview myEdit() is run and propagates within the listview. I was wondering how to do it once and stop invoking listview until I am done with myEdit? Is there a simpler way to handle such a situation as this?
Simple yet hard to see when you have a mind block and forget some of the basics (yes yes I'm still learning):
var testtrue = true;
WinJS.UI.processAll(root).then(function () {
var listview = document.querySelector('#myNotePad').winControl;
listview.addEventListener("iteminvoked", itemInvokedHandler,false);
function itemInvokedHandler(e) {
e.detail.itemPromise.done(function (invokedItem) {
if (testtrue === true){
myEdit();
}
});
};
});
In myEdit:
function myEdit() {
var theelem = document.querySelector(".win-selected #myNotes");
var gestureObject = new MSGesture();
gestureObject.target = theelem;
theelem.gestureObject = gestureObject;
theelem.addEventListener("pointerdown", pointerDown, false);
theelem.addEventListener("MSGestureHold", gestureHold, false);
function pointerDown(e) {
e.preventDefault();
e.target.gestureObject.addPointer(e.pointerId);
}
function gestureHold(e) {
if (e.detail === e.MSGESTURE_FLAG_BEGIN && test === true) {
e.preventDefault();
editNotes();
} else {
}
console.log(e);
}
theelem.addEventListener("contextmenu", function (e) {
e.preventDefault();}, false); //Preventing system menu
};
function editNotes() {
//The Code I wish to execute
return test = false;
};
What I needed was a conditional statement so that it would run if true and not if false. That same test needed to be done in the gestureHold otherwise it would continue to fire myEdit on the invoked item because of the way the gesture is attached to the item the first time it is run.

Categories

Resources