Javascript variable portability between scenes

Having a hard time with something I feel like should be easy but has had me flummoxed most of the afternoon.

I'm building a educational simulation designed for third graders where students learn a little, make a choice, learn a little more and then either stay with their original choice, or choose a different one.

On the first slide where they choose something I've got javascript storing the variable. I store the number 1 for the variable they chose. Flash forward a few scenes and I want them to make another choice, but I also want them to have their previous choice come up.

To do this I did a bunch of if { else if{ else commands which worked in a testing file I built. Unfortunately it only returns a "zero" even with the unique element ID properly tagged. Any ideas what I'm doing wrong?

This google drive link (the Hype doc is 6 mb) has the document. I have set up a trigger to take anyone running it right to the first choice, you then can skip through (click on the right hand side of the screen to move forward, the left to move back) to the second choice which doesn't show up.

Do variables travel through the various scenes? If not - what should I do here?

Any help greatly appreciated!

The scope of a variable will depend on how it is defined.

If you want a variable that is universally available within a Hype document (but not elsewhere) you should consider using Hype custom data.

Check out this forum post for more details:

1 Like

To expand on @drewbullen's answer a bit, Hype event handlers are functions, so when you do something like:

function chooseA(hypeDocument, element, event) {	

	var a = 1;
	var b = 0;
	var c = 0;
	// ... and so on
}

Because you declared the variables with a var keyword, they are scoped to the function, and don't live outside that particular function. So you cannot access them from a different function (like a different event handler). This isn't particular to scenes; two event handlers that run in the same scene don't have access to them either. Further, once the function is done running, the variables are cleaned up -- so they always start fresh when the function is called.

Therefore when you have another function like:

function whichChoice(hypeDocument, element, event) {	
	if (a = 1) {
		hypeDocument.getElementById("choice").innerHTML = "Site 1";
		} else if (b = 1) {	

The a that you are referencing here has no knowledge of the a defined in another function, especially since it doesn't even exist at the time you're calling this.

"naked" variable access like this goes to the global scope. Since your declarations before were local to the function, you won't have them defined.

Now what you could have done is remove the var keyword in the chooseA() function, and then they would also be on the global scope and this would theoretically work.

However, while it might work, it is a particularly bad idea for several reasons to do it this way. The global scope means anything on the .html page can use those variable names. This could be other Hype documents, including your own. Or it could be other scripts that you've included. In particular, since these are single letter variable names there's a good chance someone other script might be accidentally colliding with them.

Instead, @drewbullen's suggestions are spot-on, you can store things into the hypeDocument.customData storage, which is intended exactly to solve your problem.

Setting the variables would look like:

function chooseA(hypeDocument, element, event) {	

	hypeDocument.customData.a = 1;
	hypeDocument.customData.b = 0;
	hypeDocument.customData.c = 0;
	// ... and so on
}

And testing the variables would look like:

function whichChoice(hypeDocument, element, event) {	
	if (hypeDocument.customData.a == 1) {
		hypeDocument.getElementById("choice").innerHTML = "Site 1";
	} else if (hypeDocument.customData.b == 1) {	

One very important note is that a single = sign is for variable assignment in JavaScript. A == is required for equality testing. So note that I changed those in the example, since your code will definitely do the wrong thing with a single equal sign.

Scoping is a core JavaScript concepts to learn, so I'd recommend reviewing some other online docs to reinforce how it all works :slight_smile:.

1 Like

Moved my post here:

2 Likes

All of you - huge thanks! Over the last few years I've kicked the tires on most of the stuff Hype can do without using Javascript and now I'm dipping those toes in the water. Was a HUGE q-Basic programmer back in the day but never anything more complex. I couldn't figure out why this was not working.

Again, huge thanks all! Will continue investigating down this path!

2 Likes

You're welcome. I'd go with @drewbullen and @jonathan if you're into learning the regular Hype way. My reactive approach is more a convenience approach if the focus is on getting things done in a production environment over learning coding. I updated the reactive code, should be even more robust now. Sample file has different approaches and ways in it. You don't need them all.

1 Like

I'd love to know both! I've picked up several Javascript books on coding (mostly for kids because I'm an older dog and this is a new trick) and have been working through code for this and collisions for these interactives. But I obviously have more to learn because in rewriting my examples I'm only able to return a value if people choose site 1.

I'm going to make a copy of the file and try your route by assigning the variables via custom behavior, but I'd also love to know where I'm going wrong with my "returning of the choice"

if (hypeDocument.customData.a == 1) {
	hypeDocument.getElementById("choice").innerHTML = "Site 1";
} else if (hypeDocument.customData.b == 1) {
	hypeDocument.getElementbyID("choice").innerHTML = "Site 2";
} else if (hypeDocument.customData.c == 1) {
	hypeDocument.getElementbyID("choice").innerHTML = "Site 3";
} else if (hypeDocument.customData.d == 1) {
	hypeDocument.getElementbyID("choice").innerHTML = "Site 4";
} else if (hypeDocument.customData.e == 1) {
	hypeDocument.getElementbyID("choice").innerHTML = "Site 5";
} else {
	hypeDocument.getElementByID("choice").innerHTML = "Site 6";		
	}

This will return Site 1 if people chose site one, but won't return Sites 2-6 if those were selected. First I forgot to close the bracket which returned nothing, even for site 1 but then I figured that out.

I've double checked that code (even tried commenting out the others since each variable's natural state is null) but I can only get either Site 1 to return, or the "..." that I set the original "choice" unique identifier to. (Changed from "0" in the document I provided above to make sure it wasn't somehow saving the variables as 0.

I am not really sure why you don't just use a single variable and determine the route from it. Are the variable like toggles? In the other case, there is a single variable/choice … meaning an variable that can be either of the decisions, but not all. Another hint is… I like to use switch statements in such cases. I find them easier to read:

var choiceElm = hypeDocument.getElementById("choice");
switch(hypeDocument.customData.choice) {
     case 1: choiceElm.innerHTML = 'Site 1'; break;
     case 2: choiceElm.innerHTML = 'Site 2'; break;
     case 3: choiceElm.innerHTML = 'Site 3'; break;
     case 4: choiceElm.innerHTML = 'Site 4'; break;
     case 5: choiceElm.innerHTML = 'Site 5'; break;
     default: choiceElm.innerHTML = 'Site 6'; break;
}      

BTW that is only one way of assigning them, as the reactivity is based on customData itself. Hence, the reactivity also works when assigning them in code hypeDocument.customData.choice = 1; would also trigger updates in the case of Hype Reactive Content.

2 Likes

If I'm reading up on "switch" correctly I would still have to define the variable selected back in the previous scene.

My "guess" based on your hint: the choice they pick on the previous scene is toggled as 0-5 (or 1-5 here) using custom behavior and that number tells Hype to change what I have as the unique identifier of "choice" to "Site X" based on what value is being returned.

You're correct that this is technically a "toggle" - students will be going back to this choice 5 different times, each time getting more information from the map. They'll either let their choice ride or choose a new one, so it'll be a lot of toggling them on and off depending on the choice they made in the previous scene. (I have another function that resets everything to zero I plan on summoning after the scene has loaded and spit back their previous choice, but before the make their next choice)

My problem is probably that when in doubt I go back to how I solved these problems as a 11 year old programming things in QBasic. 🫠 I so desperately want the syntax to be the same but as evidenced above with the relatively simple = vs == mistake, when in doubt my brain goes backward.

Everyone - a massive kudos. I could not get these solutions to work but then I remembered my old friend Occam and his razor.

Rather than creating a complex set of if/then statements, I used and tailored the suggestion above to use custom data.

This means I now have 6 javascript functions A-F that all look like this:

function chooseA(hypeDocument, element, event) {
hypeDocument.customData.place = "Site 1";
}

When students click on their choice and go through the next few rounds of slides and make it to the next decision tree, the scene loads and runs my "checker" function which now looks like this:

function whichChoice(hypeDocument, element, event) {
hypeDocument.getElementById("choice").innerHTML = hypeDocument.customData.place;
}

This replaces the text I put on the Canvas of "..." with whichever site was chosen.

I finished programming all the "explainer" slides yesterday and am now just going to shore up the decision tree slides.

Honestly - all of you - you have my thanks. I will learn the heck out of Javascript yet! :smile:

@MaxZieb @jonathan @drewbullen - a cup of coffee for each of you: :coffee::coffee::coffee:

4 Likes

That definitely sounds like the simplest solution! (And finding those is definitely part of the joy I have in programming too!)

2 Likes