Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Calculating Check Boxes in columns to total at the bottom

Engaged ,
Apr 14, 2020 Apr 14, 2020

I have a page with 12 columns of 31 checkboxes that are to be tabulated at the bottom of each column.

 

My field structure has the following naming convention:

 

check1.row    check2.row    check3.row...

check1.row1  check2.row1  check3.row1...

check1.row2  check2.row2  check3.row2....

...and so on down to row30 (which is the 31st row)

 

the bottom tabulation row goes like this...

check1.total   check2.total   check3.total....

 

I have a code from a recent similar situation I used as a start. I set the bottom total field as the target field. First I get the column names with a split and pop, then I get the array for the column. The loop starts by not adding the target field, and loops through the array to see if the checkbox value is not "Off" which will add one to the value if it counts. This would put the event value in the total. I'm not getting any syntax errors but it's not working.

 

I'm newer at this. I referenced another solution here for counting checkboxes and adding assorted scores to a total. Obviously there's something I'm missing here.

 

var aNameParts = event.targetName.split(".");
aNameParts.pop();
var strColName = aNameParts;
var oColFldList = this.getField(strColName);
oColFldList.getArray().forEach(function(a,i)
{if(a != event.target) event.value=Number(i?event.value:0);
if (a.value!="Off") Number+=1;});

 

 

 

TOPICS
PDF forms
3.4K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
1 ACCEPTED SOLUTION
Community Expert ,
May 10, 2020 May 10, 2020

Number++ looks not correct.

 

Try this:

var aNameParts = event.targetName.split(".");
aNameParts.pop();
aNameParts.pop();
aNameParts.push("value");
var strColName = aNameParts.join(".");
var oColFldList = this.getField(strColName);
var total = 0;
oColFldList.getArray().forEach(function(a,i,ar){if (a.value!="Off") total++;});
event.value = total;

View solution in original post

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 15, 2020 Apr 15, 2020

So are is the idea to count the number of checked boxes? Or to add up the export values?

 

I would suggest that since you are a beginner you write the code as a For Loop instead of using the shortcut "forEach" function. The loop makes it more explicit so you can follow what is happening in the code. 

In fact, I think you should write out the exact steps needed to accomplish the required task as a hierarchal list.

Before you can even begin to code you need to be able to follow your written list of steps to accomplish the goal. 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
Apr 15, 2020 Apr 15, 2020

Hi Thom,

Thanks. What I'm wanting to do is count the number of "on" checkboxes and put the total in the bottom field. These are for dates of the month to be tabulated when an event happened for users. 

 

So I wrote up my need in commented form and did the coding within it. It seems sound what I've written but I have a syntax error message in the Calculation script window of "missing ; after for-loop initializer 11: at line 12". I looked up the Mozilla reference on for-loops and it looks like I have the proper ; between the initialization and the condition. I read I don't need a final expression (optional), and that's good because both of my if statements below cover the target field as getting 0 and if the field is not "off" so the field gets counted.

 

// the total field has the same prefix as the checkboxes above it of check1.total, checkboxes are check1.row, etc. Split and pop off the end for the name of the column
var aNameParts = event.targetName.split(".");
aNameParts.pop();
//put the column name in a variable
var strColName = aNameParts;
//get the fields of the column and put in variable
var oColFldList = this.getField(strColName);
//take the array of fields from the column list
oColFldList.getArray();
//go through the list, if the field value is not Off, then add one to the count, the event target gets a value of 0
for (let i = 0 ; i < oColFldList.length;) {
    if(thisField!= event.target) event.value=Number(i?event.value:0);
    if(a.value!="Off") Number+=1;
}
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
Apr 16, 2020 Apr 16, 2020

You're comments are just fine up to the point where it really counts, and then it all falls apart. It is the bit being done in the loop you need to think through.

So the "i" in the for statment is never incremented. Which means that the loop will just run forever.

Next, there is no "thisField" defined anywhere, so the first if doesn't do anything. The event.value initailization and handling is ok, but for a counting loop this could be handled much better by using a counting variable and assigning event.value at the end. 

To continues, there's no "a" defined, so "a.value" doesn't mean anything. And there is no "Number" variable defined anywhere, so that code doesn't do anything either. 

Thom Parker - Software Developer at PDFScripting
Use the Acrobat JavaScript Reference early and often

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 08, 2020 May 08, 2020

I'm back to this project after a delay. I have redone my column field structure to the following:

 

 

 

 

check1.value.row      check2.value.row      check3.value.row
check1.value.row 1    check2.value.row 1    check3.value.row 1
check1.value.row 2    check2.value.row 2    check3.value.row 2
"
"
check1.value.row 30   check2.value.row 30   check3.value.row 30
check1.calc.total     check2.calc.total     check3.calc.total

 

 

 

The "value" fields are checkboxes, the "calc" fields are text boxes for the results of the number of boxes.

 

I'm doing a spawnable template setup for adding pages. Those pages will add on more field names to the front, so the following script pops off the last two names to use the assorted possible front name combinations, joins "value" to the name, and is to get the array of checkboxes in the column and tally if they're on and add the totals. The script below goes in the "calc" fields.

 

I have the script set up, but when I paste into the custom calculation script I get a syntax error on the last line where it's assigning the total to the event.value. I do not understand why this is a wrong syntax. I have other projects with "event.value = total" in them.

 

 

 

 

var aNameParts = event.targetName.split(".");
aNameParts.pop();
aNameParts.pop();
aNameParts.push("value");
var strColName = aNameParts.join(".");
var oColFldList = this.getField(strColName);
var total = 0;
oColFldList.getArray().forEach(if (this.value!="Off")) total++;
event.value = total;

 

 

 

  

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 09, 2020 May 09, 2020

Okay, I figured out that I wasn't using forEach properly. It needed a function. So here is the new version. But I'm still getting a "syntax error 7: at line 8". 

 

 

var aNameParts = event.targetName.split(".");
aNameParts.pop();
aNameParts.pop();
aNameParts.push("value");
var strColName = aNameParts.join(".");
var oColFldList = this.getField(strColName);
oColFldList.getArray().forEach(function(a,i){event.value=Number(i?event.value:0) + (if (a.value!="Off") Number++;)});

 

 

I'm not getting something right. I look at the function line and to me it says, "Get the array from the chosen fields, and for each of them do this function (value, index): get the event value by using 'Number' and starting at zero, then go through the array items and see if an item's value as a checkbox is not 'Off'. If so, then add one to the total of 'Number' .)

 

This seems sound. But apparently, it's not.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 10, 2020 May 10, 2020

Number++ looks not correct.

 

Try this:

var aNameParts = event.targetName.split(".");
aNameParts.pop();
aNameParts.pop();
aNameParts.push("value");
var strColName = aNameParts.join(".");
var oColFldList = this.getField(strColName);
var total = 0;
oColFldList.getArray().forEach(function(a,i,ar){if (a.value!="Off") total++;});
event.value = total;
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 10, 2020 May 10, 2020

Thank you for replying, Bernd. I added your code and it had no syntax error, so that's good. Trying it out has no result. Here are two screen shots showing an attempt to click the two boxes before the total with no results, and a shot with the script in place pointing at the correct field.

 

Screen Shot 2020-05-10 at 1.36.05 PM.pngScreen Shot 2020-05-10 at 1.35.42 PM.png

Also, I see you added "ar" to the array spot in the function. I assume that was a critical spot, and I must have understood wrong that that spot was optional on one reference I was checking. Is "Number" not a good variable name? I see you used "total" instead and declared it differently. I was basing the use of "Number" on a different script successfully used to calculate a sum on a different page in this document.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 10, 2020 May 10, 2020

Check the console for errors.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 10, 2020 May 10, 2020

Screen Shot 2020-05-10 at 2.09.45 PM.png

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 10, 2020 May 10, 2020

Looking at the errors in the Javascript Debugger, I'm not sure what to make of it. A variation of the top part of the script where I split the target name, pop the ends, join the "value" back to it in order to get the target array (guaranteeing that this page or any other spawned page with different prefixes from the field names works correctly) works perfectly without a hitch on another page in this document so I know that setup is proper.

 

Here is the other script that I'm referring to, and you can see that's it pretty much the same structure for collecting fields and it works perfectly in a setup for summing all text fields...

 

 

var aNameParts = event.targetName.split(".");
aNameParts.pop();
aNameParts.pop();
aNameParts.push("value");
var strColName = aNameParts.join(".");
var oColFldList = this.getField(strColName);
oColFldList.getArray().forEach(function(a,i){event.value=Number(i?event.value:0) + Number(a.value);});

 

 

So since this works, I don't see why the script we're working on wouldn't work. oColFldList should not be empty, and this.getField should also have info. You can see on the screen shot three replies up that the column structure is set up properly with "check1.value.row" as the column, and that is guaranteed consistent because of InDesign's repeating actions when duplicating. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 11, 2020 May 11, 2020

The script works for me:

testfile 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 11, 2020 May 11, 2020

I was going to extract a copy of the page and send it to you and then I got a warning "an incorrect file structure was found in the PDF file". That made me wonder if that was the reason why it wasn't working. I had to import the PDF file into a "combine files" document and resave it to fix that. I had to copy-paste the field group into the new document and..... IT WORKS! So it was my corrupt document holding it back.

Screen Shot 2020-05-11 at 9.56.54 AM.png

And thanks to you mentioning debugging, I learned how to do and fixed three improperly labelled fields on my other complicated javascript form, so you helped me fix another upcoming problem. THANK YOU.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 11, 2020 May 11, 2020

Successful final result....

 

Screen Shot 2020-05-11 at 10.47.51 AM.png

 And here is the final tally field's code to calculate the bottom rows. The Total days field is labled, "check13.calc.total" for reference. It loops through check1 to check12...

 

var total = 0;
for (var i=1; i<=12; i++) {

var aNameParts = event.targetName.split(".");
aNameParts.pop();
aNameParts.pop();
aNameParts.pop();
var strColName = aNameParts.join(".");
	total+=Number(this.getField(strColName+"."+"check"+i+".calc.total").valueAsString);
}
event.value = total;

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 10, 2020 May 10, 2020

You use a very complicated way to reinvent the wheel when you don't even need JavaScript to do this type of calculation.

The creation of the attached document took me less than 3 minutes, each checkbox have a "1" export value, each "total" field uses only one calculation (Acrobat's buit in calculation), the "grandTotal" field too.

The only difference compared to your request is that I named the fields "total" in a more logical way.

 

See this great sample PDF: https://documentcloud.adobe.com/link/track?uri=urn%3Aaaid%3Ascds%3AUS%3A1c732995-09a8-4dc3-ab3b-661a...

 


Acrobate du PDF, InDesigner et Photoshopographe
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 10, 2020 May 10, 2020

Oh it's a good example, JR, but I cannot use the built-in calculation because this document is going to have spawnable pages from a template to make copies, and each spawned page will have different field name prefixes. So I have to use the javascript code to take those different prefixes into account on new pages. If this was a one-pager situation then yes, I would have used the built-in calcation.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Engaged ,
May 13, 2020 May 13, 2020
LATEST

The correct answer also takes into account that spawnable pages of the form will create different prefixes on the field names. That need isn't evident in my original question.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines