How do I reference multiple pages/subpages?

Broklynite

09-12-2015

I suppose that this ultimately can apply to objects as well as pages. At the moment though, I'm really more concerned with pages and subpages.

I want to hide/show multiple pages based on a drop-down menu selection. I have of course searched regarding this subject. Nobody seems to be quite asking for what I'm asking, and the most closely related questions only answer for a single object rather than multiple.

I have a dropdown menu that, depending on the selection, certain pages and subpages which were previously hidden become visible. However, I am trying to build in a certain forgiveness, so that if someone accidentally selects the wrong item on the dropdown menu and goes back to correct themselves, either (1) all of the associated pages will go back to their default state of hidden, before continuing forward and making certain selections visible, or (2) each object is manually named and told to go back to being hidden.

The only way I've found to do this is as follows:

switch (newValue)

{

     case "1":

this.resolveNode("subpage_1").presence = "visible";

this.resolveNode("subpage_2").presence = "hidden";

this.resolveNode("page_3").presence = "hidden";

     break;

    case "2":

this.resolveNode("subpage_1").presence = "hidden";

this.resolveNode("subpage_2").presence = "visible";

this.resolveNode("page_3").presence = "hidden";

     break;

    case "3":

this.resolveNode("subpage_1").presence = "hidden";

this.resolveNode("subpage_2").presence = "hidden";

this.resolveNode("page_3").presence = "visible";

    break;

}

This is tedious, time consuming, and inelegant. What I'd like to do instead is address multiple objects simultaneously. Something like:

switch (newValue)

{

     case "1":

         this.resolveNode("subpage_2", "page_3").presence = "hidden";

         this.resolveNode("sabpage_1").presence = "visible";

    break;

     case "2":

          this.resolveNode("subpage_1", "page_3").presence = "hidden";

          this.resolveNode("subpage_2").presence = "visible";

     break;

     case "3":

          this.resolveNode("subpage_1", "subpage_2").presence = "hidden";

         this.resolveNode("page_3").presence="visible";

      break;

}

I'm aware that this is seen as inelegant in and of itself, but given the overall design of the sheet, the naming scheme, etc, there's really no way to have the system call all pages or subpages starting with the same letters and such. So I'd have to name each one individually. And that's fine! But I've tried a million methods to no avail. I just want a more condense way to hide/make visible multiple pages and subpages simultaneously, or barring that to reset the visibility to the default.

Accepted Solutions (1)

Accepted Solutions (1)

radzmar

MVP

10-12-2015

With an array and the forEach() method you can write a very compact script to do what you're after.


var aObjects = [[subpage_1, "1"], [subpage_2, "2"], [page_3", "3"]],


  cSelection = xfa.event.change;


// Loop through all elements in the array…


aObjects.forEach(function (element) {


    //… and set its presence


    // element[0] is the first value of the nested array i.e. "subpage_1", element[1] is the second value i.e. "1"


    element[0].presence = element[1] === cSelection ? "visible" : "hidden";


});


Answers (5)

Answers (5)

Broklynite

15-06-2016

So, I've been using Radzmar's solution for a while now, and that solution works very well up to a point. However, it begins to become ungainly as the number of subforms which must be addressed grows larger (I'm currently at 50, and it'll only go up).

So with that said, is there a way in Javascript to refer to a subform as well as all of its subforms? Yes, I know that the highest subform in the hierarchy is always dominant (so if a page is set to hidden, all of the subforms within it are hidden). However, my hierarchy is such that there are nested subforms which need to be individually referenced when making them visible. That in turn means each must be addressed in order to hide them.

What would be significantly easier is if I could say "This form AND ALL subforms below it in the hierarchy" presence = hidden.

Let's say my hierarchy was as follows:

     form1

          Page 1

          Page 2

               Subform1

                    Subsubform1

               Subform2

                    Subsubform2

                    Subsubform3

               Subform3

          Page 3

               Subform1

               Subform2

               Subform 3

          Page 4

               Subform1

               Subform2

               Subform3

Page 1 is where selections are made to build the document. But if somebody makes a mistake, they can choose something else and in doing so, hide all the old info. Some selections may end up with more pages than others, so as a result, I need to be able to code something where

1. Change in dropdown menu occurs

2. Page 2 and all subforms and all subsubforms presence set to hidden

3. Page 3 and all subforms and all subsubforms presence set to hidden

4. Page 4 and all subforms and all subsubforms presence set to hidden

What would be better is if I could set an exception to that. For example, I have a subform which is set to visible on all pages regardless of if the page is hidden or not. That's because it contains elements like a digital signature which can not be put into a Master Page.

However, in the choice between growing that named array ever longer, element by element, or having something clean and clear and just telling it to make two subforms visible instead of one when a page is called up, I would prefer the latter.

Broklynite

11-12-2015

Oh, WOW that works beautifully! I didn't even have to change *anything* except the object names. I had figured I'd need to change at least a few things, but nope, it's lovely. Thank you so much!

_Bruce_Robertson

MVP

10-12-2015

Hi,

You understanding is correct.  The resolveNodes method returns a list of the same objects as your original resolveNode method returned ... so you can reference the presence property.

Using "#subform" refers to a object by it's class, so all subforms with a name property that matches, in this case.  You could also use #field for all fields in a subform,

If you form structure is more complex I think radzmar's approach gives you more flexibility.

Regards

Bruce

Broklynite

10-12-2015

You're absolutely correct, I meant pages and subforms.

So, in some cases the subforms will be on the same page, while other times they will be on different pages. And in turn, some pages might become hidden altogether.

If I'm understanding this correctly:

var subforms = this.resolveNodes('#subform.[oneOf(name, "page_3", "subpage_1")]'); 


variable subforms is an array consisting of the names (? named object/elements?) page_3 and subpage_1.  I'm not sure what the #subform is for.


for (var i = 0; i < subforms.length; i++) {


This bit is picking through each item in the array


    subforms.item(i).presence = "hidden";


and then setting them to hidden


Is that more or less correct?

_Bruce_Robertson

MVP

10-12-2015

Hi,

I'm not sure what you mean by pages and subpages, but assume these are just subforms (and are all at the same level), in which case you could use a predicate in the resolveNodes method, so;

var subforms = this.resolveNodes('#subform.[name == "page_3" or name == "subpage_1"]');

for (var i = 0; i < subforms.length; i++) {

    subforms.item(i).presence = "hidden";

}

 

The bit between the square brackets is a FormCalc expression, so it might be neater to use the oneOf function, that is;

var subforms = this.resolveNodes('#subform.[oneOf(name, "page_3", "subpage_1")]'); 

Regards

Bruce