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

Enhancing JavaScript code for Quick Navigation to Empty Fields

Contributor ,
May 21, 2024 May 21, 2024

I've a code snippet to pinpoint empty fields within a lengthy form. Ideally, the script sholuld guides me directly to the first blank field. But, if this proves challenging, I'd like it to provide the page number and the information from the tooltip associated with the empty field. My intention is to populate the tooltip with brief descriptions, facilitating rapid identification for users. While the current script effectively notifies me of empty fields names, I seek improvements: displaying the tooltip text instead of the field name and accurately identifying the page numbers, instead of zeros.

Thank you

 

This is the code:

var emptyFields = [];

var currentPage = this.pageNum;

for (var i = 0; i < this.numFields; i++) {
var fname = this.getNthFieldName(i);
var f = this.getField(fname);

if (f.type !== "button" && f.required === true) {
if (f.value === "" || f.value === "Off") {
var pageNum = getPageNumForField(f); // Call the function to get page number
var tooltip = f.tooltip;
if (tooltip) {
var tooltipInfo = "Page " + pageNum + ": " + tooltip;
emptyFields.push(tooltipInfo);
} else {
emptyFields.push("Page " + pageNum + ": " + "Field " + f.name);
}
}
}
}

if (emptyFields.length > 0) {
var message = "Please fill in the following required field(s):\n\n" + emptyFields.join("\n");
// Use a timeout to delay the alert
app.setTimeOut(function() {
app.alert({
cMsg: message,
cTitle: "Required Fields Check",
nIcon: 3, // Optional: set icon type (3 for warning icon)
nType: 0 // Optional: set type to OK button only
});
// Restore the original page number after the alert
this.pageNum = currentPage;
}.bind(this), 10); // Bind 'this' to ensure the correct context
}

function getPageNumForField(field) {
var page = field.page;
return page + 1; // Add 1 to convert from 0-based indexing
}

/*
function getPageNumForField(field) {
var page = field.page;
if (typeof page === 'number' && !isNaN(page)) { // Check if page is a valid number
return page + 1; // Add 1 for 1-based indexing (if applicable)
} else {
return "N/A"; // Return a placeholder for invalid page numbers
}
}

 

SaherNaji_0-1716294192558.pngexpand image

 

So instad of fields names I want to use the text in Tooltip, and we can ignore to use the real page number

 

tooltip.pngexpand image

 

 


Thank you

TOPICS
Acrobat SDK and JavaScript
1.3K
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

correct answers 2 Correct answers

Community Expert , May 21, 2024 May 21, 2024

Here is a shorter script where you can indicate the max number of fields to indicate in the alert box.

var maxAlerts=10; // Max fields indicated in the alert box
var emptyFields=[];
for (var i=0; i<this.numFields; i++) {
	if (emptyFields.length<maxAlerts) {
		var f=this.getField(this.getNthFieldName(i));
		if (f.type!="button" && f.required==true) {
			if (f.value=="" || f.value=="Off") {
				if (!emptyFields.length) var firstField=this.getNthFieldName(i);
				var thisPage=this.getPageLabel(f.pa
...
Translate
Community Expert , May 23, 2024 May 23, 2024

Hi,

I added a few lines between "BB Start" and "BB End".

 

 

function getPageNumForField(field) {
  // No longer used, can be removed
  // return field.page + 1; // Convert from 0-based to 1-based indexing
}

var emptyFields = [];
var maxAlerts = 10; // Max fields indicated in the alert box
var currentPage = this.pageNum; // Save the current page number (not used)
var firstField = null;

for (var i = 0; i < this.numFields; i++) {
  if (emptyFields.length < maxAlerts) {
    var fname = this.getNt
...
Translate
Community Expert ,
May 21, 2024 May 21, 2024

Hi,

Try that:

 

var emptyFields = [];
var currentPage = this.pageNum;
for (var i = 0; i < this.numFields; i++) {
	var fname = this.getNthFieldName(i);
	var f = this.getField(fname);
	if (f.type !== "button" && f.required === true) {
		if (f.value === "" || f.value === "Off") {
			var pageNum = getPageNumForField(f); // Call the function to get page number
			if (f.userName) emptyFields.push(f.userName);
			else emptyFields.push("Page " + pageNum + ": " + "Field " + f.name);
		}
	}
}
if (emptyFields.length > 0) {
	var message = "Please fill in the following required field(s):\n\n" + emptyFields.join("\n");
	// Use a timeout to delay the alert
	app.setTimeOut(function() {
		app.alert({
			cMsg: message,
			cTitle: "Required Fields Check",
			nIcon: 3, // Optional: set icon type (3 for warning icon)
			nType: 0 // Optional: set type to OK button only
		});
		// Restore the original page number after the alert
		this.pageNum = currentPage;
	}.bind(this), 10); // Bind 'this' to ensure the correct context
}

function getPageNumForField(field) {
	return this.getPageLabel(field.page);
}

 

@+

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
Contributor ,
May 21, 2024 May 21, 2024

Thanks @bebarth 
I updated it like this, and it's working very well now

function getPageNumForField(field) {
    var page = field.page;
    return page + 1; // Add 1 to convert from 0-based indexing
}

var emptyFields = [];

// Save the current page number
var currentPage = this.pageNum;

for (var i = 0; i < this.numFields; i++) {
    var fname = this.getNthFieldName(i);
    var f = this.getField(fname);
    
    if (f.type !== "button" && f.required === true) {
        if (f.value === "" || f.value === "Off") {
            var pageNum = getPageNumForField(f); // Call the function to get page number
            if (f.userName) {
                emptyFields.push("Page " + pageNum + ": " + f.userName);
            } else {
                emptyFields.push("Page " + pageNum + ": " + "Field " + f.name);
            }
        }
    }
}

if (emptyFields.length > 0) {
    var message = "Please fill in the following required field(s):\n\n" + emptyFields.join("\n");
    app.alert({
        cMsg: message,
        cTitle: "Required Fields Check",
        nIcon: 3, // Optional: set icon type (3 for warning icon)
        nType: 0 // Optional: set type to OK button only
    });
}

// Restore the original page number after the alert
this.pageNum = currentPage;
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
Contributor ,
May 21, 2024 May 21, 2024

But if we could update it to take us the the first empty field without any messages this will better

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
Contributor ,
May 21, 2024 May 21, 2024

Oh,
I tested it with many empty fields, and here are the result:

 

SaherNaji_0-1716296812932.pngexpand image

 

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 21, 2024 May 21, 2024

- To go to the first empty field you need to save its name in a variable, say "firstEmptyfield" and then add this command to your code:

this.getField(firstEmptyField).setFocus();

- You need to limit the length of your message in the alert window. You can do that by only saving the first X number of fields to the array, for example like this:

if (emptyFields.length<30) emptyFields.push("Page " + pageNum + ": " + "Field " + f.name);

 

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
Contributor ,
May 21, 2024 May 21, 2024

Hi @try67 

Thank you

I didn't quite understand why I should save the first empty field name. I don't know which field will be the first empty one, especially since many users will be using this form and might forget to fill out some fields.

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 21, 2024 May 21, 2024

You still have a couple of issues with the script. 

1) the field page number is an array of number if the field has more than one instance. The getPageNumForField function needs to be modified.

2) What's an empty field? What if it contains a single space, is it still emtpy?

3) What's the first field? The geometry of the form does not necessarily match the field order. 

 

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
Contributor ,
May 21, 2024 May 21, 2024

Hi @Thom Parker 
I can abandon the idea of using code to get the correct page numbers. Instead, I can manually type the page number in each tooltip for each field. However, I'm not a JavaScript programmer; all I can do is piece together some lines of code. How should I proceed?

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 21, 2024 May 21, 2024

Here is a shorter script where you can indicate the max number of fields to indicate in the alert box.

var maxAlerts=10; // Max fields indicated in the alert box
var emptyFields=[];
for (var i=0; i<this.numFields; i++) {
	if (emptyFields.length<maxAlerts) {
		var f=this.getField(this.getNthFieldName(i));
		if (f.type!="button" && f.required==true) {
			if (f.value=="" || f.value=="Off") {
				if (!emptyFields.length) var firstField=this.getNthFieldName(i);
				var thisPage=this.getPageLabel(f.page);
				if (f.userName) emptyFields.push(f.userName);
				else emptyFields.push("Page "+thisPage+": "+"Field \""+f.name+"\"");
			}
		}
	} else break;
}
if (emptyFields.length) {
	var message="Please fill in the following required field(s):\n\n"+emptyFields.toString().replace(/,/g, "\r");
	app.alert({
		cMsg: message,
		cTitle: "Required Fields Check",
		nIcon: 3
	});
	this.getField(firstField).setFocus();
}

Let me know.

@+

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
Contributor ,
May 21, 2024 May 21, 2024

Hi @bebarth 
Thanks, acutlly it did not run quickly, so I did some quickly edits, now this is the updated code:

function getPageNumForField(field) {
    return field.page + 1; // Convert from 0-based to 1-based indexing
}

var emptyFields = [];
var maxAlerts = 10; // Max fields indicated in the alert box
var currentPage = this.pageNum; // Save the current page number
var firstField = null;

for (var i = 0; i < this.numFields; i++) {
    if (emptyFields.length < maxAlerts) {
        var fname = this.getNthFieldName(i);
        var f = this.getField(fname);
        
        if (f.type !== "button" && f.required === true) {
            if (f.value === "" || f.value === "Off") {
                if (!firstField) firstField = fname; // Save the first empty field name
                var pageNum = getPageNumForField(f); // Get page number using the function
                
                // Check if getPageLabel method exists and is valid
                var pageLabel;
                try {
                    pageLabel = this.getPageLabel(f.page);
                } catch (e) {
                    pageLabel = pageNum; // Fallback to page number if getPageLabel fails
                }
                
                if (f.userName) {
                    emptyFields.push("Page " + pageLabel + ": " + f.userName);
                } else {
                    emptyFields.push("Page " + pageLabel + ": " + "Field \"" + f.name + "\"");
                }
            }
        }
    } else {
        break;
    }
}

if (emptyFields.length > 0) {
    var message = "Please fill in the following required field(s):\n\n" + emptyFields.join("\n");
    app.alert({
        cMsg: message,
        cTitle: "Required Fields Check",
        nIcon: 3, // Warning icon
        nType: 0  // OK button only
    });
    
    if (firstField) {
        this.getField(firstField).setFocus();
    }
}

// Restore the original page number after the alert
this.pageNum = currentPage;

 

 and this is the result:

 

SaherNaji_0-1716311283052.pngexpand image

it's okay, the list now is perfect, thanks for that, but how could I use the Tooltip text instead of the field name?

also I want to ignore at all the page number, I prefer to write it into the Tooltip itself

 

Thanks again

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 21, 2024 May 21, 2024

For the tooltip, use the userName property!

@+

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
Contributor ,
May 21, 2024 May 21, 2024

@Thom Parker @try67 @bebarth 

 

Thank you very much, all of you, I did it and used this code

 

function getPageNumForField(field) {
  // No longer used, can be removed
  // return field.page + 1; // Convert from 0-based to 1-based indexing
}

var emptyFields = [];
var maxAlerts = 10; // Max fields indicated in the alert box
var currentPage = this.pageNum; // Save the current page number (not used)
var firstField = null;

for (var i = 0; i < this.numFields; i++) {
  if (emptyFields.length < maxAlerts) {
    var fname = this.getNthFieldName(i);
    var f = this.getField(fname);
  
    if (f.type !== "button" && f.required === true) {
      if (f.value === "" || f.value === "Off") {
        if (!firstField) firstField = fname; // Save the first empty field name
      
        if (f.userName) {
          emptyFields.push(f.userName);
        } else {
          emptyFields.push("Field \"" + f.name + "\"");
        }
      }
    }
  } else {
    break;
  }
}

if (emptyFields.length > 0) {
  var message = "Please fill in the following required field(s):\n\n" + emptyFields.join("\n");
  
  // **Assuming app.alert supports tooltips (modify as needed):**
  app.alert({
    cMsg: message,
    cTitle: "Required Fields Check",
    nIcon: 3, // Optional: set icon type (3 for warning icon)
    nType: 0 // Optional: set type to OK button only
  });
  
  if (firstField) {
    this.getField(firstField).setFocus();
  }
}

// No longer needed as page number is not used
// this.pageNum = currentPage;

 

and this is the result I want

SaherNaji_0-1716322212565.pngexpand image

 

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 21, 2024 May 21, 2024

For the page number the best thing to do is use the first one. Unless it's a field on a page template, then the first number will be -1.

 

Here's an update of the function, it returns 0 if the field does not exist on a real page.

function getPageNumForField(field) {
  var num = null;
  if(typeof(field.page) != "number")
     num = (field.page[0] == -1)?field.page[1]:field.page[0];
  else
     num = field.page;

  return num + 1;
}

 

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
Contributor ,
May 21, 2024 May 21, 2024

Thanks @Thom Parker 

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
Contributor ,
May 23, 2024 May 23, 2024

Now I have this updated code:

function getPageNumForField(field) {
  // No longer used, can be removed
  // return field.page + 1; // Convert from 0-based to 1-based indexing
}

var emptyFields = [];
var maxAlerts = 10; // Max fields indicated in the alert box
var currentPage = this.pageNum; // Save the current page number (not used)
var firstField = null;

for (var i = 0; i < this.numFields; i++) {
  if (emptyFields.length < maxAlerts) {
    var fname = this.getNthFieldName(i);
    var f = this.getField(fname);
  
    if (f.type !== "button" && f.required === true) {
      if (f.value === "" || f.value === "Off") {
        if (!firstField) firstField = fname; // Save the first empty field name
      
        if (f.userName) {
          emptyFields.push(f.userName);
        } else {
          emptyFields.push("Field \"" + f.name + "\"");
        }
      }
    }
  } else {
    break;
  }
}

if (emptyFields.length > 0) {
  var message = "Please fill in the following required field(s):\n\n" + emptyFields.join("\n");
  
  // **Assuming app.alert supports tooltips (modify as needed):**
  app.alert({
    cMsg: message,
    cTitle: "Required Fields Check",
    nIcon: 3, // Optional: set icon type (3 for warning icon)
    nType: 0 // Optional: set type to OK button only
  });
  
  if (firstField) {
    this.getField(firstField).setFocus();
  }
}

// No longer needed as page number is not used
// this.pageNum = currentPage;

 

Is there a way to sort the tooltip texts which appear in the window below from A to Z?
Page 1...
Page 2...
Page 3...

and not like this:

Page 1
Page 2
Page 32
Page 33
Page 6
Page 7

and when I click the button, it should take me to the first field in this list.

 

SaherNaji_0-1716476703393.pngexpand image

 

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
Community Expert ,
May 23, 2024 May 23, 2024

Hi,

I added a few lines between "BB Start" and "BB End".

 

 

function getPageNumForField(field) {
  // No longer used, can be removed
  // return field.page + 1; // Convert from 0-based to 1-based indexing
}

var emptyFields = [];
var maxAlerts = 10; // Max fields indicated in the alert box
var currentPage = this.pageNum; // Save the current page number (not used)
var firstField = null;

for (var i = 0; i < this.numFields; i++) {
  if (emptyFields.length < maxAlerts) {
    var fname = this.getNthFieldName(i);
    var f = this.getField(fname);
  
    if (f.type !== "button" && f.required === true) {
      if (f.value === "" || f.value === "Off") {
        if (!firstField) firstField = fname; // Save the first empty field name
      
        if (f.userName) {
          emptyFields.push(f.userName);
        } else {
          emptyFields.push("Field \"" + f.name + "\"");
        }
      }
    }
  } else {
    break;
  }
}

if (emptyFields.length > 0) {
	// BB Start
	for (var i=0; i<emptyFields.length; i++) emptyFields[i]=[emptyFields[i],Number(emptyFields[i].substring("Page ".length,emptyFields[i].indexOf("-")))];
	emptyFields.sort(function(a, b){return a[1]-b[1]});
	for (var i=0; i<emptyFields.length; i++) emptyFields[i].pop();
	// BB End
	
  var message = "Please fill in the following required field(s):\n\n" + emptyFields.join("\n");
  
  // **Assuming app.alert supports tooltips (modify as needed):**
  app.alert({
    cMsg: message,
    cTitle: "Required Fields Check",
    nIcon: 3, // Optional: set icon type (3 for warning icon)
    nType: 0 // Optional: set type to OK button only
  });
  
  if (firstField) {
    this.getField(firstField).setFocus();
  }
}

// No longer needed as page number is not used
// this.pageNum = currentPage;

 

 

 Please try and let me know...

@+

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
Contributor ,
May 23, 2024 May 23, 2024

Thank you very much @bebarth,

It's working and sorts the list from A to Z.

But there's one final thing: why does the code take me to this item? It should take me to Page 1 - (Do you ever ...).

 

SaherNaji_0-1716486279517.pngexpand image

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 23, 2024 May 23, 2024

Sorry but I don't understand ! This page should be Page 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
Contributor ,
May 23, 2024 May 23, 2024

This window is accurate, and I thank you for the lines you wrote.

When I click OK in this window, it directs me to field 13 ("Very hard events...") on page 7. However, the correct logic is for it to go to page 1 to fill in the field ("Do you ever confide in...").

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
Contributor ,
May 23, 2024 May 23, 2024
LATEST

I did it thank you

var emptyFields = [];
var maxAlerts = 10; // Max fields indicated in the alert box
var fieldsMap = {}; // Map to store the field name associated with each tooltip text

for (var i = 0; i < this.numFields; i++) {
  if (emptyFields.length < maxAlerts) {
    var fname = this.getNthFieldName(i);
    var f = this.getField(fname);

    if (f.type !== "button" && f.required === true) {
      if (f.value === "" || f.value === "Off") {
        var tooltipText = f.userName || "Field \"" + f.name + "\"";
        fieldsMap[tooltipText] = fname; // Store the field name associated with the tooltip text
        emptyFields.push({ tooltip: tooltipText, name: fname });
      }
    }
  } else {
    break;
  }
}

if (emptyFields.length > 0) {
  emptyFields.sort(function(a, b) {
    // Extract page numbers from tooltip texts and compare them numerically
    var pageA = parseInt(a.tooltip.match(/Page (\d+)/)[1], 10);
    var pageB = parseInt(b.tooltip.match(/Page (\d+)/)[1], 10);
    return pageA - pageB;
  });

  var message = "Please fill in the following required field(s):\n\n" + emptyFields.map(function(field) {
    return field.tooltip;
  }).join("\n");

  // Display the alert with the sorted tooltip texts
  app.alert({
    cMsg: message,
    cTitle: "Required Fields Check",
    nIcon: 3, // Optional: set icon type (3 for warning icon)
    nType: 0 // Optional: set type to OK button only
  });

  // Get the field name for the first sorted tooltip text
  var firstField = emptyFields[0].name;
  if (firstField) {
    this.getField(firstField).setFocus();
  }
}
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