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

adding a new element with setAttr() and sheet-worker event

1587730161

Edited 1587732838
for a custom sheet, I added the possibility to drop from the compendium I make a copy in the correct block of the sheet ( repeating block for the most part ) But when I use setAttr() to add a new element to a repeating node foo the event on("change:foo remove:foo", () =>{}); don't triggered If I manually change an input of the new added element, or remove an another element, the previous event is triggered as usual. I missed something or its a missing functionnality ?
1587743109
GiGs
Pro
Sheet Author
API Scripter
I'm not following the issue exactly - some code would be handy.
1587746042

Edited 1587800199
an example, I have 2 repeating block, one for the inventory, an another as a deposit, I add a button to send an item to export item between this two block, and a input to show the weight value. for the HTML code I have : <script data-type="text/worker">     on( "sheet:opened", () => {         equipment_weight();     });     // calculate the weight of the equipment     on( "change:repeating_equipment:equipment_weight change:repeating_equipment:equipment_quantity remove:repeating_equipment", equipment_weight );     function equipment_weight() {         getAttrsRepeating("equipment", ["equipment_weight", "equipment_quantity"], (user_repeating) => {             let sum = 0;             Object.keys(user_repeating).forEach(id => {                sum += user_repeating[id]["equipment_weight"] * user_repeating[id]["equipment_quantity"];            });             // send payload             setAttrs({"weight": sum});         });     }     // send item to deposit     on( "clicked:repeating_equipment:equipment-to-deposit", equipment_to_deposit );     function equipment_to_deposit(event) {         let source = event.sourceAttribute.replace(/equipment-to-deposit$/, '');         let target = "repeating_deposit_"+generateRowID()+"_";         getAttrsNumber([source+"equipment_quantity", source+"equipment_weight"], (user_number) => {             getAttrs([source+"equipment_label"], (user_string) => {                 let payload = {};                 payload[target+"deposit_label"] = user_string.equipment_label;                 payload[target+"deposit_weight"] = user_string.equipment_weight;                 payload[target+"deposit_quantity"] = user_string.equipment_quantity;                 // send payload                 setAttrs( payload );                 // remove object in equipment                 removeRepeatingRow(source.slice(0, -1));             });         });     }     // send item to inventory     on( "clicked:repeating_deposit:deposit-to-equipment", deposit_to_equipment);     function deposit_to_equipment(event) {         let source = event.sourceAttribute.replace(/deposit-to-inventory$/, '');         let target = "repeating_equipment_"+generateRowID()+"_";         getAttrsNumber([source+"deposit_quantity", source+"deposit_weight"], (user_number) => {             getAttrs([source+"deposit_label"], (user_string) => {                 let payload = {};                 payload[target+"equipment_label"] = user_string.deposit_label;                 payload[target+"equipment_weight"] = user_string.deposit_weight;                 payload[target+"equipment_quantity"] = user_string.deposit_quantity;                 // send payload                 setAttrs( payload );                 // remove object in deposit                 removeRepeatingRow(source.slice(0, -1));             });         });     }     // ------------------------------------------     // sub functions     // ------------------------------------------     // get all attribute name and their value as getAttrs()     // return cleaned numbers     function getAttrsNumber(attr, callback) {         if ( !Array.isArray(attr) ) attr = [attr];         if ( !(callback instanceof Function) ) callback = () => {};         getAttrs(attr, (payload) => {             Object.keys(payload).forEach( key => { payload[key] = parseNumber(payload[key]) });             callback(payload);         });     }     // get all attributes name and their values from a repeating block ordered by Id (roll20 generated)     // return cleaned numbers     function getAttrsRepeating(section, fields, callback) {         section = section.replace(/^repeating_/g, '');         if ( !Array.isArray(fields) ) fields = [fields];         if ( !(callback instanceof Function) ) callback = () => {};         // get data from DOM         // note : we work on raw data and not with initialized variables         // because we don't know what "getAttrs" produce         getSectionIDs(section, id => {         // prepares attributes name for "getAttrs"             let attributeNames = id.reduce( (m,id) => [...m, ...(fields.map(field => "repeating_"+section+'_'+id+'_'+field))],[]);             getAttrs(attributeNames, raw => {                 let payload = {}, regex = new RegExp( "repeating_" + section + "_([^_]*)_(.*)"), match;                 Object.keys(raw).forEach( key => {                     match = key.match(regex);                     if ( !payload.hasOwnProperty( match[1]) ) payload[ match[1] ] = {};                     payload[ match[1] ][ match[2] ] = parseNumber( raw[key] );                 });                 callback(payload);             });         });     }     // parse and clean numbers from roll20     // ( checkbox from roll20 return "on" for TRUE, 0 for FALSE )     function parseNumber(value) {         if ( value === "" ) return null;         return parseFloat(value) || (value === "on" ? 1 : 0);     } </script> weight : <input name="attr_weight" value="0" title=""> <div>     <fieldset class="repeating_equipment">         <table>             <tbody>             <tr>                 <td>                     <input type="text" name="attr_equipment_label" title="" />                 </td>                 <td>                     <input type="number" name="attr_equipment_weight" title="" />                 </td>                 <td>                     <input type="number" name="attr_equipment_quantity" title="" />                 </td>                 <td>                     <button type="action" name="act_equipment-to-deposit">send</button>                 </td>             </tr>             </tbody>         </table>     </fieldset> </div> <div>     <fieldset class="repeating_deposit">         <table>             <tbody>             <tr>                 <td>                     <input type="text" name="attr_deposit_label" title="" />                 </td>                 <td>                     <input type="number" name="attr_deposit_weight" title="" />                 </td>                 <td>                     <input type="number" name="attr_deposit_quantity" title="" />                 </td>                 <td>                     <button type="action" name="act_deposit-to-equipment">send</button>                </td>            </tr>             </tbody>         </table>     </fieldset> </div> There is no function for deposit ( because I don't calculate the weight for items in the deposit ) So as I said, when I click on the button, the item is send to the deposit, the weight of the item in inventory is correctly recalculated ( equipment_weight() is executed because of removeRepeatingRow() command ). But when I click on the button in the deposit, the weight of the item is not added to the total weight ( equipment() is not executed, change: repeating_equipment:equipment_weight is not triggered ) I already got a solution, as  I use a separate function for the callback so I can change in the function deposit_to_inventory() : setAttrs( payload ); to setAttrs( payload, {silent:true}, equipment_weight); But it is not the same the logic with the events change and remove a new event add , or modify the event remove can be a good way of thinking
1587748250
GiGs
Pro
Sheet Author
API Scripter
They said be careful what you ask for, but I didn't listen... This might be too complex of a problem for me to help with at the moment, but some observations. There's a couple of possible issues here. Is this syntax correct? getAttrs(source+equipment_quantity, (user) => { getattrs expects an array. Also this setAttrs( {target+"deposit_label": user.equipement_quantity}); When constructing variables like that, you might need to put square brackets around the name, like setAttrs( {[target+"deposit_label"]: user.equipement_quantity}); Also the fact you've used 'equipment' in some places and 'equipement' in others makes me want to check all the attribute names are correct. You said you modified the getRepaataingAttrs. Do you have the original form of that function and can you post it? Again stripping out parts of the code like // some logics for calcullate the total weight sent to a extern variable makes it hard for us to test it and figure out where things are going wrong. Often you do need to test it for yourself.
1587770907

Edited 1587772272
getAttrs(source+equipment_quantity, (user) =&gt; { good point I didn't check my code setAttrs( {[target+"deposit_label"]: user.equipement_quantity}); be careful setAttrs() take a object as first parameter, and an attribute name can't be an array but a string ( javascript convert it, but it's not a good practice for ECMAscript coding ), maybe an abuse for Objects.keys() behavior ? for equipement and equipment yep It is because I wrote my code too quickly, my bad ;) for the original function g etAttrsRepeating() it comes from the wiki <a href="https://wiki.roll20.net/RepeatingSum" rel="nofollow">https://wiki.roll20.net/RepeatingSum</a> "makes it hard for us to test it and figure out where things are going wrong. Often you do need to test it for yourself." the code I showed is a not working as it; I wrote this quickly to show the logic I use the code i actuallay using in my character sheet is working, there is no problems, my question concern a "code ethic", something as a coder I believe is missing. But If you need a code for tests, I edited my message to show a very close code I use, it must be working now ( or maybe not, I will do some some debug&nbsp; tomorrow; it's 2 o'clock of the morning for me :p
1587782354
GiGs
Pro
Sheet Author
API Scripter
Thanks for the updated code, I'll look through that soon.&nbsp; lo(ea)l said: the code i actuallay using in my character sheet is working, there is no problems, my question concern a "code ethic", something as a coder I believe is missing. I'm not following you here. Are you saying your code was failing before, but is now working? What is the issue with code ethic? A question about this: setAttrs( {[target+"deposit_label"]: user.equipement_quantity}); be careful&nbsp; setAttrs() &nbsp;take a object as first parameter, and an attribute name can't be an array but a string ( javascript convert it, but it's not a good practice for ECMAscript coding ), maybe an abuse for Objects.keys() behavior ? In this context the code isnt expecting an array, it's expecting a property name, and this is exactly the same as doing&nbsp; obj['bits' + 'of' + 'a' + 'string'] . Here's a reference:&nbsp; <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names" rel="nofollow">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names</a>