Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Custom Javascript Functions and Key-Value Pair Dilemma.

As a precursor, I have been spending hours researching this, scouring the Twine forums, w3schools for Javascript, the Twine 2 wiki, and SugarCube 2 docs, so this is kinda my last resort.

Firstly, I have found next to no documentation on creating custom Javascript functions and using them. Everything I have learned is through looking at examples, and with my own knowledge of JS.

I set out trying to learn how to take an array of objects, such as:
[ { name: "Gold", value: 100 }, { name: "Silver", value: 10 }, { name: "Copper", value: 1 } ]

And pass it into a custom JS function to get the sum of all of "value" properties.

I created a function and attached it to "window" (a trick that doesn't seem to be explain anywhere) which looked like this:
window.SumValue = function (list) {
	var v=0;
	for(var i=0; i<=list.length; i++) {
		v+=list[i].value;
	}
	return v;
}
(I put this in my "Edit Story Javascript" area of my Twine project.)
Then, in attempted to use the function as follows:
<<set $list to [ { name: "Gold", value: 100 }, { name: "Silver", value: 10 }, { name: "Copper", value: 1 } ]>>

<<print SumValue($list)>>

The intended result was to print the number: 111 to the screen when the passage loaded (100 + 10 + 1), instead I get an error that reads, "Error: <<print>>: bad evaluation: Cannot read property 'value' of undefined".

If anyone has some answers for me, even if it's just pointing me in the direction of the documentation on how work with JS and Twine/Sugarcube, I would most appreciate it.

I am using Twine 2 (offline), SugarCube 2.12.1 (local/offline).

Lastly, I would prefer to not have to use widgets to accomplish this, as they are bulky, do not provide a return method, and generally aren't good for internal workings.

Comments

  • I hate to bump, it always felt rude or desperate, but I would like to see if I could at least get some direction on this. It's very difficult divining how Twine and SugarCube interact, at least at my level, and I feel that I'm greatly in the dark when it comes to creating custom Javascript functions for Twine. There's at least three whole languages/systems to understand here, and I don't know where to look at this point for answers.

    Any help is greatly appreciated.
  • MeekoSoup wrote: »
    Firstly, I have found next to no documentation on creating custom Javascript functions and using them. Everything I have learned is through looking at examples, and with my own knowledge of JS.
    I always suggest the Mozilla Developer Network. IME, they're currently the best one-stop-shop for both guides and reference material for HTML, CSS, and JavaScript.

    MeekoSoup wrote: »
    I created a function and attached it to "window" (a trick that doesn't seem to be explain anywhere) […]
    That trick—including the reason it's necessary: scoping issues—has been explained on these forums countless times. That's not a shot at you, BTW, just an observation.

    The environment/scope within which author/developer JavaScript is normally executed inside most story formats is localized. Meaning, if you want a function you define to be accessible outside of its own localized scope, you need to attach it to a scope which is already accessible to the rest of the story format.

    In all story formats you may use the global scope for this purpose, which you accomplish by attaching the function to the window object—as you've already discovered. As a special property of the window object, all of its members are also what's known as auto-globals—meaning you can access them without have to prefix them with window.

    In SugarCube, you have an additional option in the setup object.

    MeekoSoup wrote: »
    […]which looked like this:
    window.SumValue = function (list) {
    	var v=0;
    	for(var i=0; i<=list.length; i++) {
    		v+=list[i].value;
    	}
    	return v;
    }
    
    I see an error and have a couple of suggestions:
    1. ERROR: When iterating over the array, you're including the length of the array in your range, which is incorrect. Arrays in JavaScript are 0-based—i.e. the first index is 0—so your range should be 0(length - 1). You set your lower bound to 0, which is correct, however, you use the the less-than-or-equal operator in the loop conditional, which makes your upper bound length, rather than the correct (length - 1). You should have used the less-than operator. This is the cause of the "cannot read property 'value' of undefined" error you received—since your last access went out-of-bounds and thus the value was undefined.
    2. SUGGESTION: You did not terminate your assignment statement with a semi-colon. While JavaScript does have ASI (automatic semi-colon insertion) rules, you should not depend on them unless you understand them very well. Personally, I say do not depend on them at all, but that's a personal preference.
    3. SUGGESTION: I, generally, do not recommend snuggling identifiers up to non-unary operators.
    Try something like the following:
    window.SumValue = function (list) {
    	var sum = 0;
    
    	for (var i = 0; i < list.length; i++) {
    		sum += list[i].value;
    	}
    
    	return sum;
    };
    


    EXTRA CREDIT ALTERNATIVE

    You're not leveraging the native JavaScript library. The native Array object has methods which may be used to help you out here. For example, here's your summing function rewritten to use the <Array>.reduce() method:
    window.SumValue = function (list) {
    	return list.reduce(function(sum, current) {
    		return sum + current.value;
    	}, 0);
    };
    
  • Wow, thank you TheMadExile! I cannot believe I made so many noobie mistakes. On top of the fact that I didn't do a good proof read of my own post, I can't believe I made a fence-post error on something I do all the time... That is incredibly sloppy of me. I would like to apologizes as well. Rereading my post, I feel like it sounded like I was angry or that I had not researched anything.

    Thank you again for all the help. I didn't realize how well Twine and SugarCube interfaced with native JavaScript. And thanks for explaining everything so thoroughly! I hope that I can help people on the forum even half as much as you helped me!
Sign In or Register to comment.