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

Custom parse in repeating section

I have an action button that does a custom parse. It works great, but when I try to put it into a repeating section, it does not work. The relevant parts are as follows: <fieldset class="repeating_skills">     <input type="number" name="attr_skill" value="2"/>     Modifier:     <input type="number" name="attr_Modifier" value="0"/>     Effect die:     <input type="number" name="attr_effectDie" value="4"/>     <button type="action" name="act_skillRoll">Click me</button> </fieldset> with the following sheetworker: <script type="text/worker">     on('clicked:repeating_skills:skillRoll', (eventInfo) => {         getAttrs(["repeating_skills_skill","repeating_skills_Modifier"], function(values){             var sk=parseInt(values.repeating_skills_skill)             var mod=parseInt(values.repeating_skills_Modifier)             var net=sk+mod             if(net>-1){                 startRoll("&{template:check} {{name=Test}} {{effect=[[@{effectDie}]]}} {{Skill=@{skill}}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[(3+abs(@{skill}+@{Modifier}))]]]]t[Success_Dice]}k3]]]]}} {{result=$[[4]]}}", (results) => {                              finishRoll(                         results.rollId,{}                     );                 });             }else             {                 startRoll("&{template:check} {{name=Test}} {{effect=[[@{effectDie}]]}} {{Skill=@{skill}}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[(3+abs(@{skill}+@{Modifier}))]]]]t[Success_Dice]}kl3]]]]}}", (results) => {                              finishRoll(                         results.rollId,{}                     );                 });                              }         });     }); </script>
1645361060

Edited 1645361124
GiGs
Pro
Sheet Author
API Scripter
Not related to your problem, in programming you generally want to reduce duplication as much as possible. The if statement and CRP could be better writtten as below (basically construct what is different first, and have the code for the functions that follow just once):         let roll_text = "&{template:check} {{name=Test}} {{effect=[[@{effectDie}]]}} {{Skill=@{skill}}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[(3+abs(@{skill}+@{Modifier}))]]]]t[Success_Dice]}kl3]]]]}}" ;         if ( net >- 1 ){             roll_text += " {{result=$[[4]]}}" ;         }         startRoll ( roll_text , ( results ) => {                     finishRoll (                 results . rollId ,{}             );         });
Thanks. The "{{result=$[[4]]}}" should actually be on both - one roll keeps the highest 3 and the other keeps the lowest 3. That said, I can still shorten things a bit with that trick.
1645361770
GiGs
Pro
Sheet Author
API Scripter
Okay, on to your problem. I'm guessing here that the issue your roll_text doesnt have repeating section attributes. In a macro in repeating section, you dont have to inckude the repeating section name and row id, because it is run within the section, and roll20 automatically adds them. For custom roll parsing, it may be that roll20 doesnt work like that, and you need to supply the repeating section name and row index. There's multiple ways to get it, but for this function it might be easiest to use getAttrs, since you are getting those values already. This might work: on ( 'clicked:repeating_skills:skillRoll' , ( eventInfo ) => {             getAttrs ([ "repeating_skills_skill" , "repeating_skills_Modifier" , "repeating_skills_effectDie" ], function ( values ) {                 var sk = parseInt ( values . repeating_skills_skill );                 var mod = parseInt ( values . repeating_skills_Modifier );                 var die = values . repeating_skills_effectDie ;                 var net = sk + mod                 var roll_text = `&{template:check} {{name=Test}} {{effect=[[ ${ die } ]]}} {{Skill= ${ sk } }} {{Modifier=[[ ${ mod } ]]}} {{roll1=[[[[{[[[[(3+abs( ${ sk } + ${ mod } ))]]]]t[Success_Dice]}kl3]]]]}}` ;                 if ( net > - 1 ) {                     roll_text += " {{result=$[[4]]}}" ;                 }                 startRoll ( roll_text , ( results ) => {                     finishRoll (                         results . rollId , {}                     );                 });             });         }); In this code I'd edited the roll_text to include the actual values for repeating_skills_skill and modifier, and added effectDie. If used template literal syntax: when you create a string variable with ` ` quotes (those are not " or ' quotes), you can include variables and other code inside ${ } and they will be calculated and included as if they were strings.
So more like this then: on('clicked:repeating_skills:skillRoll', function(eventInfo) => { getAttrs(["repeating_skills_skill","repeating_skills_Modifier"], function(values){ var sk=parseInt(values.repeating_skills_skill) var mod=parseInt(values.repeating_skills_Modifier) var net=sk+mod let roll_text = "&{template:check} {{name=Test}} {{effect=[[@{effectDie}]]}} {{Skill=@{skill}}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[(3+abs(@{skill}+@{Modifier}))]]]]t[Success_Dice]}k"; if(net>-1){ roll_text += "l" } roll_text +="3]]]]}} {{result=$[[4]]}}" startRoll(roll_text, (results) => { finishRoll( results.rollId,{} ); }); });
1645362049
GiGs
Pro
Sheet Author
API Scripter
Final thoughts: You have a lot of inline brackets in this bit: {{roll1=[[[[{[[[[(3+abs( ${ sk } + ${ mod } ))]]]]t[Success_Dice]}kl3]]]]}} Wouldnt this work? {{roll1=[[{[[3+abs( ${ sk } + ${ mod } )]]t[Success_Dice]}kl3]]}} Maybe something to do with your table roll?
1645362579
GiGs
Pro
Sheet Author
API Scripter
Sorry, I didnt see you were replying as I was posting. Randall S. said: So more like this then: on('clicked:repeating_skills:skillRoll', function(eventInfo) => { getAttrs(["repeating_skills_skill","repeating_skills_Modifier"], function(values){ var sk=parseInt(values.repeating_skills_skill) var mod=parseInt(values.repeating_skills_Modifier) var net=sk+mod let roll_text = "&{template:check} {{name=Test}} {{effect=[[@{effectDie}]]}} {{Skill=@{skill}}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[(3+abs(@{skill}+@{Modifier}))]]]]t[Success_Dice]}k"; if(net>-1){ roll_text += "l" } roll_text +="3]]]]}} {{result=$[[4]]}}" startRoll(roll_text, (results) => { finishRoll( results.rollId,{} ); }); }); It looks like that would mangle roll1 a lot. Something to be aware of is you can use if(something) {     // do something when something is true } else {     // do a different then if something is not true } so you can build your string accounting for both possibilities.
I am including an api chat button in the result, and for some reason it does not work unless I put in the extra brackets.
1645364405
GiGs
Pro
Sheet Author
API Scripter
That sounds familiar, I remember some mention of needing extra brackets in some situations involving rolltables.
1645364407

Edited 1645364896
With the modifications you suggested, I have:     on('clicked:repeating_skills:skillRoll', (eventInfo) => {         getAttrs(["repeating_skills_skill","repeating_skills_Modifier","repeating_skills_effectDie"], function(values){             var sk=parseInt(values.repeating_skills_skill)             var mod=parseInt(values.repeating_skills_Modifier)             var die=parseInt(values.repeating_skills_effectDie)             var net=sk+mod             var roll_text = `&{template:check} {{name=Test}} {{effect=[[${die}]]}} {{Skill=${sk}}} {{Modifier=[[${mod}]]}} {{roll1=[[[[{[[[[(3+abs(${sk}+${mod}))]]]]t[Success_Dice]}k`             if(net<0){                 roll_text +="l"             }             roll_text +="3]]]]}} {{result=$[[4]]}}"             startRoll(roll_text, (results) => {                 finishRoll(                     results.rollId,{}                 );             });         });     }); It still doesn't work. If I take out the repeating section it works fine.
If I could take out the brackets, it would be easier, but then when you click the api button, it translates the result as something like "0,+1,+-1,+2}k3" instead of "3" and it can't do any math or dice rolling with the result. That's why I have the {{result=$[[4]]}} to retrieve the roll with the tootltip that I lose with the extra bracket.
Do I need to somehow include the rowId in this to get it to work?
I found this: "Note that when starting a roll via the startRoll sheet worker, the system will not be able to automatically add the correct repeating section id, and you will need to fully resolve the attribute name [Click Here](~repeating_test_-MckIineUhDw8UwVpy-z_test1)." But I don't know how to resolve said attribute name.
1645369204

Edited 1645369319
GiGs
Pro
Sheet Author
API Scripter
You shouldnt need to include the repeating attribute name. In the change to roll_text I made, I removed all references to attributes, and instead entered their values directly, which you got from getAttrs. That was specifically to bypass this problem. I would suggest replacing roll_text with something as simple as possible, removie the table call for example, just to test where the process is failing. Right ow you have several things that could be failing. Maybe just: var roll_text = '&{template:check} {{name=Test}}' At the moment we cant test it ourselves so we are guessing. You might post the rolltable contents and the rolltemplate html and css, so we can try it out ourselves.
1645369883

Edited 1645370330
GiGs
Pro
Sheet Author
API Scripter
Another thought has occurred to me: why are using custom roll parsing for this? You dont perform any calculations in startRoll, so it seems like you could replace that whole sheet worker with a roll button. Maybe have a worker to contruct the roll text, like this: on ( 'change:repeating_skills:skill change:repeating_skills:modifier' , ( eventInfo ) => {             getAttrs ([ "repeating_skills_skill" , "repeating_skills_Modifier" ], function ( values ){                 var sk = parseInt ( values . repeating_skills_skill )                 var mod = parseInt ( values . repeating_skills_Modifier )                 var net = sk + mod                 var roll_text = `&{template:check} {{name=Test}} {{effect=[[effectDie]]}} {{Skill=@{skill}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[3+abs(@{skill}+@{Modifier})]]]]t[Success_Dice]}k`                 if ( net < 0 ){                     roll_text += "l"                 }                 roll_text += "3]]]]}} {{result=$[[4]]}}"                 setAttrs ({                     rolltext : roll_text                 })             });         }); Then update your html like < fieldset class = "repeating_skills" >         < input type = "number" name = "attr_skill" value = "2" />         Modifier:         < input type = "number" name = "attr_Modifier" value = "0" />         Effect die:         < input type = "number" name = "attr_effectDie" value = "4" >         <input type = "hidden" name = "attr_rolltext" value = "" >         < button type = "roll" name = "roll_skillRoll" value = "@{rolltext}" > Click me </ button >     </ fieldset > In this way, you avoid the problem of using action buttons - the roll button will make the roll and use the correct attributes. You build the rolltext based on the skill and modifier attributes . But I'd test with a very simply roll first, just to make sure the javascript and html is working, so you can then look at the button value.
That did the trick. Thank you! I guess I was just making this harder than it needed to be.
1645371350

Edited 1645371476
Only problem is that, after you change anything on the repeating section, you have to click somewhere else to make the change real before the button updates. If you change the modifier and then click the roll button, it rolls using the old modifier. (edit) actually it does update, but it still makes the if then choice based on the old value.
1645372282

Edited 1645372334
GiGs
Pro
Sheet Author
API Scripter
Something is going wrong there, I'd check the code. It should be updating immediately you change the modifier or skill value. Possibly also create a new character sheet and test with that. I find when creating character sheets, the character I'm working often gets corrupted after a bunch of changes.
I tried creating a new character sheet and even a new campaign - still have the same issue. If the modifier+skill =0 and I change the m so they are less than zero, it rolls with the new value, but does not trigger the "net<0" condition. If I click on the button again without changing anything, it rolls correctly. It seems like it is updating, but making the evaluation for the if statement based on the previous value.
1645375146
GiGs
Pro
Sheet Author
API Scripter
Just to be clear, are you using < correctly? In javascript, < means "less than", not "equal to or less then". If you want to use "less than or equal" you need to put <= . If that's not the issue, can you post the entire sheet code (html and css) on gist.github.com or pastebin.com, and I'll try to figure out what's up.
1645375490

Edited 1645375524
The code is: HTML CSS
1645397048
GiGs
Pro
Sheet Author
API Scripter
I didnt have the necessary table so it wouldnt run for me. I changed the sheet worker to this: on('change:repeating_skills:skill change:repeating_skills:modifier', (eventInfo) => {             getAttrs(["repeating_skills_skill","repeating_skills_Modifier"], function(values){                 var sk=parseInt(values.repeating_skills_skill)                 var mod=parseInt(values.repeating_skills_Modifier)                 var net=sk+mod                 console.log(`net: ${net}`);                 var roll_text = `&{template:check} {{name=Test}}`                 setAttrs({                     repeating_skills_rolltext: roll_text                 })             });         }); So it prints to the console what net is every time i click the roll button, and it is properly updated with the correct value. You can see the conole by rightclicking any element, selecting Inspect or Inspect Element, and then in the frame that appears, click the console tab.
The table just generates a number from -3 to +3 that is weighted. The calculation in the marco "{[[[[(3+abs(@{skill}+@{Modifier}" is being done correctly, but the sheetworker calculation:                if(net<0){                     roll_text += "l";                 } seems to be using the previous value. until I click on any part of the repeating section. So if I change the modifier and then click the button, it gives the wrong result. If I click the button again, it then generates the correct result. If I change the modifier and then click anywhere else on the sheet before clicking on the button, it also gives the correct result. It seems to be a problem with the repeating section updating. From issues I have had creating rows, I know there is some kind of discrepancy between when changes are made to repeating sections and when they become real. If you create a new row, for instance, and you don't change anything in that row, it disappears as soon as you do anything to update the section. I think my solution will be to hide the roll button in a div that can only be revealed by clicking on it, which will automatically update the row.
1645405404
GiGs
Pro
Sheet Author
API Scripter
The test I did is showing that the net variable is being updated at the correct time, so it's a puzzle.
1645406029
GiGs
Pro
Sheet Author
API Scripter
Okay, I tried it again, changing the roll_text to test the if directly: on('change:repeating_skills:skill change:repeating_skills:modifier sheet:opened', (eventInfo) => {             getAttrs(["repeating_skills_skill","repeating_skills_Modifier"], function(values){                 var sk=parseInt(values.repeating_skills_skill)                 var mod=parseInt(values.repeating_skills_Modifier)                 var net=sk+mod                 console.log(`net: ${net}`);                 var roll_text = `k`;                 if(net<0){                     roll_text += "l";                 }                                 setAttrs({                     repeating_skills_rolltext: roll_text                 })             });         }); So here, if net is below 0, and click the button, it'll print out kl , and if 0 or above, it'll print out k. This models the change you want to see and it works perfectly. So if the code is being updated exactly when it needs to be. However, it occurred to me that if you are changing the code, and reopening the sheet, values might be properly updated right then. So I added sheet:opened to the change line - it's a good idea to add this if you are adding this code to a sheet thats already in use.
1645407905

Edited 1645407931
GiGs
Pro
Sheet Author
API Scripter
One thing I noticed - the hidden roll_text attribute definitely needs a default value set. I wonder if this is your issue. This: <input type="hidden" name="attr_rolltext" value=""> should be <input type="hidden" name="attr_rolltext" value=" &{template:check} {{name=Test}} {{effect=[[effectDie]]}} {{Skill=@{skill}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[3+abs(@{skill}+@{Modifier})]]]]t[Success_Dice]}k 3]]]]}} {{result=$[[4]]}} "> So that a default value is set when the row is initially created.
1645610310

Edited 1645610408
After abnging my head against this, I think I figured out what the problem is.The only thing the sheetworker is changing is whether it is "k3" or "kl3". All the values are being calculated correctly. The new string is then sent to the rolltext input, but that field doesn't actually update until something else is clicked. If I change the html like so:     <fieldset class="repeating_skills">         <div class="f">             <input type="number" name="attr_skill" value="2"/>             Modifier:             <input type="number" name="attr_Modifier" value="0"/>             Effect die:             <input type="number" name="attr_effectDie" value="4"/>             <input type="text" name="attr_rolltext" value=""/>             <button type="roll" name="roll_skillRoll" value="&{template:check} {{name=Test}} {{effect=[[@{effectDie}]]}} {{Skill=@{skill}}} {{Modifier=[[@{Modifier}]]}} {{roll1=[[[[{[[[[(3+abs(@{skill}+@{Modifier}))]]]]t[Success_Dice]}k@{rolltext}3]]]]}} {{result=$[[4]]}}"></button>         </div>     </fieldset> and change the sheet worker to:     on('change:repeating_skills:skill change:repeating_skills:modifier', (eventInfo) => {             getAttrs(["repeating_skills_skill","repeating_skills_Modifier"], function(values){                 var sk=parseInt(values.repeating_skills_skill)                 var mod=parseInt(values.repeating_skills_Modifier)                 var net=sk+mod                 var roll_text = ``;                 if(net<0){                     roll_text = "l";                 }                 setAttrs({                     repeating_skills_rolltext: roll_text                 })             });         }); The problem becomes apparent. When you change the modifier field, you can see that the rolltext field does not change until the modifier field loses focus and the row updates.
1645623002
GiGs
Pro
Sheet Author
API Scripter
In the code I tried above, the k and kl values were changing instantly, so I don't know why that isnt working for you. Was it specifically the modifier value that wasnt triggering changes, and not the skill value/
It is both. They do change, but not  until I click off the field. If you manually type in the change and hit enter or tab, it works, but if you change the number with the spinners, it does not. It is weird because it only causes an issue when you change the number and immediately click the button without first clicking off the field that was changed. It then gives the wrong rol, but then immediately updates the rolltext field to the correct value. It looks like the button click event is triggering before the field loses focus and updates. Regardless, I dealt with it by putting the button in a div that is hidden until a control is clicked. Since clicking anywhere on the row updates it, this fixes the issue.
1645635709
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
This is just how Roll20 character sheets work. The change events that the sheet runs off of are actually blur events (e.g. the input loses focus). There's unfortunately no way around this issue that I'm aware of.
1645641484
GiGs
Pro
Sheet Author
API Scripter
Randall S. said: It is both. They do change, but not  until I click off the field. Aha, that clears up the confusion. As Scott says, there's no way around this - it's just the way roll20 works. It was so natural to me to do that, I wasnt doing it without thinking about it.
It's good anyway. Hiding the controls this way makes the sheet look cleaner anyway. I was just curious as to why it wasn't updating.