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

Sheetworker on-change events not firing when changes are made within a routine called by sheet:opened event.

March 06 (6 years ago)

Edited March 06 (6 years ago)
Chris D.
Pro
Sheet Author
API Scripter
Compendium Curator

If you have a sheetworker routine that does stuff in the on-opened event, and that routine changes stuff, on-changed events are NOT generated for those changed things!

The problem is only seen when you have a function that runs calculations when the sheet is first opened. 

<!DOCTYPE html>
<meta charset="UTF-8">
<div class="user-root"> 
    <input name="attr_a" type="number"  value="1" style="width: 3em;" >
    <input name="attr_b" type="number"  value="1" style="width: 3em;" >
    <input name="attr_c" type="number"  value="1" style="width: 3em;" >
    <br>
    <input name="attr_r1" type="number" value="0"  style="width: 3em;" >
    <input name="attr_r2" type="number" value="0"  style="width: 3em;" >
</div>

<script type="text/worker">

    var calculateR1 =  function () {
        'use strict';
        getAttrs(["a", "b" ], function gar1(values) {
            'use strict';
            let vals = {};
            vals[ "r1"] = parseInt(values[ "a"]) + parseInt( values[ "b"]);
log( "R1: a = " + values["a"]);    log( "b = " + values["b"]);    log( "r1 = " + vals["r1"]);
            setAttrs( vals);
        });
    }; 

    var calculateR2 =  function () {
        'use strict';
        getAttrs(["c", "r1" ], function gar1(values) {
            'use strict';
            let vals = {};
            vals[ "r2"] = parseInt(values[ "c"]) + parseInt( values[ "r1"]);
log( "r2: c = " + values["c"]);        log( "r1 = " + values["r1"]);        log( "r2 = " + vals["r2"]);
            setAttrs( vals);
        });
    }; 


    on("change:a change:b", function () {
        calculateR1();
    });
    on("change:c change:r1", function () {
        calculateR2();
    });

    on('sheet:opened',function fnOnSheetOpened(){
        'use strict';
log( "sheet opened.");
        calculateR1();
    });
</script>

When the sheet is opened for the first time, it is supposed to do all the calculations. Now I knew that because of asynchronous issues, R1 is not going to be correct if calculateR2 is run while calculateR1 is still being processed, so I can't just put calculateR1() and calculateR2() both in the sheet:opened event.

But I trusted that when R1 was actually written out, it would generate the event that would cause calculateR2 to run. It is not. 

I don't want to have calculateR1 call calculateR2 directly, because then it would be called twice in every other circumstance! So I don't really know how to work around this. It seems like every solution I try ether has it sometimes not being called, or sometimes being called twice. 


Using Windows 10 and latest version of chrome. 

We're sorry to hear that you are experiencing issues with this.

Please carefully work through to the first three steps of our guide to Solving Technical Issues:

Step 1: Make sure to use the right browser

           - Please check if these issues persist when using both Chrome and Firefox.

Step 2: Ensure that there are no extensions/addons interfering with Roll20

           - Please disable all add-ons/extensions.

Step 3: Clear your cache

If steps 1-3 does not resolve your issue, please work through step 4 and provide us with that information.

March 06 (6 years ago)

Edited March 06 (6 years ago)
Chris D.
Pro
Sheet Author
API Scripter
Compendium Curator

Using Windows 10 and version Version 72.0.3626.121 (Official Build) (64-bit) of chrome. I don't have firefox installed so have  not tested it on that. 

I have very few extensions and have disabled them all for this test. 

I have cleared my cash. 

Javascript is installed. I am not running any API scripts in this test. 

AntiVirus is Windows defender. I also usually run Avast online security and pop-up blocker pro but these extensions and all others have been disabled.


The html is exactly like it is in my top post. 

I cleared the console log and opened a character sheet. 

sheet opened.
sheetsandboxworker.js?1551864188123:120 R1: a = 1
sheetsandboxworker.js?1551864188123:120 b = 1
sheetsandboxworker.js?1551864188123:120 r1 = 2
app.js?1551283991:545 Do refresh link cache!
app.js?1551283991:551 Really updating character sheet values
app.js?1551283991:551 Setting up repeating sections took until 0ms
app.js?1551283991:551 Updating ALL VALUES
app.js?1551283991:551 Finding list of dirty attributes took until 1ms
app.js?1551283991:551 Querytest took until 1ms
app.js?1551283991:551 Attribute cache compliation took until 1ms
app.js?1551283991:551 Set values (including auto-calcuating variables) took until 2ms
app.js?1551283991:551 Appending to screen took until 2ms
app.js?1551283991:551 Took 2ms
app.js?1551283991:559 Refresh Journal List!
app.js?1551283991:559 Search took 10ms

As you can see from this console log,  calculateR1(); is run (it logs values for a, b, and r1), but on("change:c change:r1" never fires to run calculateR2()  (we see no log entries from that routine);

If I then change field 'a', 

app.js?1551283991:551 Really updating character sheet values
app.js?1551283991:551 Setting up repeating sections took until 0ms
app.js?1551283991:551 Finding list of dirty attributes took until 1ms
app.js?1551283991:551 Querytest took until 2ms
app.js?1551283991:551 Attribute cache compliation took until 2ms
app.js?1551283991:551 Set values (including auto-calcuating variables) took until 2ms
app.js?1551283991:551 Took 3ms
sheetsandboxworker.js?1551864188123:120 R1: a = 2
sheetsandboxworker.js?1551864188123:120 b = 1
sheetsandboxworker.js?1551864188123:120 r1 = 3
app.js?1551283991:551 Really updating character sheet values
app.js?1551283991:551 Setting up repeating sections took until 1ms
app.js?1551283991:551 Finding list of dirty attributes took until 1ms
app.js?1551283991:551 Querytest took until 2ms
app.js?1551283991:551 Attribute cache compliation took until 2ms
app.js?1551283991:551 Set values (including auto-calcuating variables) took until 2ms
app.js?1551283991:551 Took 3ms
sheetsandboxworker.js?1551864188123:120 r2: c = 1
sheetsandboxworker.js?1551864188123:120 r1 = 3
sheetsandboxworker.js?1551864188123:120 r2 = 4
app.js?1551283991:551 Really updating character sheet values
app.js?1551283991:551 Setting up repeating sections took until 0ms
app.js?1551283991:551 Finding list of dirty attributes took until 0ms
app.js?1551283991:551 Querytest took until 1ms
app.js?1551283991:551 Attribute cache compliation took until 1ms
app.js?1551283991:551 Set values (including auto-calcuating variables) took until 1ms
app.js?1551283991:551 Took 2ms

the on:change event for a fires (we see the log entries it generates), r1 is updated, and this causes event on:change r1 to fire which calculates r2 (and we see the log entries it generates). This is how it should be, but this is also how it should be if r1 is updated during the sheet:open event. 


So once again, if event sheet:open  causes value r1 to be set, the on:change r1 event does not fire. Even though it does work if on:change a causes value r1 to be set. 

March 06 (6 years ago)
The Aaron
Roll20 Production Team
API Scripter

As a work around, try deferring the calculate:

    on('sheet:opened',function fnOnSheetOpened(){
        'use strict';
log( "sheet opened.");
        setTimeout(calculateR1,100);
    });

Probably the event handling it’s set up properly when sheet:opened is issued. 

March 06 (6 years ago)
Chris D.
Pro
Sheet Author
API Scripter
Compendium Curator

Very interesting. 

That seemed like a very great idea, but I got an error 

sheetsandboxworker.js?1551914506929:152 Character Sheet Error: Trying to do getAttrs when no character is active in sandbox.

so I tried 

    on('sheet:opened',function fnOnSheetOpened(){
        'use strict';
log( "sheet opened.");
        calculateR1();
        setTimeout( function () { log( "timeout."); calculateR1();}, 1000);
    });

and got. 

sheet opened.
sheetsandboxworker.js?1551914506929:120 R1: a = 1
sheetsandboxworker.js?1551914506929:120 b = 1
sheetsandboxworker.js?1551914506929:120 r1 = 2
app.js?1551283991:545 Do refresh link cache!
app.js?1551283991:551 Really updating character sheet values
app.js?1551283991:551 Setting up repeating sections took until 0ms
app.js?1551283991:551 Updating ALL VALUES
app.js?1551283991:551 Finding list of dirty attributes took until 1ms
app.js?1551283991:551 Querytest took until 2ms
app.js?1551283991:551 Attribute cache compliation took until 2ms
app.js?1551283991:551 Set values (including auto-calcuating variables) took until 3ms
app.js?1551283991:551 Appending to screen took until 4ms
app.js?1551283991:551 Took 4ms
app.js?1551283991:559 Refresh Journal List!
app.js?1551283991:559 Search took 14ms
sheetsandboxworker.js?1551914506929:120 timeout.
sheetsandboxworker.js?1551914506929:152 Character Sheet Error: Trying to do getAttrs when no character is active in sandbox.

So as you can see, while sheet:open is actually running, calculateR1() can be run and works fine, excepting that no on:change events fire. However if you set a timeout (and I tried this with several values from 100ms up to 5000ms), it always said no character is active in sandbox. Obviously I did not close the character or do anything at all between creating the character and the timeout expiring. 

Also, this is not a function of the character being created for the first time. I get the exact same results when reopening a character. 


So... bizarreness. But thanks for a very great idea Aaron.  


March 07 (6 years ago)
The Aaron
Roll20 Production Team
API Scripter

Ah, that makes unfortunate sense. It looses the context of the character in the new callstack created when the timeout expires. :(

Hi Chris, 

I went ahead and forwarded this over to our devs.

Thanks!

March 11 (6 years ago)
Drespar
Roll20 Team

Hi everyone,

This issue has been submitted to the dev team for resolution. Thank you for catching this!

March 11 (6 years ago)

Javascript onChange events are not triggered by changes made programmatically. You may be able to achieve the desired result by using a .trigger to activate the event.

More information on events can be found here: https://api.jquery.com/on/#on-events-selector-data-handler

March 11 (6 years ago)
The Aaron
Roll20 Production Team
API Scripter

Can we use jQuery in sheet workers?

March 12 (6 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Nope, only javascript, just like the API. Sheetworkers have no direct interaction with the DOM; only through the defined sheetworker functions.

March 12 (6 years ago)

Edited March 12 (6 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Shawn C. said:

Javascript onChange events are not triggered by changes made programmatically. You may be able to achieve the desired result by using a .trigger to activate the event.

More information on events can be found here: https://api.jquery.com/on/#on-events-selector-data-handler

This is not actually how the sheetworker environment works; I hadn't seen this response and Aaron's response makes more sense now that I have.

setAttrs({someAttribute:'SomeValue'});

will trigger the following once the sheet is opened:

on('change:someAttribute',(event)=>{
    console.log('look mah, programmatic change triggering');
});

The bug being reported here is that changes made during a sheet:opened event do not do this like they should.