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

[HELP] Ghost Rows with Sheet Worker generateRowID function

1515767695
Finderski
Pro
Sheet Author
Compendium Curator
So, I created a Conversion script to migrate info from one set of repeating rows to a different set of (new) repeating rows.  For some weird reason (probably me doing something wrong), it's generating a ghost row for every row migrated; what I mean by that is, I have 6 rows to migrate, 6 rows actually migrate and visible, but there are 6 invisible rows (visible only when I do a getSectionIDs() on the new repeating section). Here's my conversion code: function convertRS (mookSection, wcSection, mfieldArray, wcfieldArray) { var mookRS = "repeating_"+mookSection; getSectionIDs(mookRS, function(idArray) { if (idArray.length > 0) { var oldAttrs = []; //build oldAttrs array... for (var a=0; a < idArray.length; a++) { for (var b=0; b < mfieldArray.length; b++) { oldAttrs[oldAttrs.length] = mookRS + "_" + idArray[a] + "_m" + mfieldArray[b]; } } getAttrs(oldAttrs, function(v) { const sattrs = {}; for(var i=0; i < idArray.length; i++) { var newrowid = generateRowID(); var mookRF = "repeating_" + mookSection + "_" + idArray[i] + "_m"; var wcRF = "repeating_" + wcSection + "_" + newrowid + "_"; //For this idArray SectionID value need to get the ATTRS for the entire row and create them for(var r=0; r < mfieldArray.length; r++) { var getMRF = '', putWCRF = ''; getMRF = mookRF+mfieldArray[r]; putWCRF = wcRF+wcfieldArray[r]; sattrs[putWCRF]=v[getMRF]; } } setAttrs(sattrs); }); } else { console.log("<===== "+mookSection+" had no rows =====>") } }); } Quick note: I say a ghost row for each row actually migrated, I wonder if it may be more for some sections (I'm migrating multiple sections)...this particular section I'm working with has 2 fields that needed to migrate, but I wonder if it would be two ghost rows for each actual row if I had three fields per row to migrate?  I'll try to do something additional research on that front. Thanks for any help y'all can provide.
1515768582
Jakob
Sheet Author
API Scripter
I can't immediately see what would be wrong here, it seems okay (apart from a coding style that's a bit hard to parse for me). Perhaps try to log the sattrs object before you set it? Seeing what attributes you're actually setting might help debug the issue. There's another problem here that doesn't have anything to do with your question, but I just thought I'd warn you: generateRowID() doesn't actually generate unique IDs if run in immediate succession. It might happen that some rows are "swallowed" in your conversion process (this is non-deterministic behaviour, they need to run at the same millisecond and with the same random seed). It will come up occasionally, however, so it's best to put in some safeguard against duplicated row IDs.
1515770368
Finderski
Pro
Sheet Author
Compendium Curator
Jakob said: I can't immediately see what would be wrong here, it seems okay (apart from a coding style that's a bit hard to parse for me). Perhaps try to log the sattrs object before you set it? Seeing what attributes you're actually setting might help debug the issue. There's another problem here that doesn't have anything to do with your question, but I just thought I'd warn you: generateRowID() doesn't actually generate unique IDs if run in immediate succession. It might happen that some rows are "swallowed" in your conversion process (this is non-deterministic behaviour, they need to run at the same millisecond and with the same random seed). It will come up occasionally, however, so it's best to put in some safeguard against duplicated row IDs. Log (not sure how to log sattrs so it's meaningful...my attempt resulted in simply showing [object Object]??): ~~~~ ConvertRS Iteration 0:: for Section: mhindrances:: id generated: -L2etzM6fx3vHktItbOm ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrance ** wcRF: repeating_hindrances_-L2etzM6fx3vHktItbOm_hindrance ******************** 0-0) Current value of getMRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrance ##### sattrs: [object Object] ##### ******************** ** mookRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrancedescription ** wcRF: repeating_hindrances_-L2etzM6fx3vHktItbOm_hindrancedescription ******************** 0-1) Current value of getMRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrancedescription ##### sattrs: [object Object] ##### ~~~~ ConvertRS Iteration 1:: for Section: mhindrances:: id generated: -L2etzM8JZYb45xMzWiL ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrance ** wcRF: repeating_hindrances_-L2etzM8JZYb45xMzWiL_hindrance ******************** 1-0) Current value of getMRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrance ##### sattrs: [object Object] ##### ******************** ** mookRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrancedescription ** wcRF: repeating_hindrances_-L2etzM8JZYb45xMzWiL_hindrancedescription ******************** 1-1) Current value of getMRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrancedescription ##### sattrs: [object Object] ##### ~~~~ ConvertRS Iteration 2:: for Section: mhindrances:: id generated: -L2etzMA79ZB4aaBtA1a ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrance ** wcRF: repeating_hindrances_-L2etzMA79ZB4aaBtA1a_hindrance ******************** 2-0) Current value of getMRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrance ##### sattrs: [object Object] ##### ******************** ** mookRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrancedescription ** wcRF: repeating_hindrances_-L2etzMA79ZB4aaBtA1a_hindrancedescription ******************** 2-1) Current value of getMRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrancedescription ##### sattrs: [object Object] ##### ~~~~ ConvertRS Iteration 3:: for Section: mhindrances:: id generated: -L2etzMCRiWJFC5EKVcl ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrance ** wcRF: repeating_hindrances_-L2etzMCRiWJFC5EKVcl_hindrance ******************** 3-0) Current value of getMRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrance ##### sattrs: [object Object] ##### ******************** ** mookRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrancedescription ** wcRF: repeating_hindrances_-L2etzMCRiWJFC5EKVcl_hindrancedescription ******************** 3-1) Current value of getMRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrancedescription ##### sattrs: [object Object] ##### ~~~~ ConvertRS Iteration 4:: for Section: mhindrances:: id generated: -L2etzMEWvQCRkanFQlz ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrance ** wcRF: repeating_hindrances_-L2etzMEWvQCRkanFQlz_hindrance ******************** 4-0) Current value of getMRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrance ##### sattrs: [object Object] ##### ******************** ** mookRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrancedescription ** wcRF: repeating_hindrances_-L2etzMEWvQCRkanFQlz_hindrancedescription ******************** 4-1) Current value of getMRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrancedescription ##### sattrs: [object Object] ##### ~~~~ ConvertRS Iteration 5:: for Section: mhindrances:: id generated: -L2etzMHRElP36ASzuIM ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrance ** wcRF: repeating_hindrances_- L2etzMHRElP36ASzuIM _hindrance ******************** 5-0) Current value of getMRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrance ##### sattrs: [object Object] ##### ******************** ** mookRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrancedescription ** wcRF: repeating_hindrances_- L2etzMHRElP36ASzuIM _hindrancedescription ******************** 5-1) Current value of getMRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrancedescription ##### sattrs: [object Object] ##### So, the number of iterations was correct (i.e. we didn't get 12 row IDs), each field pair has the same row id (see the couple I bolded). Hopefully to help parse this out: mookRF is the existing repeating section, and wcRF is where I'm moving everything to. As for the other item you pointed out, how do I protect against that?
1515772037
Jakob
Sheet Author
API Scripter
Aha! You can't just put an object into a string, otherwise you just get [object Object]. Log just  the object: console.log(sattrs); Or the stringified version: console.log(JSON.stringify(sattrs)); Odd though, from what I can see, the log looks ok, so no idea where your ghost rows are coming from. Maybe  some of the strangeness is coming from your variables being hoisted to the top of the function, but probably not. Try replacing your instances of var  by let  ( let  has block scope, rather than function scope). About the other thing: keep track of the row IDs already created, and continue generating new IDs until you get a new one. Roughly something like this: const sattrs = {}; const createdIDs = []; for(var i=0; i < idArray.length; i++) { let newrowid; while (!newrowid) { let newID = generateRowID(); if (!createdIDs.includes(newID)) { newrowid = newID; createdIDs.push(newrowid); } } // continue as normally in your code }
1515772153
GiGs
Pro
Sheet Author
API Scripter
To convert objects into a format useful for logging, you can use JSON.stringify() log(JSON.stringify(sattrs));
1515773661
Finderski
Pro
Sheet Author
Compendium Curator
So, I modified the sattrs logging with the JSON.stringify...here are the current logs: ~~~~ ConvertRS Iteration 0:: for Section: mhindrances:: id generated: -L2f6-z-VF3ZCGDk1LZq ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrance ** wcRF: repeating_hindrances_-L2f6-z-VF3ZCGDk1LZq_hindrance ******************** 0-0) Current value of getMRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrance ******************** ** mookRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrancedescription ** wcRF: repeating_hindrances_-L2f6-z-VF3ZCGDk1LZq_hindrancedescription ******************** 0-1) Current value of getMRF: repeating_mhindrances_-kqbf3urpclludbwoo3l_mhindrancedescription ~~~~ ConvertRS Iteration 1:: for Section: mhindrances:: id generated: -L2f6-z1BeXXYiyK4ZAc ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrance ** wcRF: repeating_hindrances_-L2f6-z1BeXXYiyK4ZAc_hindrance ******************** 1-0) Current value of getMRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrance ******************** ** mookRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrancedescription ** wcRF: repeating_hindrances_-L2f6-z1BeXXYiyK4ZAc_hindrancedescription ******************** 1-1) Current value of getMRF: repeating_mhindrances_-kqbf81cbgrpr-ngkget_mhindrancedescription ~~~~ ConvertRS Iteration 2:: for Section: mhindrances:: id generated: -L2f6-z4XbrHM7W7vVph ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrance ** wcRF: repeating_hindrances_-L2f6-z4XbrHM7W7vVph_hindrance ******************** 2-0) Current value of getMRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrance ******************** ** mookRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrancedescription ** wcRF: repeating_hindrances_-L2f6-z4XbrHM7W7vVph_hindrancedescription ******************** 2-1) Current value of getMRF: repeating_mhindrances_-kqbf9vogpo-xmmkisen_mhindrancedescription ~~~~ ConvertRS Iteration 3:: for Section: mhindrances:: id generated: -L2f6-z6Ha8W-fh6X-X- ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrance ** wcRF: repeating_hindrances_-L2f6-z6Ha8W-fh6X-X-_hindrance ******************** 3-0) Current value of getMRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrance ******************** ** mookRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrancedescription ** wcRF: repeating_hindrances_-L2f6-z6Ha8W-fh6X-X-_hindrancedescription ******************** 3-1) Current value of getMRF: repeating_mhindrances_-kqbfbryol4zicy1rdty_mhindrancedescription ~~~~ ConvertRS Iteration 4:: for Section: mhindrances:: id generated: -L2f6-z7JCewNHe-eyvJ ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrance ** wcRF: repeating_hindrances_-L2f6-z7JCewNHe-eyvJ_hindrance ******************** 4-0) Current value of getMRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrance ******************** ** mookRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrancedescription ** wcRF: repeating_hindrances_-L2f6-z7JCewNHe-eyvJ_hindrancedescription ******************** 4-1) Current value of getMRF: repeating_mhindrances_-kqbfhmyq18dfojwelwi_mhindrancedescription ~~~~ ConvertRS Iteration 5:: for Section: mhindrances:: id generated: -L2f6-zAImoK4JrjAMoB ~~~~ ******************** ** mookRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrance ** wcRF: repeating_hindrances_-L2f6-zAImoK4JrjAMoB_hindrance ******************** 5-0) Current value of getMRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrance ******************** ** mookRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrancedescription ** wcRF: repeating_hindrances_-L2f6-zAImoK4JrjAMoB_hindrancedescription ******************** 5-1) Current value of getMRF: repeating_mhindrances_-kqbfio48krgb6wf5ola_mhindrancedescription ##### sattrs: { "repeating_hindrances_-L2f6-z-VF3ZCGDk1LZq_hindrance":"Loyal (Minor)", "repeating_hindrances_-L2f6-z-VF3ZCGDk1LZq_hindrancedescription":"Your character may not be a hero, but he’d give his life for his friends. This character can never leave a man behind if there’s any chance at all he could help.", "repeating_hindrances_-L2f6-z1BeXXYiyK4ZAc_hindrance":"Brawler", "repeating_hindrances_-L2f6-z1BeXXYiyK4ZAc_hindrancedescription":"Frequent fights with his bare hands have given this thug a powerful punch. When he hits a foe with a successful bare-handed Fighting roll, he adds +2 to his damage.", "repeating_hindrances_-L2f6-z4XbrHM7W7vVph_hindrance":"Bruiser", "repeating_hindrances_-L2f6-z4XbrHM7W7vVph_hindrancedescription":"When the bruiser gets a raise on his barehanded Fighting attack, he rolls a d8 instead of a d6.", "repeating_hindrances_-L2f6-z6Ha8W-fh6X-X-_hindrance":"Combat Reflexes", "repeating_hindrances_-L2f6-z6Ha8W-fh6X-X-_hindrancedescription":"Adds +2 to his Spirit roll when attempting to recover from being Shaken.", "repeating_hindrances_-L2f6-z7JCewNHe-eyvJ_hindrance":"Improved Martial Artist", "repeating_hindrances_-L2f6-z7JCewNHe-eyvJ_hindrancedescription":"never considered unarmed in\ncombat and so is never subject to the Unarmed\nDefender rule (page 87). With a successful unarmed attack, he adds +d6 to his Strength roll (as if he were using a small weapon).", "repeating_hindrances_-L2f6-zAImoK4JrjAMoB_hindrance":"No Mercy", "repeating_hindrances_-L2f6-zAImoK4JrjAMoB_hindrancedescription":"May spend a Benny to re-roll any one damage roll, including those made for area effect attacks."}  ##### NOTE: I broke the sattrs up into separate lines and in field pairs...in the log, they were actually just a single long string with no line breaks. I also added some additional logging to the code that gets the sectionIDs and here's the output from that: ## Hindrance ID Array: -kqbf3urpclludbwoo3l, -kqbf81cbgrpr-ngkget, -kqbf9vogpo-xmmkisen, -kqbfbryol4zicy1rdty, -kqbfhmyq18dfojwelwi, -kqbfio48krgb6wf5ola, -l2f6-z-vf3zcgdk1lzq, -l2f6-z1bexxyiyk4zac, -l2f6-z4xbrhm7w7vvph, -l2f6-z6ha8w-fh6x-x-, -l2f6-z7jcewnhe-eyvj, -l2f6-zaimok4jrjamob For ease of reading, I broke these into separate lines, too...the odd thing here is the first 6 IDs; I have no idea what those are from. The last 6 match the sattrs log (except for the case).
1515773800
Finderski
Pro
Sheet Author
Compendium Curator
And, just in case it's important, here's the code calling the getSectionIDs: function specHindranceBlock() { console.log("<==Creating Hindrance Statblock!!==>"); getSectionIDs("mhindrances", function(midarray) { console.log("****"); console.log("** Number of Mook Hindrances:" + midarray.length); console.log("****"); }); var specHindrances = ""; var numHindrances = 0; getSectionIDs("hindrances", function(idarray) { numHindrances = idarray.length; console.log("****"); console.log("** Number of Hindrances:" + numHindrances); console.log("****"); console.log("####"); console.log("## Hindrance ID Array: " + idarray); console.log("####"); for(var i=0; i<idarray.length; i++) { specHindrances += "<li>**@{repeating_hindrances_$"+i+"_hindrance}**: @{repeating_hindrances_$"+i+"_hindrancedescription}</li>"; }   console.log("**** Special Abilities ("+numHindrances+"): "+specHindrances+" ****");   setAttrs({   specHindrances: specHindrances,   numHindrances: numHindrances   }); }); }
1515775308

Edited 1515775864
Jakob
Sheet Author
API Scripter
The output of your conversion function is completely fine. I'm pretty certain the error isn't in there. Have you redefined the standard getSectionIDs function or something? Shouldn't it be getSectionIDs("repeating_hindrances", ... instead? You may have stumbled upon a particularly weird behaviour in the getSectionIDs function when given an invalid input, but I cannot help but notice that your first couple of IDs are the ids of the OLD mhindrances section... Side remark #1: Which reminds me, your conversion function should definitely  do cleanup and remove all the old rows in order to not bloat any converted sheet with invisible attributes. You can do this by adding removeRepeatingRow() calls for the right id to your for loop. Side remark #2: Putting HTML into your attribute values won't work, it's all filtered out automatically. (Though there are other ways to make what you're trying to do here work, if it is what I think it is). Or at least I think  it doesn't work, I tried it at some point and it did not do what I wanted...
1515776536
Finderski
Pro
Sheet Author
Compendium Curator
I'll try changing it to repeating_hindrances, though the reason I didn't was from the  wiki which has this example: on("change:repeating_inventory", function() { getSectionIDs(" inventory ", function(idarray) { for(var i=0; i < idarray.length; i++) { //Do something with the IDs } }); }); That's under the getSectionIDs header; although, you are correct, in other areas they do use a different convention (just not under the getSectionIDs header specifically). re: Side remark #1: I intend to at somepoint, but given that this is a conversion and I've seen how people get really upset when data is lost, I was going to leave them in until I validate that no one is screaming for my head.  Then, I was going to go back in and remove not just those things, but also all the old HTML code that supports that old section for Mooks.  Essentially, I'm combining two different types of characters into a single section, so the html should get cut almost in half. re: Sideremark #2: Oddly, it still works and does what I want it to with the html list. I'll see what happens when I add "repeating_" into the getSectionIDs and report back.
1515776808
Finderski
Pro
Sheet Author
Compendium Curator
Apparently, if you omit "repeating_" in the getSectionIDs, it functions as a wild card type search.  Once I added repeating_ then I only get the 6 back that I'd expected. Thanks for all your help...it is now functioning as it should and I'll go back and clean up some code and finish putting together my stat block.
1515790062
Jakob
Sheet Author
API Scripter
Finderski said: Apparently, if you omit "repeating_" in the getSectionIDs, it functions as a wild card type search.  Once I added repeating_ then I only get the 6 back that I'd expected. Thanks for all your help...it is now functioning as it should and I'll go back and clean up some code and finish putting together my stat block. That's really weird and unintuitive. Anyway, glad it worked!