Stefan Cameron on Forms
Building intelligent forms using Adobe LiveCycle Designer

Conditional Breaks

Some of you have requested a sample of the new Conditional Breaks feature in Designer 7.1.

This feature allows you to set conditions, based on imported data, which determine when breaks should occur.

For example, you may have data that you want to list by category and every time the category changes, you’d like to start the new category on a new page. Or, you may have a separator that you want to insert in between sets of data on your form.

I’ve created a little sample which demonstrates the Conditional Breaks feature by listing some movie data where each time the category changes, a new page starts. Don’t forget to import the data.xml file into the form when you open it in Acrobat.

Download Sample [zip]

Minimum Requirements: Designer 7.1, Acrobat 7.0.5.

Note: A basic understanding of Data Binding is required for this sample.

Since breaks are only really useful inside flowed subforms (there’s no point setting breaks on a subform inside a positioned container since the data won’t flow — it’ll all stay in one place instead of flowing left-to-right, top-to-bottom, for example), you can only get to the Conditional Break settings on the Object palette’s Pagination tab if you select a subform inside a flowed container (subform). The only exception is selecting a row or a section within a Table object since the content of Tables is always flowed.

Typically, after creating a new form, you would add a positioned subform (let’s call it the ContentSubform) to the page and add the fields you need into it. You would then make the page subform flowed (set the Content property on the Object palette’s Subform tab to Flowed), then select the ContentSubform and click on the Edit button on the Object palette’s Pagination tab. This will open the Conditional Breaks Dialog where you can add multiple conditions for that subform’s breaks.

In my sample, the data represents movies and each movie record has the following information:

  • Category
  • Title
  • Actor

Since I wanted to create a report-style form where a change in category breaks to a new page and a change in the actor’s name is preceeded by a separator, I created a movie subform which lists the data and then two other subforms:

  1. NewCategorySF which I want to insert every time the category changes.
  2. NewActorSF which I want to insert every time the actor’s name changes.

I then specified two conditional breaks on the movie subform:

  1. The first one checks for a change in the category data. When a change occurs, the layout will break to the top of a new instance of the “page 1” subform and, before starting to list the data for the new category, insert an instance of the NewCategorySF subform. This is what we call a Break Before Conditional Break (since the break occurs before the new record, which contains the new category name, is inserted into the form). Notice that the NewCategorySF subform is listed as a Leader for the Conditional Break because it’s meant to be inserted after the break but before the new record gets inserted into the form.
  2. The second checks for a change in the actor data. When a change occurs, the layout will not actually break because we simply want to use the Conditional Break to know when to insert the NewActorSF to separate the data set into sub-groups of actors. In this case, I specified NewActorSF to be a Leader for the Conditional Break because I wanted it to show-up after the actual break but before the new record is inserted into the form. You may wonder why I didn’t make it a Trailer but in this case, there wouldn’t be any difference since there isn’t an actual “physical” break in the data flow (to a new page or content area, for example).

Also notice that the NewCategorySF and NewActorSF subforms are both set to Repeat for Each Data Item (you can set this on the Object palette’s Binding tab) with a Min Count of 1 so that they always appear before the very first data record is inserted into the form. Otherwise, they wouldn’t appear until the first Conditional Break occurs.


Posted by Stefan Cameron on May 6th, 2006
Filed under Conditional Breaks,Tutorials
Both comments and pings are currently closed.

31 Responses to “Conditional Breaks”

  1. Cindy on May 24th, 2006

    The link to this site isn’t working…has it moved?
    thanks

  2. Stefan Cameron on May 25th, 2006

    Cindy,

    The only link in this post is the one to the sample file. I just tried it and it worked fine for me. Please give it another try. It’s possible the server was in the process of rebuilding my blog at the moment when you tried to download the file.

  3. jay on July 6th, 2006

    This is very interesting site

  4. Howard Treisman on August 28th, 2006

    Hi Stefan

    I noticed that if you specify a leader or trailer subform, and that subform is set to “Flowed”, then the form doesn’t render properly. This is quite simple to try. Do you have an magic for making this work?
    Many thanks,
    Howard

  5. Stefan Cameron on August 28th, 2006

    Howard,

    I’m going to take a guess as assume that you’re seeing an extra page immediately when you create the Conditional Break.

    This can happen if you haven’t yet set a condition script for the break because having no condition script is the same as having a condition script that always returns true and therefore always causes the break to execute.

    Since Designer’s WYSIWYG design-time rendering tries to execute the breaks that it can, it immediately executes the conditional break you just specified simply because it has no condition.

    Try specifying a condition script and see what happens. The form should go back to “normal”.

  6. Varun Shah on November 8th, 2006

    Hi ,
    I have one doubt.

    If a table has 20 records(i.e Rows ) , I want to write a conditional break statement in such a way that i should display first 10 records from the table and after some pages, I should be able to display the remaining data from the table.

  7. Stefan Cameron on November 13th, 2006

    Varun,

    I decided to enlist the help of a colleague of mine here at Adobe in order to answer your question. Here’s what he said:

    Since form content is laid out in a contiguous manner, there is no stopping within a table (say after 10 rows), jumping to other form content, and then back to the other rows again.

    However, there are ways to break from one page to another and emit intermediate pages (“skip over pages”) along the way. Obviously the only objects on the “skipped over” pages will be whatever is defined as the master page content.

    Remember that pageAreas support occurrence information (<occur/> property) so you would use an ordered pageSet, and setup pages with <occur min=”1″/> in order to ensure these pages get emitted. Then, depending on how you wanted to group the pageAreas, you could ensure that when you break to a page “B”, that one or more intermediate pages were emitted.

    Here’s an example:

    <subform name=”root”>
      <pageSet relation=”ordered”>
        <pageArea name=”PageA”>
          …page background objects…
        </pageArea>

        <pageArea name=”X”>
          <occur min=”1” />
          …page background objects…
        </pageArea>

        <pageArea name=”Y”>
          <occur min=”1” />
          …page background objects…
        </pageArea>

        <pageArea name=”PageB”>
          …page background objects…
        </pageArea>
      </pageSet>
      …form content…
    </subform>

    Say the first 10 rows were on “PageA”. A conditional break on the 11th row to “PageB” would cause one instance of page “X” and one instance of page “Y” to be emitted as well. Depending on how the form is designed, you may wish to protect against inadvertent X/Y instances coming out –- as it’s defined now X/Y will be emitted anytime you jump from “PageA” to any page defined lower down. This may or may not be desirable. To ensure that X/Y were emitted when a break to “PageB” occurred you could nest pageSets, something like this:

    <subform name=”root”>
      <pageSet relation=”ordered”>
        <pageArea name=”PageA”>
          …page background objects…
        </pageArea>

        <!– This nested pageSet packages PageB with X/Y. Effectively any jump to PageB will cause X+Y to also be emitted –>
        <!– Note that in such cases pages X/Y could be ‘boilerplate’ pages, i.e. pageAreas with no contentAreas –>
        <pageSet relation=”ordered”
          <pageArea name=”X”>
            <occur min=”1”/>
              …page background objects…
          </pageArea>

          <pageArea name=”Y”>
            <occur min=”1”/>
              …page background objects…
          </pageArea>

          <pageArea name=”PageB”>
            …page background objects…
          </pageArea>
        </pageSet>
      </pageSet>
      …form content…
    </subform>

    Adam
    Adobe Systems

    To summarize, you can do what you were asking but only to some degree since the pages that get “skipped” must be master pages (or “background content” as Adam referred to them). Fields you place on master pages will still be functional but they operate on a global basis rather than within the context of a page subform like body page fields do.

    Also, you’ll need to use the XML Source view in order to achieve the nested pageSet solution that Adam proposed since Designer doesn’t currently let you add pageSets (collections of master pages) in Design view. You can, however, use the “Restrict Page Occurrence” property on the Master Page tab of the Object palette (which you get when you select a master page using the Hierarchy palette) in order to set each page’s <occur min=”1″/> property.

  8. KP Shankar on June 6th, 2007

    Dear Stefan,

    How can I add a hyperlink to a PDF using Designer. As of now I am using a transparent button over a label. Is there any hyperlink object in designer?
    And how can I add a (dynamically growing )bullet list in designer. I have tried using script and achieved this to some extent but want to knww whether Designer has some standard object for bulleted list. In the “conditional break” sample file, you have a link. I tried opening the sample file using designer but was propmted for a password.So could not find how you added the link.

  9. Stefan Cameron on June 9th, 2007

    KP Shankar,

    At this time, there is no hyperlink object in Designer. Using a transparent button over a label (or simply editing the button’s Appearance property to remove its 3D borders and fill color and specifying a blue underlined font) is the closest you can get to a hyperlink.

    As for bulleted lists, there isn’t any standard object that achieves this functionality. My first guess is that you would have to use a repeating subform containing circle object for the bullet and a read-only text field without a caption and borders as the bullet text. You would then add/remove instances of the repeating subform as needed to grow/shrink the bulleted list. I’m happy to work through it with you if you like. I wish there was an easier, non-scripting, answer but I’m afraid there isn’t in this case.

    Finally, the file that contains the hyperlink in this article’s sample files is the readme file which is just a Microsoft Word file converted into PDF and protected with a permissions password to prevent modifications. There is no form in this file so I don’t recommend you attempt to load it into Designer. The actual sample form file is “CondBreakSample.pdf”. Sorry about the confusion!

  10. KP Shankar on June 22nd, 2007

    Hi Stefan,

    I am still working on the bullet lists. I need to capture the backspace key press in the change event of a textfield. But I find it difficult to do that. As of now I
    am able to capture the “Enter” and other key press but not Backspace. Is there any way for identifying whether backspace was pressed in the field. I add a new
    instance in the “Enter” key press (using ‘\u000a’ ). Now I need to capture the Backspace keypress to delete the empty instance. I tried using (‘\u0008’-Backspace)
    but it was of no use. Is there anything like “xfa.event.keycode”(similar to ‘window.event.keycode’ ) so that I can compare to the keycode of backspace.

    Thanks,
    KP Shankar

  11. Stefan Cameron on June 23rd, 2007

    KP Shankar,

    Wouldn’t it be easier to simply check the new value of the text field in its Exit event? If the value isn’t an empty string, then add a new instance and set focus to it. Otherwise, remove that instance of the text field and set focus to the previous instance…

  12. suchita on July 2nd, 2007

    Hi Stefan,

    I want to capture the “Enter” keypress. It would be very helpful if you could provide me with the script for this

  13. Stefan Cameron on July 14th, 2007

    suchita,

    I did some digging in various documentation modules and couldn’t find a way to determine the key that was pressed. Your best bet is to use the Change event on a text edit field, for example, to access the “xfa.event.newText” property and compare it to the field’s current (as-yet-unchanged) value. The “xfa.event.newText” property will contain the new value that will be assigned to the field once the Change event completes. Using that event, you should be able to determine whether the backspace key was pressed (e.g. if there’s a character missing in xfa.event.newText compared to this.rawValue).

    As for the Enter key, the Exit event fires whenever input focus is removed from a field. Since input focus is removed when the Enter key is pressed, that should be a good indication that the Enter key may have been pressed. Unfortunately, this event will also occur if the user clicks away from the field. Once again, you would probably have to look at (i.e. parse) the current value (this.rawValue) of the field to determine if any bullets should be added/removed.

  14. anil on September 5th, 2007

    Hi stefan ,

    I want a table to break after 27 rows are reached and show the remaining occurences in the next page .
    can u tel me wt is the code that v need to do in the EDIT CONDITIOANL TAB for acheiving this functionality .

    Thanks
    ANIL

  15. Stefan Cameron on September 16th, 2007

    anil,

    Unfortunately, in order to do that you would need access to what is know as the “Form DOM” (Form Document Object Model) from the Conditional Break’s “condition” and the only DOM you can access from there is the Data DOM (the model that gives you access to the values of the various data records as data is being merged into your form).

    The only way I can think of that you could do this is by numbering the records in your data file and specify a condition statement that causes a break when a specific data item in the current data record is larger than 27.

  16. KX on February 27th, 2008

    Stefan,
    Can you elaborate a little bit on what you meant in the previous post by accessing “Form DOM” vs. Data DOM. Do you have any examples by any chance?

  17. Stefan Cameron on March 3rd, 2008

    KX,

    When a form is loaded in Acrobat/Reader, there are a few DOMs (Document Object Models) that come into play. The two most important ones are the Form DOM and the Data DOM. The Form DOM is what you access when you get/set properties of form objects (e.g. setting an object’s presence) while the Data DOM is what contains the data that’s loaded into the form.

    The “root” of the Form DOM is “xfa.form…” but it’s implicit whenever you access a property (or a related object) of an object on your form.

    The “root” of the Data DOM is “xfa.datasets…”

    What anil was trying to do implied accessing a form object property in the condition script associated with a Conditional Break. Unfortunately, condition scripts may only access form data (that lives in the Data DOM).

  18. Sejal on March 18th, 2008

    How can i create a conditional break that will output a few lines from another table based on some criteria?

    For example, I have some line items on an invoice that I am printing. When the type of material changes on the line item, I want to output some text from another table that matches that material.

    Any help would be greatly appreciated.

    Thanks!

  19. Stefan Cameron on March 20th, 2008

    Sejal,

    Based on your description of the problem, it doesn’t sound like a conditional break is the right thing to use. What you should be doing is using the Change or Exit event of the field that holds the material type data to output the text to the other table by setting the value of a field in that other table or by adding more rows to the table (using the Instance Manager).

  20. Ian on May 22nd, 2008

    Hi Stefan,

    Just wondering if this only works with imported data because i am currently facing a problem where i have a table which users can add rows to and it does not perform a page break when the table becomes too large to fit into 1 page instead it just carry on adding and goes off the page. Its there a way i can solve that using the conditional break?

    Many thanks

  21. Laura H. on May 23rd, 2008

    Is there any way to prevent the Text objects from automatically hyperlinking text with protocols? I have an http(s) and 2 mailtos that I want to be text, but not be actual links. I’ve looked in the XML, but it’s not generating a link element, so something is automatically processing it. I see no options or settings I can turn on or off. Any ideas?

  22. Stefan Cameron on May 28th, 2008

    Ian,

    The problem you’re describing is actually due to the fact that the page on which you have placed the table has a positioned layout rather than a flowed layout. When the layout is positioned, the page doesn’t resize to accommodate changes in its content (i.e. the table). Rather, the content is simply cut-off at the bottom of the page.

    To fix this, select the page and set the “Object palette > Subform tab > Content property” to “Flowed” instead of “Positioned”.

  23. Stefan Cameron on May 28th, 2008

    Laura H.,

    Unfortunately, I don’t have any suggestions for this one. The auto-detection of hyperlinks is something Acrobat is doing when it loads the form and inspects the text objects. There might be setting in Acrobat that you can set to prevent this behaviour but that would only solve the problem on your system…

  24. fursten on January 12th, 2009

    Stefan,

    In a previous post in this thread you said:

    “The only way I can think of that you could do this is by numbering the records in your data file and specify a condition statement that causes a break when a specific data item in the current data record is larger than 27.”

    If the records are numbered, let´s say by a rownumber field, what expression must we use to break a table for each 27 group of records (27; 54; etc.)?

    Thank you

  25. Stefan Cameron on January 15th, 2009

    fursten,

    I believe it would be something like

    rowNumber.value > 0 && rowNumber.value % 27 == 0

    in JavaScript.

  26. David on October 8th, 2009

    Hi,

    How can we count the number of Action category? Also, at the second page after you click on the preview, we can see the NewActor alone at the bottom and the remain information at right on the top on the same page. How can we force to move the NewActor on the top with the remain of the information?

    thks

  27. Stefan Cameron on October 16th, 2009

    David,

    There are many ways you could figure-out the number of Actor categories. One would be to get a list of <movie> nodes from the data and iterate through it, looking for unique actor names.

    var movieList = xfa.datasets.data.resolveNodes("data.movie[*]"); ...

    As for ensuring that the NewActorSF subform never ends-up alone at the bottom of a content area, that’s more challenging. The simplest, though not the most scientific, would be to reduce the height of the content areas (the columns) just slightly so that there is just not quite enough room for that one NewActorSF instance to fit in the first column and it’ll end-up in the second.

    If you want something more precise, then I don’t think you would be able to use the condition break that sets this subform when the actor changes. Instead, you would have to move it into the movie subform, hide it and have Initialization script in the movie subform that keeps track of the actor name and shows the NewActorSF subform within that particular movie subform instance only when the actor name changes. You can use a script object variable to keep track of the actor names — and this would be a way for you to count the actor names as well, at the same time. This way, you would be guaranteed that the NewActorSF would never be alone at the bottom of a column.

  28. Neha on September 3rd, 2010

    Hi Stefan,

    I have a form which needs to have duplex printing.
    the form starts on the first page and has a flowed content. this data should be printed on the front pages only and break to next front page if the page size is reached.
    On the back side of the first page a text will be printed and the back side of rest of the pages needs to be blank.

    Could you help me with achieving it.

    Thanks.

  29. Stefan Cameron on September 28th, 2010

    Neha,

    I had to consult a colleague about your question. Yes, you can achieve that. You will need to set your form to use simplex/duplex printing and then define a master page that has a placement of “first/odd”, another that has a placement of “first/even”, a third with placement “even” and a fourth with placement “odd”.

    You would then place your text on the “first/even” page and your table on the “first/odd” page, configuring it to flow onto the “odd” page.

    That should give you a form with a table flowing from page 1 to 3 to 5, etc., and some text on page 2 only.

  30. Jesus on September 29th, 2010

    What can I do if I can’t get the text field to expand down when I add a lot of text on the sunken boxs in preview PDF, even right after I check the expand to fit box, check the allow page breaks within content box and auto fit box?

  31. Stefan Cameron on October 1st, 2010

    @Jesus,

    Could it be that you aren’t previewing your form as a dynamic PDF? If you aren’t, there’s no way that text field will grow no matter what you do…