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

relative Newb seeking help

I have seen sheets where an array is used with an on(change) event for a group of related attributes, skills etc. All the examples i have found have been quite complex and i have got lost trying to follow the logic.  my code; ['wit','wil','str','dft','spd','hlh'].forEach(attr => { on('change:${attr}', (info) => {  getAttrs(['${attr}'], function(v) { setAttrs({ ${attr}ST: Math.floor((parseInt(v.${attr})||0)/2), ${attr}ST_max: Math.round((parseInt(v.${attr})||0)/3), ${attr}Grp: attrGroup((parseInt(v.${attr})||0)), ${attr}Grp_max: attrED((parseInt(v.${attr})||0)) }); }); }); }); This doesn't work, but hopefully somone can see what im trying to do and point me to where i can find the answers on how to do this. I really want to understand the process, but not even sure what this is called to do proper searching to figure it out.
1701792717

Edited 1701797959
GiGs
Pro
Sheet Author
API Scripter
You are using the wrong type of quote. This construction: 'change:${attr}' is called a template literal, and you need to use backticks ` here (on most keyboards, these quotes are at the left of the number 1 key at the top of your keyboard) If you're using a normal quote, either ' or ", the contents are read exactly as printed, complete with ${ } as characters in the quote. If on the other hand, you use backticks, like so `change:${attr}` The ${ } part is seen as code, which says "treat whatever is inside { } as code, and complete that then build a string using it. (This is why template literals as so powerful - they allow you include javascript inside the string which is then run as code and not simply copied and printed). Your total code should probably look like this: ['wit','wil','str','dft','spd','hlh'].forEach(attr => { on(`change:${attr}`, (info) => {  getAttrs([`${attr}`], function(v) { setAttrs({ [`${attr}ST`]: Math.floor((parseInt(v[attr])||0)/2), [`${attr}ST_max`]: Math.round((parseInt(v[attr])||0)/3), [`${attr}Grp`]: attrGroup(parseInt(v[attr])||0), [`${attr}Grp_max`]: attrED(parseInt(v[attr])||0) }); }); }); }); in the above code, attrGroup and attrED are separate functions, so if there's an error in those, the code might not run proerly. Note that the getAttrs line can be written like that, but could also remove the template literal and be: getAttrs([attr], function(v) {
1701792872

Edited 1701797991
GiGs
Pro
Sheet Author
API Scripter
The template literal syntax can be replaced with the older strong concatenation, which would look like this: ['wit','wil','str','dft','spd','hlh'].forEach(attr => { on('change:' + attr, (info) => {  getAttrs([attr], function(v) { setAttrs({ [attr + 'ST']: Math.floor((parseInt(v[attr])||0)/2), [attr + 'ST_max']: Math.round((parseInt(v[attr])||0)/3), [attr + 'Grp']: attrGroup(parseInt(v[attr])||0), [attr + 'Grp_max']: attrED(parseInt(v[attr])||0) }); }); }); });
1701793256

Edited 1701798042
GiGs
Pro
Sheet Author
API Scripter
There were a lot of syntax errors here, and they weren't all do to do with template literals. The parseInt errors were due to misunderstanding of javascript variable syntax - you can use the v.attr syntaxx when attr is exactly the name of an attribute, but if it's a variable you have to use v[attr] syntax. And in setAttrs, you have to use the [ ] syntax again, if you are referring to a variable. This tells javascript to construct that variable and place it here. Since you asked for a googlable term, one problem is with Template literal Suntx, another is with Javascript Object synatx, and another is with Javascribe Variable syntax. I don't know if that will lead you to all of them, but it should get you started. And yes, this is very complex stuff!
1701794344

Edited 1701798076
GiGs
Pro
Sheet Author
API Scripter
I personally would not do this: setAttrs({ [`${attr}ST`]: Math.floor((parseInt(v[attr])||0)/2), [`${attr}ST_max`]: Math.round((parseInt(v[attr])||0)/3), [`${attr}Grp`]: attrGroup(parseInt(v[attr])||0), [`${attr}Grp_max`]: attrED(parseInt(v[attr])||0) }); That's running code inside the setAttrs, which make it hard to interrogate. I'd do something like this: const attr_ST = Math.floor((parseInt(v[attr])||0)/2); const attr_Max = Math.round((parseInt(v[attr])||0)/3); const f1 = attrGroup(parseInt(v[attr])||0); const f2 = attrED(parseInt(v[attr])||0); setAttrs({ [`${attr}ST`]: attr_ST, [`${attr}ST_max`]: attr_Max, [`${attr}Grp`]: f1, [`${attr}Grp_max`]: f2 }); By putting those values inside a variable, I can then investigate their values with console.log, like so const attr_ST = Math.floor((parseInt(v[attr])||0)/2); const attr_Max = Math.round((parseInt(v[attr])||0)/3); const f1 = attrGroup(parseInt(v[attr])||0); const f2 = attrED(parseInt(v[attr])||0); console.log({attr_ST, attr_Max, f1, f2}); I can then print them out to the console and see whether they have the values I expect them to (and remove the console.log part later). This enables a lot of debugging approaches which aren't there in the original construction.
1701797932

Edited 1701798085
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
GiGs has hit pretty much everything, the only piece I'd change would be the setAttrs. I'm a fan of using an object to store changes and then sending that object to setAttrs. It allows you to log results for debugging, but doesn't require as many extra variable declarations: const setobj = {};//empty object where we'll store our changes to be made // Store changes in the setObj setobj[`${attr}ST`] = Math.floor((parseInt(v[attr])||0)/2); setobj[`${attr}ST_max`] = Math.round((parseInt(v[attr])||0)/3); setobj[`${attr}Grp`] = attrGroup(parseInt(v[attr])||0); setobj[`${attr}Grp_max`] = attrED(parseInt(v[attr])||0); // apply changes setAttrs(setObj); This probably doesn't seem that different in this instance, but if you ever have logic that determines what attribute is being set, you can use this same setup and not have to do anything complicated to have a dynamic set. Something like this: const setobj = {};//empty object where we'll store our changes to be made // Store changes in the setObj setobj[`${attr}ST`] = Math.floor((parseInt(v[attr])||0)/2); setobj[`${attr}ST_max`] = Math.round((parseInt(v[attr])||0)/3); setobj[`${attr}Grp`] = attrGroup(parseInt(v[attr])||0); setobj[`${attr}Grp_max`] = attrED(parseInt(v[attr])||0); if(attr === 'wit'){ setObj[`${attr}_dependent_attribute`] = 'something that should only be set when wit changes'; } // apply changes setAttrs(setObj); Consider how you'd do that without having the setObj . You'd either need another setAttr  call inside the if (which isn't ideal), or you'd need more logic that would be reasonably complex to conditionally apply that change to the final setAttrs . And I'm a proponent of using the same overall code architecture throughout code as it makes reading and troubleshooting the code easier if you don't have to change the way you're thinking about your code depending on what function you are in. Another benefit of using this even when it isn't needed is that if you later decide you do need a conditional set, it's easier to add.
1701798281
GiGs
Pro
Sheet Author
API Scripter
I'd agree, I'd normally use an object too, but... I think for newbies who don't understand javascript objects its better tpo use separate variables. Also we can't tell if those function calls will work properly, and it's easier to identify problems there (while stumbling around with only a limited idea of what you're ding) if we use individual variables Object variables are great, but I think they are best recommended when you know you already understand them.
1701799427

Edited 1701807263
Thanks for all the advice, plenty to think about there. II have done object orientated programming in various languages before, just a newbie to roll20 character sheet quirks. So in for penny.... I might as well get to learning about the objects mentioned. just trying to learn this as  a way to keep my mind occupied, so i'm not sitting in front of the TV watching junk. I love these forums where there is always someone willing to help us newbies learn stuff.
1701807581

Edited 1701810128
is there a way to bring another related attribute over using the getAttrs something like ['cha', 'cbt', 'com', 'est', 'mec', 'nat', 'sci'].forEach(attr => { on(`change:${attr}`, (info) => {  getAttrs([`${attr}`, `${attr}_max`], function(v) { const base = parseInt(v[attr])||0; const aMax = parseInt(v[attr_max])||0; This gives a syntax error (unsurprisingly) and after trying variations the closest i got was and error stating attr_max is not defined
1701807859
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Martin said: is there a way to bring another related attribute over using the getAttrs something like ['cha', 'cbt', 'com', 'est', 'mec', 'nat', 'sci'].forEach(attr => { on(`change:${attr}, (info) => {  getAttrs([`${attr}`, `${attr}_max`] function(v) { const base = parseInt(v[attr])||0; const aMax = parseInt(v[attr_max])||0; This gives a syntax error (unsurprisingly) and after trying variations the closest i got was and error stating attr_max is not defined Yes, you just need to assemble the full attribute name just like I did in the setObj demonstration. so v[attr_max]  should be v[`${attr}_max`] .