getElementById dosent work since Sugarcube ver 2.24.0

0 votes
asked Apr 11 by xHome (160 points)

I tried to implement an progress bar in my Sugarcube Story. With Sugarcube 2.21.0 everything worked fine, but after an update to Sugarcube 2.24.0 it seems like the script is running before registering the "id". Is there any way to fix it?

Passage Code:

<<set _a to 43>>
<<set _c to Math.round(_a/10)>>
<<nobr>><ul id="loadbar">
    <li>
    <div class="layerFill1" id="1"></div>
    </li>
    <li>
    <div class="layerFill2" id="2"></div>
    </li>
    <li>
    <div class="layerFill3" id="3"></div>
    </li>
    <li>
    <div class="layerFill4" id="4"></div>
    </li>
    <li>
    <div class="layerFill5" id="5"></div>
    </li>
    <li>
    <div class="layerFill6" id="6"></div>
    </li>
    <li>
    <div class="layerFill7" id="7"></div>
    </li>
    <li>
    <div class="layerFill8" id="8"></div>
    </li>
    <li>
    <div class="layerFill9" id="9"></div>
    </li>
    <li>
    <div class="layerFill10" id="10"></div>
    </li>
</ul><</nobr>>
<<for _i to 1; _i lt _c+1; _i++>>
<<script>>
	window.progresstest();
<</script>>
<</for>>

 Javascript Code:

window.progresstest = function () {
    var b='_b';
    var d='_i';
	document.getElementById(d).style.width="100%";
	document.getElementById(d).style.height="12px";
}	

Errormessage: <<script>>: bad evaluation: Cannot read property 'style' of null

1 Answer

0 votes
answered Apr 11 by xHome (160 points)

Found a solution myself with $(document).on(':passagedisplay', function (ev) {

<<set _a to 43>>
<<nobr>><ul id="loadbar">
    <li>
    <div class="layerFill1" id="1"></div>
    </li>
    <li>
    <div class="layerFill2" id="2"></div>
    </li>
    <li>
    <div class="layerFill3" id="3"></div>
    </li>
    <li>
    <div class="layerFill4" id="4"></div>
    </li>
    <li>
    <div class="layerFill5" id="5"></div>
    </li>
    <li>
    <div class="layerFill6" id="6"></div>
    </li>
    <li>
    <div class="layerFill7" id="7"></div>
    </li>
    <li>
    <div class="layerFill8" id="8"></div>
    </li>
    <li>
    <div class="layerFill9" id="9"></div>
    </li>
    <li>
    <div class="layerFill10" id="10"></div>
    </li>
</ul><</nobr>>
<<set _c to Math.round(_a/10)>>
<<if _c lte 1>>
	<<set _b to "linear-gradient(to bottom, rgba(230,5,15,1) 0%,rgba(229,114,118,1) 100%)">>
<<elseif _c gt 1 and _c lte 2>>
	<<set _b to "linear-gradient(to bottom, rgba(224,21,175,1) 0%,rgba(221,110,194,1) 100%)">>
<<elseif _c gt 2 and _c lte 3>>
	<<set _b to "linear-gradient(to bottom, rgba(199,28,222,1) 0%,rgba(207,110,221,1) 100%)">>
<<elseif _c gt 3 and _c lte 4>>
	<<set _b to "linear-gradient(to bottom, rgba(72,43,216,1) 0%,rgba(124,107,214,1) 100%)">>
<<elseif _c gt 4 and _c lte 5>>
	<<set _b to "linear-gradient(to bottom, rgba(50,80,213,1) 0%,rgba(118,137,211,1) 100%)">>
<<elseif _c gt 5 and _c lte 6>>
	<<set _b to "linear-gradient(to bottom, rgba(56,140,210,1) 0%,rgba(169,191,209,1) 100%)">>
<<elseif _c gt 6 and _c lte 7>>
	<<set _b to "linear-gradient(to bottom, rgba(63,193,207,1) 0%,rgba(167,203,206,1) 100%)">>
<<elseif _c gt 7 and _c lte 8>>
	<<set _b to "linear-gradient(to bottom, rgba(69,205,169,1) 0%,rgba(171,204,195,1) 100%)">>
<<elseif _c gt 8 and _c lte 9>>
	<<set _b to "linear-gradient(to bottom, rgba(75,202,124,1) 0%,rgba(171,201,182,1) 100%)">>
<<else>>
	<<set _b to "linear-gradient(to bottom, rgba(123,196,87,1) 0%,rgba(212,219,208,1) 100%)">>
<</if>>
<<for _i to 1; _i lt _c+1; _i++>>
<<set _d to _i>>_d
<<script>>
 var b = State.getVar("_b");
 var i = State.getVar("_i");
 $(document).on(':passagedisplay', function (ev) {
     	    document.getElementById(i).style.width="100%";
	        document.getElementById(i).style.height="12px";
	        document.getElementById(i).style.backgroundImage=b;
});
<</script>>
<</for>>

 

commented Apr 11 by TheMadExile (43,200 points)

The "since Sugarcube ver 2.24.0" in your question is misleading as the code you initially tried has never worked.  This is due to the fact that the rendering passage content is not yet on the page, which is why you have to delay the code until it is.

Beyond that, your new code has some issues.

  1. You're creating multiple persistent event handlers when it seems as though a single one-time-use handler would do.  Even if you did need a persistent handler, a single one would likely be sufficient.
  2. The State.getVar() method is most useful when you do not know one, or both, of a variable's name or whether it's a story or temporary variable beforehand.  Otherwise, you're better off using either State.variables or State.temporary as appropriate.
  3. You're not caching values that you're using repeatedly.  This is especially egregious in cases like calls to document.getElementById().

As a suggestion, I'd look into replacing your entire <<for>> loop with the following:

<<script>>
$(document).one(':passagedisplay', function (ev) {
	var bg  = State.temporary.b;
	var len = State.temporary.c + 1;

	for (var i = 1; i < len; i++) {
		var el = document.getElementById(i);
		el.style.width = '100%';
		el.style.height = '12px';
		el.style.backgroundImage = bg;
	}
});
<</script>>

If you really want to print out the IDs as well, and that wasn't simply for testing, then you could keep the <<for>> around and simply have it do that (do not put the above example <<script>> into the loop in that case, keep them separate).

Welcome to Twine Q&A, where you can ask questions and receive answers from other members of the community.

You can also find hints and information on Twine on the official wiki and the old forums archive.

See a spam question? Flag it instead of downvoting. A question flagged enough times will automatically be hidden while moderators review it.
...