[HELP] Modifying existing HTML code for on('change:...

1533725392

Edited 1533871601
First I must state I am extremely new to HTML5, Javascript, and CSS coding. PART 1 I am working on a character sheet, I am not the original author, that has the following code to determine if a Language cost has change and to update the totals - all from a Repeating Section. The code works perfectly fine, but now I need to also have it check if new attributes, not part of any Repeating Section,  have changed and if so to add their point costs as well into the totals. These new attributes are named: attr_native_language_spoken and attr_native_language_written The code is as follows: // Update the total cost of Languages on('change:repeating_languages:spoken change:repeating_languages:written remove:repeating_languages', function (e) { var total = 0; var tally = _.after(2, function () { setAttrs({ languages_points: total }); }); sumRepeating('repeating_languages', 'spoken', function(v) { console.log('Spoken: ' + v); total += +v; tally(); }); sumRepeating('repeating_languages', 'written', function(v) { console.log('Written: ' + v); total += +v; tally(); }); }); // function to sum a field from a repeating section function sumRepeating(sectionName, fieldName, callback) { getSectionIDs(sectionName, function (ids) { if (ids.length === 0 ) { callback(0); return; } var fieldArray = []; for (var i = 0; i < ids.length; i++) { fieldArray.push(sectionName + '_' + ids[i] + '_' + fieldName); } getAttrs(fieldArray, function (fieldValues) { var vals = Object.values(fieldValues); vals.push(0); var total = vals.reduce(getSum); callback(total); }); }); } How would I go about making the changes I need? Note after it detects that costs have changed, there is additional code: // Update Summery on('change:tl_pts change:appearance change:languages_points change:cf_points change:advantages_points change:disadvantages_points change:racial_points', function (e) { getAttrs(['tl_pts', 'appearance', 'languages_points', 'cf_points', 'advantages_points', 'disadvantages_points', 'racial_points'], function(v) { var vals = Object.values(v); vals.push(0); setAttrs({ trait_points: vals.reduce(getSum) }); }); }); Does this code need t be modified as well in any way? Any help at all would be greatly appreciated.
1533780453

Edited 1533871589
PART 2 This part of the code works for the On Change function;    <div class="sheet-cell sheet-col1"> <select name="attr_spoken"> <option value="3">Native</option> <option value="2">Accented</option> <option value="1">Broken</option> <option value="0" selected>None</option> </select> </div>       However if I make a small modification on the value= to include,  - @{language_talent},  the On Change no longer works. <div class="sheet-cell sheet-col1"> <select name="attr_spoken"> <option value="3 - @{language_talent}">Native</option> <option value="2 - @{language_talent}">Accented</option> <option value="1 - @{language_talent}">Broken</option> <option value="0" selected>None</option> </select> </div> I think I am in way over my head wit this one. I am sure it has to do with the // function to sum a field from a repeating section (shown in my previous post)
1533871187

Edited 1533879222
OK I have gotten a little further PART 1 I changed this part f the code: // Update the total cost of Languages on('change:repeating_languages:spoken change:repeating_languages:written remove:repeating_languages', function (e) { To this: // Update the total cost of Languages on('change:native_language_spoken change:native_language_written change:repeating_languages:spoken change:repeating_languages:written remove:repeating_languages', function (e) { Which now executes the code following that entry whenever the Native Language is updated (Spoken or Written). Now I need to know what to modify to the rest of that code to add the values of attr_native_mange_spoken and attr_native_language_written; PART 2 Still having issues, see preceding post. I am totally stuck in both cases!
1533877427
G G
Pro
Sheet Author
The reason this code fails is because the sheet worker does not recognise the values here as numbers. <select name="attr_spoken"> <option value="3 - @{language_talent}">Native</option> <option value="2 - @{language_talent}">Accented</option> <option value="1 - @{language_talent}">Broken</option>         <option value="0" selected>None</option> </select> What I would do is as follows: 1. leave those entries as 3 / 2 / 1, but change the name to attr_spoken_base 2. Create a hidden input, attr_spoken, and have a sheet worker run whenever spoken_base changes, which enters a number 3/2/1 - language_talent. (Don't use an autocalc field - this has to be a sheet worker.) 3. this means you dont have to change the sum_repeating sheet workers to calculate these. For the other problem, to add in the native language costs: how are the costs used? When you add them into the total character points cost, are they added in an autocalc field, or does it add the costs using a sheet worker?  If it is based on autocalc, there's a very simple solution: 1) In the sheetworker above, change this line  setAttrs({ languages_points: total });  to  setAttrs({ languages_points_base: total }); and create a hidden input named language_points_base to hold it. 2) then change the language_points to an autocalc field (disabled), and set its value="[@{language_points}+@{native_mange_spoken}+{native_language_written}]]" On the other hand, if the @{language_points } stat is used in a sheetworker, you'll need to edit the sheetworker to add it. I am not familiar with the syntax of the sum repeating functions you have above, but this might work: // Update the total cost of Languages on('change:native_language_spoken change: native_language_written change:language_talent change:repeating_languages:spoken change:repeating_languages:written remove:repeating_languages', function (e) { getAttrs(['native_language_spoken','native_language_written'], function(values) { var native_spoken = parseInt(values.native_language_spoken)||0; var native_written = parseInt(values.native_language_written)||0; var total = 0; var tally = _.after(2, function () { setAttrs({ languages_points: total + native_spoken +native_written }); }); sumRepeating('repeating_languages', 'spoken', function(v) { console.log('Spoken: ' + v); total += +v; tally(); }); sumRepeating('repeating_languages', 'written', function(v) { console.log('Written: ' + v); total += +v; tally(); }); }); });
1533878839

Edited 1533879102
G G between my last post and your post, I was able to get PART 1 all figured out (took some time). So PART 1 is fully functional at this time. Here is how I coded it: (Not as elegant as yours but it works - do you foresee any problems with it?) // Update the total cost of Languages on('change:native_language_spoken change:native_language_written change:repeating_languages:spoken change:repeating_languages:written remove:repeating_languages', function (e) { console.log('**** Languages Changed ****'); var total = 0; var tally = _.after(2, function () { setAttrs({ languages_points: total }); }); getAttrs(['native_language_spoken', 'native_language_written'], function(v) { console.log('Native Language Spoken: ' + v.native_language_spoken); console.log('Native Language Written: ' + v.native_language_written); total += +v.native_language_spoken; total += +v.native_language_written; tally(); }); sumRepeating('repeating_languages', 'spoken', function(v) { console.log('Spoken: ' + v); total += +v; tally(); }); sumRepeating('repeating_languages', 'written', function(v) { console.log('Written: ' + v); total += +v; tally(); }); });
1533880101
G G
Pro
Sheet Author
I am not sure how the tally function works, but if it working it should be fine. i did mine the way I did, because setAttrs calls should usually be inside the getAttrs box. These are asynchronous functions, which means that you cant be certain what order they'll run. Even though they are listed one after the other, the setattrs function might be run before the getattrs, and so before you have the attributes you need. However, the tally function is getting around that for the sumRepeating functions - but I think that is because they have a callback parameter. I'd test it a few times and make sure the getAttrs attributes are bing called properly. If your function is working reliably, then all is well. Did you have anything left to sort out?
1533880162

Edited 1533880256
G G said: The reason this code fails is because the sheet worker does not recognise the values here as numbers. <select name="attr_spoken"> <option value="3 - @{language_talent}">Native</option> <option value="2 - @{language_talent}">Accented</option> <option value="1 - @{language_talent}">Broken</option>         <option value="0" selected>None</option> </select> -------- The @{language_talent} has a default vale of 0 if the character does not have Language Talent, otherwise if the character does then the value is 1. So if you have the Language Talent, the new costs would be 2/1/0 (both for Spoken and Written). I cannot change any attribute names or else it will affect all users currently using this sheet (GURPS) and there a number of coded sections that use those names for other calculations. However your post has given me some ideas to try. 
1533881159

Edited 1533881203
G G
Pro
Sheet Author
Changing the attribute name the way I suggested would not change things for users - because I was suggesting keeping the current attribute, but adding another to act as an intermediate. For example, my suggestion for the native language points problem was: You currently have the  language_points attribute. And the sheet worker updates that attribute. My suggestion was to keep that attribute, and add a second, hidden one, called language_points_base . Then change the current script to update the  language_points_base  attribute, and have language_points  take that value and add the native language points to it (updating either as an autocalc field or a sheet worker- both would work). To end users, it would appear identical to the current sheet - the language_points attribute would show the total points, as it does now. You just had an intermediate hidden step to reach it.
1533881881
G G said: Changing the attribute name the way I suggested would not change things for users - because I was suggesting keeping the current attribute, but adding another to act as an intermediate. For example, my suggestion for the native language points problem was: You currently have the  language_points attribute. And the sheet worker updates that attribute. My suggestion was to keep that attribute, and add a second, hidden one, called language_points_base . Then change the current script to update the  language_points_base  attribute, and have language_points  take that value and add the native language points to it (updating either as an autocalc field or a sheet worker- both would work). To end users, it would appear identical to the current sheet - the language_points attribute would show the total points, as it does now. You just had an intermediate hidden step to reach it. LOL - Easy for you to say. I understood some of what you said but since I did manage to get PART 1 to work I am happy with what  I have for it. As for PART 2 , I will try what you suggested (if I can) or keep researching for a way. I am so new to this and this sheet was written some 3 or 4 years ago - perhaps even older and those people are no longer around. Thank you again, you have been of a great help AS ALWAYS! Mike
1533883702

Edited 1533883848
G G
Pro
Sheet Author
Ahh, i understand what you mean about changing attribute names. here's an alternative solution. Step 1: Add Hidden Attribute Change your attr_spoken select to this (and do the same for written): note the new hidden input. <div class="sheet-cell sheet-col1"> <input name="attr_spoken_calc" type="hidden"> <select name="attr_spoken"> <option value="3">Native</option> <option value="2">Accented</option> <option value="1">Broken</option> <option value="0" selected>None</option> </select> </div>       Step 2 Add New Sheet Worker This sheet worker handles the cost calculation. on("change:repeating_languages:spoken change:repeating_languages:written", function () {     getAttrs(['language_talent','repeating_languages_spoken','repeating_languages_written'], function(values) {         let talent = parseInt(values.language_talent)||0; let written = parseInt(values.repeating_languages_written)||0; let spoken = parseInt(values.repeating_languages_spoken)||0; setAttrs({ "repeating_languages_written_calc": written - talent, "repeating_languages_spoken_calc": spoken - talent, });         }); }); Note:  there's a flaw in this code. It only works when you change the spoken or written selects, and does not trigger if you add the language_talent after  changing the language level. It also doesnt handle what happens when you remove a row in the field. You can  account for those things, but that's a more complex script - this is quick script to show the process. Step 3: Update Calculation Script Change all references in your other sheet worker scripts from spoken to spoken_calc, and likewise for written. For example, your part 1 script would become: // Update the total cost of Languages on('change:native_language_spoken change:native_language_written change:repeating_languages: spoken_calc change:repeating_languages: written_calc remove:repeating_languages', function (e) { console.log('**** Languages Changed ****'); var total = 0; var tally = _.after(2, function () { setAttrs({ languages_points: total }); }); getAttrs(['native_language_spoken', 'native_language_written'], function(v) { console.log('Native Language Spoken: ' + v.native_language_spoken); console.log('Native Language Written: ' + v.native_language_written); total += +v.native_language_spoken; total += +v.native_language_written; tally(); }); sumRepeating('repeating_languages', ' spoken_calc ', function(v) { console.log('Spoken: ' + v); total += +v; tally(); }); sumRepeating('repeating_languages', ' written_calc ', function(v) { console.log('Written: ' + v); total += +v; tally(); }); });
1533952213

Edited 1533952284
GG I really appreciate what you did here. I only understand about half of it. What you did in minutes would take me hours or days. In my original code, I was using a Checkbox code: </fieldset> <!-- .repeating_languages --> <div> <!-- .sheet-row --> <div class="sheet-header sheet-col0"> <input class="sheet-boolean" type="checkbox" name="attr_language_talent" value="1">                                                 <span class="sheet-popup">Check if character has Language Talent</span> </div> <!-- .sheet-header --> </div> <!-- .sheet-row -->                                                               I am not sure how to implement this with your code.  Since there is a flaw, as you say, I am a little concerned about using your code..   Also I do not think I have shown you all the code in use, perhaps you would like to see the entire HTML code (which is on my PC) to make sure you have a full grasp of what I am doing. I can also post each section as it currently is , right here.  Now this also may be asking to much of you and you have done so much for me already. I can also invite you to the game where I am testing it all. If this is to much, then just let me know - you have done more than enough, far more than I expected. Mike                                                                                 
1533953776

Edited 1533953807
G G
Pro
Sheet Author
I dont really have time or the ability to commit to a major examination of your code right now, but I can ocntinue to help you with this as my health permits. I think I've seen all the code I need to understand this section. When I said there was a flaw in the code, I really should have said, it's a proof of concept test. That script can be made to work properly, but as it is now, it can be used to test that things work okay when you change the level of native spoken or written languages. If that works to your satisfaction, we an fix the script so it covers all cases (when language talent changes, and when languages are removed). I just didnt want to make the full script in case it wasnt working how you need. The actual code isnt the important part of what I posted, it's the steps of the process. If you can understand what I'm suggesting here. you're most of the way there. My code doesnt require you to change the language_talent checkbox - you can leave it exactly as it is.
1533957005
OK I will give it all a try.however I am busy this weekend, having 2 games and I am GM in one, but next week I will plug it in and do some more testing. At one point I did get it to change as needed and the update saw the change BUT it did not recognize the amounts. I greatly appreciate all the help so let me see how far I can get now.
1533957646
G G
Pro
Sheet Author
Good luck! It's a busy week or two ahead for me too. 
1536218265

Edited 1536219328
G G I finally got around to trying this out. 90% worked as scripted. Thank you for that!!!!  I am very excited that you got me so darn close. Also it does recalculate if you delete a row even though your note says it will not, so a side benefit there. First:  The calculation for the Language Talent is allowing for a negative result. So when set to None it should be 0 points but it is subtracting the Language Talent of -1 and going negative. Spoken goes from 3 to 2, Accented goes from 2 to 1, and Broken goes from 1 to 0. All as expected. Note: None goes from 0 to -1 and that cannot be allowed. Second:  As you expected and pointed out - when selecting the Language Talent option it does not do any recalculations. I tried adding  change:language_talent  to both the Cost Calculation for the Talent and the Total Cost but that did not help. // Update cost calculation of repeating_languages (Learned Languages) on(" change:language_talent change:repeating_languages:spoken change:repeating_languages:written", function () { getAttrs(['language_talent','repeating_languages_spoken','repeating_languages_written'], function(values) { let talent = parseInt(values.language_talent)||0; let written = parseInt(values.repeating_languages_written)||0; let spoken = parseInt(values.repeating_languages_spoken)||0; setAttrs({ "repeating_languages_written_calc": written - talent, "repeating_languages_spoken_calc": spoken - talent, });         }); }); // Update the total cost of Languages on(' change:language_talent change:native_language_spoken change:native_language_written change:repeating_languages:spoken_calc change:repeating_languages:written_calc remove:repeating_languages', function (e) { console.log('**** Languages Changed ****'); var total = 0; var tally = _.after(2, function () { setAttrs({ languages_points: total }); });
1536221906
G G
Pro
Sheet Author
What does the html for the languages repeating sections, and the language talent look like now? Can you post that? The fix for the negative cost isnt too hard. There's a mistake in the first function.                         let talent = parseInt(values.language_talent)||0; let written = parseInt(values.repeating_languages_written)||0; let spoken = parseInt(values.repeating_languages_spoken)||0;                         spoken = Math.max(spoken - talent,0);                         written = Math.max(written - talent,0); setAttrs({ "repeating_languages_written_calc": written, "repeating_languages_spoken_calc": spoken });     Note: no comma on that last statement in setAttrs.  Math.max picks the highest of the values you give it, so passing it 0 as one of the values means it will never return a value below 0. I moved the calculation steps out of the setAttrs function, mainly because its neater, but also, when you're starting out, you often have problems and need to use log statements to explore what's happening, and this format makes it easier to do that when you need to. I cant remember what the issue was with the language talent not calculating, I'll have to look again at the thread after I've slept. Hope this helps you make some more progress in the meantime.
1536282767

Edited 1536282985
Repeating Section <fieldset class="repeating_languages"> <div class="sheet-row sheet-row-stats"> <div class="sheet-cell sheet-col0"> <input type="text" name="attr_name" /> </div> <div class="sheet-cell sheet-col1"> <input name="attr_spoken_calc" type="hidden"> <select name="attr_spoken"> <option value="3">Native</option> <option value="2">Accented</option> <option value="1">Broken</option> <option value="0" selected>None</option> </select> </div> <div class="sheet-cell sheet-col2"> <input name="attr_written_calc" type="hidden"> <select name="attr_written"> <option value="3">Native</option> <option value="2">Accented</option> <option value="1">Broken</option> <option value="0" selected>None</option> </select> </div> </div> <!-- .sheet-row --> </fieldset> <!-- .repeating_languages --> <div> <!-- .sheet-row --> <div class="sheet-header sheet-col0"> <input class="sheet-boolean" type="checkbox" name="attr_language_talent" value="1"> <span class="sheet-popup">Check if character has Language Talent</span> </div> <!-- .sheet-header --> </div> <!-- .sheet-row -->  
1536282859
Update Sections - Bo changes made yet // Update cost calculation of repeating_languages (Learned Languages) on("change:language_talent change:repeating_languages:spoken change:repeating_languages:written", function () { getAttrs(['language_talent','repeating_languages_spoken','repeating_languages_written'], function(values) { let talent = parseInt(values.language_talent)||0; let written = parseInt(values.repeating_languages_written)||0; let spoken = parseInt(values.repeating_languages_spoken)||0; setAttrs({ "repeating_languages_written_calc": written - talent, "repeating_languages_spoken_calc": spoken - talent, });         }); }); AND // Update the total cost of Languages on('change:language_talent change:native_language_spoken change:native_language_written change:repeating_languages:spoken_calc change:repeating_languages:written_calc remove:repeating_languages', function (e) { console.log('**** Languages Changed ****'); var total = 0; var tally = _.after(2, function () { setAttrs({ languages_points: total }); }); getAttrs(['native_language_spoken', 'native_language_written'], function(v) { console.log('Native Language Spoken: ' + v.native_language_spoken); console.log('Native Language Written: ' + v.native_language_written); total += +v.native_language_spoken; total += +v.native_language_written; tally(); }); sumRepeating('repeating_languages', 'spoken_calc', function(v) { console.log('Spoken: ' + v); total += +v; tally(); }); sumRepeating('repeating_languages', 'written_calc', function(v) { console.log('Written: ' + v); total += +v; tally(); }); });
1536990349
G G
Pro
Sheet Author
Did you resolve this? i might have time over the weekend to look at this.
1536999396
G G
Pro
Sheet Author
One thing I noticed. This line var tally = _.after( 2 , function () { should probably be var tally = _.after(3, function () { The after function delays its contents till a number of other tally() functions have been run. There used to be 2 tally functions, but you added a third (the getAttrs block), so that after(2 line should now be after(3 .