Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

API setAttrs() Isn't Triggering Sheetworker on(change:) Actions?

Is there any way for an API script to trigger a sheetworker action on a character sheet?  I vaguely recall reading that the setAttrs() command was supposed to do this, but it isn't working with my sheets.  If this isn't the case, are there any other clever suggestions on how I could get this to happen? To describe my problem:  My character sheet includes a repeating section for Projects that the PCs and NPCs can initiate at will.  Each Project has a start date and an end date, and then a counter that shows the player how close their project is to completion.  I have an API script that I use to change the date and time in-game, and whenever I do, I set a "current_date" attribute on each character sheet to the new date.  At this point, I have an on("change:current_date") trigger set up to go through the sheet's projects, and update the counter.  However, setting this attribute isn't triggering the sheetworker (I've verified it isn't a problem later on in the script by logging whenever the sheetworker is triggered, and it seems that setAttrs() simply isn't triggering). Any help/advice would be much appreciated!
You need to use setWithWorker inside the API environment.
1541512097

Edited 1541512158
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Setattrs was added to the API as well, although I have yet to use it personally. It'd help if you could share code.
This is the relevant part in my sheetworker script: on ( "change:currentdate" ,   function   ( eventInfo )   {     console . log ( ">>> DATE CHANGE DETECTED >>>"   +  JSON . stringify ( eventInfo ));     updateProjectDates ();      return ; }); And this is the code in the API script I'm using to set the attribute: _ . each ( Chars . GetAll (),   function   ( char )   {     setAttrs ( char . id ,   {  currentdate :  newTimeStrings . month  +   " "   +  newTimeNums . days  +   ", "   +  newTimeStrings . year  }); }); I also tried this version, to no avail: _ . each ( Chars . GetAll (),   function   ( char )   {     D . GetStat ( char . id ,   "currentdate" ). setWithWorker ({  current :  newTimeStrings . month  +   " "   +  newTimeNums . days  +   ", "   +  newTimeStrings . year  }); }); The attribute is being set on the sheet (I've jury-rigged it so that when the player switches tabs, it runs the same updateProjectDates() function, and the counters update then), but the on:change  isn't triggering from the API script (I was logging eventInfo to the console to detect the triggers, and nothing came up when I changed the date with the API script.
1541521914

Edited 1541522027
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
So, I just tested setAttrs in my API console with the following script and it worked as expected: on('ready',()=>{ setAttrs('-LQdq8rWR26tY2abGxhu',{api:'test'});//Swap the id for a hardcoded id in your game. }); And the following "sheet": <input type='text' name='attr_api'> <input type='text' name='attr_react'> <script type='text/worker'> on('change:api',()=>{ console.log(`##############$$$$$$$$$$$$$ api change detected $$$$$$$$$$$$$##############`); setAttrs({react:'Reacted'},{silent:true}); }); </script> My guess would be that you are not actually passing a valid character id to the function. Have you tried logging your returned char object to make sure it is giving you what you think it should and comparing the id it contains with the character id of that character in your game via @{character_id}? EDIT: Also, are you sure that your getAll and getStat functions are doing what you think they are?
1541524184

Edited 1541524209
My guess would be that you are not actually passing a valid character id to the function. Have you tried logging your returned char object to make sure it is giving you what you think it should and comparing the id it contains with the character id of that character in your game via @{character_id}? EDIT: Also, are you sure that your getAll and getStat functions are doing what you think they are? Yep, I verify all the data types in my functions, and did check to see if a valid character object was being returned (it was).  Also, the code with those functions does work --- the "currentdate" attribute on the sheet changes as it should; it's the on("change:currentdate") trigger that doesn't fire.
1541524691

Edited 1541525224
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Hmm, my demo code causes the sheetworkers to fire correctly. Here are some things to check: Is your updateProjectDate() function working as expected? Does it fire if you manually change the current date attribute? Realized you already addressed the first part of this. What does your html for these attributes look like? What does your API console look like on sandbox bootup? For instance, if you are using the spread operator (...), it will work in sheetworkers run in the browser (aka manual changes), but will crash the sheetworkers in the API sandbox (aka api generated changes).
1541593198

Edited 1541593283
Thank you very much for taking the time to work through this with me!&nbsp; I'll answer your questions in order, but you may want to skip down to the third one for what might be the problem. Does it fire if you manually change the current date attribute? No.&nbsp; When I go into the Attributes tab and manually change the current date, the on("change:currentdate") trigger doesn't fire.&nbsp; I get the following output in my log as soon as I click off of the field: [Violation] Forced reflow while executing JavaScript took 46ms app.js?1541523443:352 Really updating character sheet values app.js?1541523443:353 Foudn a pre-defined key order! app.js?1541523443:352 Setting up repeating sections took until 13ms app.js?1541523443:352 Finding list of dirty attributes took until 14ms app.js?1541523443:352 Querytest took until 15ms app.js?1541523443:352 Attribute cache compliation took until 16ms app.js?1541523443:352 Set values (including auto-calcuating variables) took until 25ms app.js?1541523443:352 Took 27ms As soon as I trigger the event by another means (I've set up the same function to trigger when tabs are switched since, as a manual action, it works just fine), this is the log output: CLICKED: radio/checkbox &lt; input class =​" sheet-tab sheet-tab4 sheet-singlesheet " type =​" radio " name =​" attr_core-tab " value =​" 4 " title =​" Projects " &gt; ​ app.js?1541523443:352 input type radio value = "4" app.js?1541523443:352 Really updating character sheet values app.js?1541523443:353 Foudn a pre-defined key order! app.js?1541523443:352 Setting up repeating sections took until 14ms app.js?1541523443:352 Finding list of dirty attributes took until 14ms app.js?1541523443:352 Querytest took until 16ms app.js?1541523443:352 Attribute cache compliation took until 19ms app.js?1541523443:352 Set values (including auto-calcuating variables) took until 24ms app.js?1541523443:352 Took 26ms VM17:454 UPDATING DATES: V: {"currentdate":"July 9, 2018","projectstartdate":"July 9, 2018","projectenddate":"July 19, 2018","projectincnum":"1","projectinccounter":6,"projectincunit":"days","projectlaunchrollToggle":2,"projectlaunchresults":"SUCCESS!"} VM17:454 ... NEW COUNTER POS: 10 VM17:454 ... UPDATING INCCOUNTER app.js?1541523443:352 Really updating character sheet values app.js?1541523443:353 Foudn a pre-defined key order! app.js?1541523443:352 Setting up repeating sections took until 11ms app.js?1541523443:352 Finding list of dirty attributes took until 16ms VM17:454 ACTIVATION BY: {"sourceAttribute":"repeating_project_-lqwukdid6jrxck5jcpr_projectinccounter","sourceType":"sheetworker","triggerName":"repeating_project_-lqwukdid6jrxck5jcpr","previousValue":6,"newValue":10} app.js?1541523443:352 Querytest took until 18ms app.js?1541523443:352 Attribute cache compliation took until 19ms app.js?1541523443:352 Set values (including auto-calcuating variables) took until 27ms app.js?1541523443:352 Took 29ms  ​ What does your html for these attributes look like? The only attribute that is causing problems is "currentdate".&nbsp; It's contained in a fairly straight-forward hidden input field, outside of any fieldset sections, right at the top of the Projects page: &lt; div &nbsp; class = "sheet-pagecontainer&nbsp;sheet-section-4&nbsp;sheet-singlesheet" &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; input &nbsp; type = "hidden" &nbsp; name = "attr_currentdate" &nbsp; /&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!--&nbsp;PROJECTS&nbsp;--&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; div &nbsp; class = "sheet-header1" &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; img &nbsp; src = "<a href="https://imgur.com/b4nLXfG.png" rel="nofollow">https://imgur.com/b4nLXfG.png</a>" &nbsp; /&gt; &nbsp; &lt;!--&nbsp;Projects Header&nbsp;--&gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/ div &gt; What does your API console look like on sandbox bootup? Uhm, well, there is an error in there, and it's been there for quite a while ... Restarting&nbsp;sandbox&nbsp;due&nbsp;to&nbsp;script&nbsp;changes... Previous&nbsp;shutdown&nbsp;complete,&nbsp;starting&nbsp;up... Spinning&nbsp;up&nbsp;new&nbsp;sandbox... "Starting&nbsp;webworker&nbsp;script..." "Loading&nbsp;0&nbsp;translation&nbsp;strings&nbsp;to&nbsp;worker..." "ReferenceError:&nbsp;GROUPATTRS&nbsp;is&nbsp;not&nbsp;defined" "ReferenceError:&nbsp;GROUPATTRS&nbsp;is&nbsp;not&nbsp;defined &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;eval&nbsp;(eval&nbsp;at&nbsp;messageHandler&nbsp;(evalmachine.&lt;anonymous&gt;:284:6),&nbsp;&lt;anonymous&gt;:421:12) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;Function.m.each.m.forEach&nbsp;(evalmachine.&lt;anonymous&gt;:5:2350) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;eval&nbsp;(eval&nbsp;at&nbsp;messageHandler&nbsp;(evalmachine.&lt;anonymous&gt;:284:6),&nbsp;&lt;anonymous&gt;:419:7) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;eval&nbsp;(&lt;anonymous&gt;) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;messageHandler&nbsp;(evalmachine.&lt;anonymous&gt;:284:6) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;process.&lt;anonymous&gt;&nbsp;(/home/node/d20-api-server/node_modules/tiny-worker/lib/worker.js:60:55) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;emitTwo&nbsp;(events.js:106:13) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;process.emit&nbsp;(events.js:194:7) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;process.nextTick&nbsp;(internal/child_process.js:766:12) &nbsp;&nbsp;&nbsp;&nbsp;at&nbsp;_combinedTickCallback&nbsp;(internal/process/next_tick.js:73:7)" "Roller:&nbsp;&nbsp;Ready!" "GetData:&nbsp;Ready!" "Chars:&nbsp;&nbsp;Ready!" "WigglePads:&nbsp;&nbsp;Ready!" "TimeTracker:&nbsp;&nbsp;Ready!" ... however, I've been ignoring it for two reasons: It hasn't appeared to be messing with any of my scripts (though boy will my face be red if this is the culprit all along...), and It makes no sense to me.&nbsp; "GROUPATTRS" is a const defined right at the top of my sheetworker script, and the line it's complaining about is just a bit further down: const &nbsp;GROUPPREFIXES&nbsp; = &nbsp; [ "g1" , &nbsp; "g2" , &nbsp; "g3" , &nbsp; "g4" , &nbsp; "g5" , &nbsp; "g6" , &nbsp; "g7" , &nbsp; "g8" , &nbsp; "g9" ]; const &nbsp;GROUPATTRS&nbsp; = &nbsp; [ "charname" , &nbsp; "Hunger" ]; &nbsp; //&nbsp;****&nbsp;GROUPATTRS&nbsp;defined&nbsp;here; error line is just below these declarations&nbsp;**** const &nbsp;GROUPREPSECTIONS&nbsp; = &nbsp; [ "rolls" ]; const &nbsp;GROUPREPREFS&nbsp; = &nbsp; [ "rollType" , &nbsp; "trait1name" , &nbsp; "trait1value" , &nbsp; "trait2name" , &nbsp; "trait2value" , &nbsp; "rolldiff" , &nbsp; "rollmod" , &nbsp; "posflags" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "negflags" , &nbsp; "roll_params" ]; const &nbsp;PROJREPSECTIONS&nbsp; = &nbsp; [ "project" ]; const &nbsp;PROJDATEDEPS&nbsp; = &nbsp; [ "projectstartdate" , &nbsp; "projectincnum" , &nbsp; "projectincunit" , &nbsp; "projectenddate" , &nbsp; "projectinccounter" , &nbsp; "projectrushpool" ]; const &nbsp;PROJREPFLAGS&nbsp; = &nbsp; [ "projectstartdate" , &nbsp; "projectincnum" , &nbsp; "projectincunit" , &nbsp; "projectscope" , &nbsp; "projectlaunchtrait1_name" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "projectlaunchtrait1" , &nbsp; "projectlaunchtrait2_name" , &nbsp; "projectlaunchtrait2" , &nbsp; "projectlaunchmod" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "projectstake1_name" , &nbsp; "projectstake1" , &nbsp; "projectstake2_name" , &nbsp; "projectstake2" , &nbsp; "projectstake3_name" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "projectstake3" , &nbsp; "projectstake4_name" , &nbsp; "projectstake4" , &nbsp; "projectstake5_name" , &nbsp; "projectstake5" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "projectstake6_name" , &nbsp; "projectstake6" , &nbsp; "projectlaunchresults" , &nbsp; "projectlaunchresultsmargin" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "projectlaunchdiffmod" , &nbsp; "projectwasrushed" ]; const &nbsp;PROJREPATTRS&nbsp; = &nbsp; [ "projectenddate" , &nbsp; "projectinccounter" , &nbsp; "projectscope_name" , &nbsp; "projectlaunchdiff" , &nbsp; "projectlaunchrollToggle" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "projectlaunchroll_params" , &nbsp; "projecttotalstake" , &nbsp; "projectrushpool" , &nbsp; "projectstakesatrush" , &nbsp; "projectrushstakelost" , &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "projectrushstakelosttogo" ]; //#endregion //#region&nbsp;Derivative&nbsp;Stats const &nbsp;basicStats&nbsp; = &nbsp;_ . flatten ([ _ . values ( ATTRIBUTES ), &nbsp;_ . values ( SKILLS ), &nbsp;ENUMSTATS , &nbsp;TRACKERS ]); const &nbsp;statFlags&nbsp; = &nbsp;_ . map ( _ . omit ( basicStats , &nbsp;TRACKERS ), &nbsp; function &nbsp; ( stat ) &nbsp; { &nbsp; return &nbsp;stat&nbsp; + &nbsp; "_flag" ; &nbsp; }); var &nbsp;GROUPSTATS&nbsp; = &nbsp; {}; _ . each ( GROUPPREFIXES , &nbsp; function &nbsp; ( prefix ) &nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;GROUPSTATS [ prefix ] &nbsp; = &nbsp; { attrList : &nbsp; [], &nbsp;repSections : &nbsp; [], &nbsp;repStats : &nbsp; []}; &nbsp;&nbsp;&nbsp;&nbsp;_ . each ( GROUPATTRS , &nbsp; function &nbsp; ( attr ) &nbsp; { &nbsp;&nbsp;&nbsp; //&nbsp;****&nbsp;the&nbsp;line&nbsp;number&nbsp;complained&nbsp;about&nbsp;in&nbsp;the&nbsp;API&nbsp;console&nbsp;*** &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GROUPSTATS [ prefix ]. attrList . push ( prefix&nbsp; + &nbsp;attr ); &nbsp;&nbsp;&nbsp;&nbsp; }); &nbsp;&nbsp;&nbsp;&nbsp;_ . each ( GROUPREPSECTIONS , &nbsp; function ( sec ) &nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GROUPSTATS [ prefix ]. repSections . push ( prefix&nbsp; + &nbsp;sec ); &nbsp;&nbsp;&nbsp;&nbsp; }); &nbsp;&nbsp;&nbsp;&nbsp;_ . each ( GROUPREPREFS , &nbsp; function ( stat ) &nbsp; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;GROUPSTATS [ prefix ]. repStats . push ( prefix&nbsp; + &nbsp;stat ); &nbsp;&nbsp;&nbsp;&nbsp; }); }); I'm curious as to&nbsp; Why does the error show up in my API console, and not the developer console of my browser?&nbsp; My developer console shows no errors and has no problems loading the sheetworker script. Though the reference error doesn't affect my API scripts or (most?) of my sheetworker scripts, is it possible this buggy constant --- despite being totally unrelated to anything having to do with Projects (though it's declared right near some Project-related constants, they have absolutely no interaction I can think of in the script; I haven't even started implementing Projects for my Group character sheets) --- is crashing the interface that lets the API trigger sheetworker events? Can you think of any reason why this error is happening in the first place?&nbsp; I mean, the code seems simple enough.
1541595792

Edited 1541595986
Ammo
Pro
One thing that might be worth your time is to change the name of your 'currentdate' attribute that you are using for your test, just to rule out that this is actually broken internally. &nbsp;It would be a massive waste of your time if there was just some internal bug around identifier collision. &nbsp;Yes, it is extremely unlikely, but rule it out and also you might find a typo somewhere in the process :)
It gets weirder:&nbsp; Even after I remove all references to GROUPATTRS from my sheetworker script, I still get that error on start up.
1541596070

Edited 1541596323
Ammo
Pro
Ryan said: It gets weirder:&nbsp; Even after I remove all references to GROUPATTRS from my sheetworker script, I still get that error on start up. Are you sure this isn't something goofy like another script is still running? &nbsp; I have never seen anything irrational happen in the Roll20 sandbox.
Ammo said: One thing that might be worth your time is to change the name of your 'currentdate' attribute that you are using for your test, just to rule out that this is actually broken internally. &nbsp;It would be a massive waste of your time if there was just some internal bug around identifier collision. &nbsp;Yes, it is extremely unlikely, but rule it out and also you might find a typo somewhere in the process :) Oh my God that was it!&nbsp; I changed it to "todaysdate" and it works perfectly!&nbsp; Thanks! (I'm still interested to know what's going on with this weird GROUPATTRS error, if you have any insights there?)
Ammo said: Ryan said: It gets weirder:&nbsp; Even after I remove all references to GROUPATTRS from my sheetworker script, I still get that error on start up. Are you sure this isn't something goofy like another script is still running? &nbsp; I haven never seen anything irrational happen in the Roll20 sandbox. I mean, I don't know how that could be --- the "Ready" lines in the log appear once for each script I have running, and each one is accounted for.&nbsp; And of course there's only the one character sheet, and I've confirmed there are no GROUPATTRS in any of the scripts (API or sheetworker).
Ahah, I reactivated the GROUPATTRS code in the sheetworker script, and the API no longer triggers the date change.&nbsp; So it appears that IS the problem, with the odd quirk that the error doesn't go away even after it's been fixed.
Ryan said: I mean, I don't know how that could be --- the "Ready" lines in the log appear once for each script I have running, and each one is accounted for.&nbsp; And of course there's only the one character sheet, and I've confirmed there are no GROUPATTRS in any of the scripts (API or sheetworker). Just trying to help step back a second before you get stuck in there for 12 hours (at least if your debugging is like mine.) &nbsp; Maybe rule out other transient bugs by creating a fresh game and testing just one thing in isolation? &nbsp;Then you know for sure that all the code that is running is the code you are actually reading...
Ryan said: Ahah, I reactivated the GROUPATTRS code in the sheetworker script, and the API no longer triggers the date change.&nbsp; So it appears that IS the problem, with the odd quirk that the error doesn't go away even after it's been fixed. I am staring very very hard at your code about the GROUPATTRS because it certainly seems correct. &nbsp;Like Scott explained (which was very valuable insight I had never understood before) pretty much everything you are seeing can be explained by the sandbox side of your sheet crashing. &nbsp;So that is probably all that is happening here, plus a lot of red herrings? &nbsp;&nbsp;
Ammo said: Ryan said: Ahah, I reactivated the GROUPATTRS code in the sheetworker script, and the API no longer triggers the date change.&nbsp; So it appears that IS the problem, with the odd quirk that the error doesn't go away even after it's been fixed. I am staring very very hard at your code about the GROUPATTRS because it certainly seems correct. &nbsp;Like Scott explained (which was very valuable insight I had never understood before) pretty much everything you are seeing can be explained by the sandbox side of your sheet crashing. &nbsp;So that is probably all that is happening here, plus a lot of red herrings? &nbsp;&nbsp; Okay, I've made some progress thanks to your help &amp; advice (much appreciated!).&nbsp; Instead of just commenting out the declaration and early lines that the error was referring to, I also commented out the entire Group section of code from my sheetworker script --- and that solved both problems: no API console error, and the sheets trigger on API changes as they should. I think the problem has something to do with the fact that I'm using an iterator to construct a variable (GROUPSTATS, via the _.each() stuff) that I'm using in on("change") trigger definitions.&nbsp; I know these aren't async functions, but maybe the script is trying to set up the on("change") triggers before the GROUPSTATS variable is ready for them?&nbsp; That's my best guess, anyways.&nbsp; When I have some time, I'll convert it into a function that the on("change") triggers can call, which will return the appropriate data, and see if that solves the problem. Thanks again for all your help, both of you!
ok before I read this I had gone away to see if there are any typos in your code by running it outside Roll20 (under node.js) and it runs fine. &nbsp; const GROUPPREFIXES = [ "g1" , "g2" , "g3" , "g4" , "g5" , "g6" , "g7" , "g8" , "g9" ] ; const GROUPATTRS = [ "charname" , "Hunger" ] ; // **** GROUPATTRS defined here; error line is just below these declarations **** const GROUPREPSECTIONS = [ "rolls" ] ; const GROUPREPREFS = [ "rollType" , "trait1name" , "trait1value" , "trait2name" , "trait2value" , "rolldiff" , "rollmod" , "posflags" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "negflags" , "roll_params" ] ; const PROJREPSECTIONS = [ "project" ] ; const PROJDATEDEPS = [ "projectstartdate" , "projectincnum" , "projectincunit" , "projectenddate" , "projectinccounter" , "projectrushpool" ] ; const PROJREPFLAGS = [ "projectstartdate" , "projectincnum" , "projectincunit" , "projectscope" , "projectlaunchtrait1_name" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "projectlaunchtrait1" , "projectlaunchtrait2_name" , "projectlaunchtrait2" , "projectlaunchmod" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "projectstake1_name" , "projectstake1" , "projectstake2_name" , "projectstake2" , "projectstake3_name" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "projectstake3" , "projectstake4_name" , "projectstake4" , "projectstake5_name" , "projectstake5" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "projectstake6_name" , "projectstake6" , "projectlaunchresults" , "projectlaunchresultsmargin" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "projectlaunchdiffmod" , "projectwasrushed" ] ; const PROJREPATTRS = [ "projectenddate" , "projectinccounter" , "projectscope_name" , "projectlaunchdiff" , "projectlaunchrollToggle" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "projectlaunchroll_params" , "projecttotalstake" , "projectrushpool" , "projectstakesatrush" , "projectrushstakelost" , &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "projectrushstakelosttogo" ] ; // not from this file const ATTRIBUTES = {} ; const SKILLS = {} ; const ENUMSTATS = [] ; const TRACKERS = [] ; // underscore.js crap function flattenDeep(arr) { &nbsp; return arr.reduce((acc, e) =&gt; Array .isArray(e) ? acc.concat(flattenDeep(e)) : acc.concat(e), [] ); } let _ = { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; flatten: flattenDeep, &nbsp; &nbsp; &nbsp; &nbsp; values: (x) =&gt; { x.values } , &nbsp; &nbsp; &nbsp; &nbsp; map: (x,y) =&gt; { x.map(y) } , &nbsp; &nbsp; &nbsp; &nbsp; omit: (x,y) =&gt; { /* sorry no time to write this */ return x } , &nbsp; &nbsp; &nbsp; &nbsp; each: (x,y) =&gt; { x.forEach(y) } } ; //#endregion //#region Derivative Stats const basicStats = _.flatten( [ _.values(ATTRIBUTES), _.values(SKILLS), ENUMSTATS, TRACKERS ] ); const statFlags = _.map(_.omit(basicStats, TRACKERS), function (stat) { return stat + "_flag" ; } ); &nbsp; var GROUPSTATS = {} ; _.each(GROUPPREFIXES, function (prefix) { &nbsp; &nbsp; GROUPSTATS [ prefix ] = { attrList: [] , repSections: [] , repStats: []} ; &nbsp; &nbsp; _.each(GROUPATTRS, function (attr) { &nbsp; // **** the line number complained about in the API console *** &nbsp; &nbsp; &nbsp; &nbsp; GROUPSTATS [ prefix ] .attrList.push(prefix + attr); &nbsp; &nbsp; } ); &nbsp; &nbsp; _.each(GROUPREPSECTIONS, function (sec) { &nbsp; &nbsp; &nbsp; &nbsp; GROUPSTATS [ prefix ] .repSections.push(prefix + sec); &nbsp; &nbsp; } ); &nbsp; &nbsp; _.each(GROUPREPREFS, function (stat) { &nbsp; &nbsp; &nbsp; &nbsp; GROUPSTATS [ prefix ] .repStats.push(prefix + stat); &nbsp; &nbsp; } ); } ); I have zero ideas why this very straight forward code without any async stuff somehow manages to access a global const before it is defined. &nbsp;Your approach of calculating it on the fly will probably fix it. &nbsp;But it is very unsatisfying not to know what is going on here :) Also, you're welcome. &nbsp;Can't resist debugging.
1541599747

Edited 1541600513
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
That is unlikely to say the least. One thing that I notice is that the line the error refereneces is not actually in the code you shared. It's in the emittwo function. What does that function look like? Heh, ammo ninjad me, this post was in reply to: I think the problem has something to do with the fact that I'm using an iterator to construct a variable (GROUPSTATS, via the _.each() stuff) that I'm using in on("change") trigger definitions.&nbsp; I know these aren't async functions, but&nbsp; maybe&nbsp; the script is trying to set up the on("change") triggers before the GROUPSTATS variable is ready for them?&nbsp; That's my best guess, anyways.&nbsp; When I have some time, I'll convert it into a function that the on("change") triggers can call, which will return the appropriate data, and see if that solves the problem. Thanks again for all your help, both of you! Ammo, what do you mean about accessing a constant before it's defined? I'm not seeing it, but I just woke up.
Scott C. said: That is unlikely to say the least. One thing that I notice is that the line the error refereneces is not actually in the code you shared. It's in the emittwo function. What does that function look like? Had already posted a congratulatory message, but isn't that a system function (i.e. Roll20 internal?). &nbsp; Does Roll20 automagically extract the sheet worker script and run a copy on the server side? &nbsp;Is this the stack trace of it simply eval'ing all the contents of that script?
But I do agree this can't really be the code we are looking at. &nbsp;There seems to be no way you would get past the reference to&nbsp; GROUPPREFIXES and then somehow not have GROUPATTRS defined.&nbsp; I'm no character sheet dev, so I don't have experience mapping this crappy stack :) back to the actual source. &nbsp;It looks like it is evaluating concatenated stuff, based on the column number of 2350 in the second frame. &nbsp;Doesn't that indicate they decided to read a compacted script and eval it? &nbsp; How are you supposed to debug.... :(
1541601426

Edited 1541601776
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Yeah, following sheetWorker stack traces from the console (either browser or API) is a PITA. They aren't just run as you have typed them in, they are loaded into the designated environment (browser for players, the API sandbox for API), and run within (I think) the Roll20 JS. You are however, probably right that emitTwo is a Roll20 function, although it's not one I've run across in my many many error generations. Ryan, can you link to a gist/repo of your entire html/script and API code? I think there's something hinky going on beyond the scope of the code you've linked. EDIT: As for how to debug, I wrap everything in a revealing module pattern so at least a function name I've defined will show up at some point to mark where my code's error stack ends. In addition, I very rarely do something directly in the on() and instead call a function from the on() so that again I have a function name to get me in the area of the problem. And finally just lots of logs; lots and lots of logs. EDIT the 2nd: Yep, looks like emitTwo is from the Roll20 side of things, just ran the code provided adding those 4 objects defined elsewhere, and same error.
Not to gloat, but the many many tiny functions that come from working in a TypeScript framework do help with stack traces: "2018-11-07T14:42:17.377Z rewards: Error: hi Scott!" "2018-11-07T14:42:17.378Z rewards: at ConfigurationArray.removeItem (apiscript.js:795:19)" "2018-11-07T14:42:17.379Z rewards: at ConfigurationDeleteItemCommand.parse (apiscript.js:1946:33)" "2018-11-07T14:42:17.379Z rewards: at Function.parse (apiscript.js:514:38)" "2018-11-07T14:42:17.380Z rewards: at Function.parse (apiscript.js:542:46)" "2018-11-07T14:42:17.380Z rewards: at Plugin.dispatchCommand (apiscript.js:2704:55)" "2018-11-07T14:42:17.380Z rewards: at Task.work.scheduleWork [as work] (apiscript.js:2679:26)" "2018-11-07T14:42:17.380Z rewards: at PromiseQueue.run (apiscript.js:2394:41)" "2018-11-07T14:42:17.381Z rewards: at PromiseQueue.update (apiscript.js:2456:22)" "2018-11-07T14:42:17.381Z rewards: at task.promise.then.catch.then (apiscript.js:2420:22)" This is an API script, and the line numbers are real ones from the script. &nbsp;In other words, it just loads whatever you put in the API script into a script host and calls it 'apiscript.js' instead of the name that you put in (booo!!!) &nbsp;but at least the line numbers are correct. With the sheet worker script, it seems to be doing something entirely different, like reading it from the file and then passing it into eval() somewhere in their own stuff? &nbsp; That would mean the line numbers of the "anonymous" frames are the real line numbers relative to the sheet worker script? &nbsp;So was it really in line 284? &nbsp;By the way, I am pretty sure the anonymous file with the incredibly long line is something like the underscore.js implementation being read in, which would contain the code they use for forEach emulation. &nbsp; Globbing it all together into incredibly long lines is exactly the sort of thing a web framework person would do... :)
Scott C. said: ... EDIT the 2nd: Yep, looks like emitTwo is from the Roll20 side of things, just ran the code provided adding those 4 objects defined elsewhere, and same error. You are able to repro the crash just using that little snippet? &nbsp; By installing it in your testing "sheet?"
1541602662

Edited 1541603072
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Ok, figured out what is going on. I have no idea why it's a problem though. The problem appears to be that you can't use const (or let for that matter) without first having a scope declared (e.g. a function wrapper). I have no idea why it doesn't just use the scope of what it's loaded into. The reason it is erroring on that line is that that is the first line where you try to add something to one of the const objects declared above. you can change the referenceError to be due to GROUPSTATS instead by changing that to a const as well. So, the fix is to wrap your entire worker in a module; I typically use the revealing module pattern, but a simple function declaration will do like so: &lt;script type='text/worker'&gt; var someFunction = function(){ const ATTRIBUTES = {}, SKILLS = {}, ENUMSTATS = [], TRACKERS = [], GROUPPREFIXES = ["g1", "g2", "g3", "g4", "g5", "g6", "g7", "g8", "g9"], GROUPATTRS = ["charname", "Hunger"], // **** GROUPATTRS defined here; error line is just below these declarations **** GROUPREPSECTIONS = ["rolls"], GROUPREPREFS = ["rollType", "trait1name", "trait1value", "trait2name", "trait2value", "rolldiff", "rollmod", "posflags", "negflags", "roll_params"], PROJREPSECTIONS = ["project"], PROJDATEDEPS = ["projectstartdate", "projectincnum", "projectincunit", "projectenddate", "projectinccounter", "projectrushpool"], PROJREPFLAGS = ["projectstartdate", "projectincnum", "projectincunit", "projectscope", "projectlaunchtrait1_name", "projectlaunchtrait1", "projectlaunchtrait2_name", "projectlaunchtrait2", "projectlaunchmod", "projectstake1_name", "projectstake1", "projectstake2_name", "projectstake2", "projectstake3_name", "projectstake3", "projectstake4_name", "projectstake4", "projectstake5_name", "projectstake5", "projectstake6_name", "projectstake6", "projectlaunchresults", "projectlaunchresultsmargin", "projectlaunchdiffmod", "projectwasrushed"], PROJREPATTRS = ["projectenddate", "projectinccounter", "projectscope_name", "projectlaunchdiff", "projectlaunchrollToggle", "projectlaunchroll_params", "projecttotalstake", "projectrushpool", "projectstakesatrush", "projectrushstakelost", "projectrushstakelosttogo"], //#endregion //#region Derivative Stats basicStats = _.flatten([_.values(ATTRIBUTES), _.values(SKILLS), ENUMSTATS, TRACKERS]), statFlags = _.map(_.omit(basicStats, TRACKERS), function (stat) { return stat + "_flag"; }), GROUPSTATS = {}; _.each(GROUPPREFIXES, function (prefix) { GROUPSTATS[prefix] = {attrList: [], repSections: [], repStats: []}; _.each(GROUPATTRS, function (attr) { // **** the line number complained about in the API console *** GROUPSTATS[prefix].attrList.push(prefix + attr); }); _.each(GROUPREPSECTIONS, function(sec) { GROUPSTATS[prefix].repSections.push(prefix + sec); }); _.each(GROUPREPREFS, function(stat) { GROUPSTATS[prefix].repStats.push(prefix + stat); }); }); on("change:currentdate", function (eventInfo) { console.log("&gt;&gt;&gt; DATE CHANGE DETECTED &gt;&gt;&gt;" + JSON.stringify(eventInfo)); return; }); } &lt;/script&gt; Ammo &nbsp;said: Not to gloat, but the many many tiny functions that come from working in a TypeScript framework do help with stack traces: That doesn't require the typescript framework though, I get the same behavior by simply coding in chunks of functions. As for the line numbers; they are accurate as long as that is the only/first script loaded into the API sandbox. All API scripts are concatenated into one long script so if you have 4 scripts, an error in your 4th script might reference line 20565, but actually only mean line 4 of itself. There's a pattern to fix this (and prevent the console from erroring), but you need to do try/catch and declare where the first line starts. You can see it at work in my PFCompanion script. But we're getting off topic from the OP. Ryan, can you see if currentdate now triggers the sheetworker on api set with this change?
1541603296

Edited 1541603337
Ammo
Pro
Nice work! &nbsp; Does Roll20 provide console.log in the context where it loads sheet workers? &nbsp;That certainly makes sense. PS: Thanks for sharing your knowledge, I didn't notice the scripts were concatenated, because I was testing in isolation mostly.
1541603515
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Ammo said: Nice work! &nbsp; Does Roll20 provide console.log in the context where it loads sheet workers? &nbsp;That certainly makes sense. PS: Thanks for sharing your knowledge, I didn't notice the scripts were concatenated, because I was testing in isolation mostly. Yep, console.log works for sheetworkers. Simply log() works in api scripts. As for the knowledge, I ain't nothing but a tyro. Just passing on what the community has taught me over the last 4-5 years or so. I'm sure that actual professional programmers look at my code and cringe ;)
Wow!&nbsp; Thanks a ton for all your work on this; unfortunately, I'm just about to head to work and I won't be back until this evening, when I'll review all of this and investigate everything you've suggested.&nbsp; In the meantime, I've pastebinned my whole sheetworker script.&nbsp; Warning:&nbsp; It's not going to be the most enjoyable read, as I'm just learning Javascript and, for example, wrote a whole suite of functions to calculate dates because I didn't know Javascript had a Date object ;)&nbsp;&nbsp; It's divided into #regions, so it might be easier to navigate if you paste it into Visual Studio (or something else that manages #regions) <a href="https://pastebin.com/t3iKC5tk" rel="nofollow">https://pastebin.com/t3iKC5tk</a>
Scott C. said: ... You can see it at work in my PFCompanion script. ... Thanks! &nbsp; Yes, it is off topic, but here is the code i just stole/adapted/improved? from you in case anyone else comes across this and wants to see. <a href="https://github.com/derammo/der20/commit/a9f488dd3f589f2271504892482e74024ce824de" rel="nofollow">https://github.com/derammo/der20/commit/a9f488dd3f589f2271504892482e74024ce824de</a>