You are viewing limited content. For full access, please sign in.

Question

Question

Altering graphs in a Laserfiche Form

asked on April 1, 2019 Show version history

I'm wondering if you can tell me if this is possible in a Laserfiche Form:

In our County, the rural roads are sprayed each year to kill off noxious weeds and landowners need to apply for a No-Spray agreement to request NO SPRAYING in some areas, maybe due to a pond that has fish that they don't want killed off by the poisons.

I am trying to turn the old paper application into a Laserfiche Form, however, landowners used to indicate the areas they did not want sprayed on this graphic, which was part of the old paper form:

 

In the above graphic, the yellow highlight shows where an applicant drew a line on two sides of the box representing the location he wants no spraying to happen.

How can we accomplish this in a LF Form?  In discussing this with our staff, they asked if the form could be built in a way that the applicant could click on the lines bordering each square and each click would highlight the section of line clicked on.  Is this possible?  Or is there an alternative way of achieving something similar?

0 0

Answer

SELECTED ANSWER
replied on April 4, 2019 Show version history

Lines 5 to 47 of the Javascript create the 36 sections of NW/NE/SW/SE buttons.  This is all done without needing to access input values, so it should work fine in the archival version.

Lines 112 to 212 of the Javascript create the highlighting when the user clicks the buttons.  This is dependent upon the input values, but only matters when the user is clicking the buttons, so it's not needed for the archive vesion of the form to work properly.  By the way, if you wanted a "Review" version of the form, that your team can see what the submitter selected, but not actually make changes, then this is the section that would need to be removed on that copy of the form - the buttons would still exist, but there wouldn't be any code to tell it what to do when they are clicked.

Lines 49 to 110 of the Javascript are what creates the highlighting based on existing values on the form (from prior submissions of the form).  This is what we need to edit to make it work for the archival version.  And really, all we need to edit is lines 53-56, where it is pulling in the values and storing them in variables.  We need to be able to pull in those values whether they are stored in input values or stored as text.

On my examination, I see that the IDs: Field1(1), Field(2), Field1(3), etc. are retained on the archival of the form - what's missing is the input elements (they have been converted to text elements).  So we should be able to make this work by checking for the value on the active form and the text on the archive form.

Replace lines 53-56 of the original Javascript, with these lines, and I think it will archive correctly for you.  So you know, I did not test this all the way through archiving to the repository, there is a way to see the archived form in LFForms, and I tested that it worked there once I made this change - it should work the same on the archival to the repository: 

    if ($('#Field1\\(1\\)').text() == '') {  //Be sure to set the correct Field # (the Q # for the NW field in the table
      //Processing the live version of the form.  
      var nwVal = parseInt($('#Field1\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NW field in the table
      var neVal = parseInt($('#Field2\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NE field in the table
      var swVal = parseInt($('#Field5\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SW field in the table
      var seVal = parseInt($('#Field6\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SE field in the table
    } 
    else {   
      //Processing the archived version of the form.
      var nwVal = parseInt($('#Field1\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the NW field in the table
      var neVal = parseInt($('#Field2\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the NE field in the table
      var swVal = parseInt($('#Field5\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the SW field in the table
      var seVal = parseInt($('#Field6\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the SE field in the table
    } 

 

0 0

Replies

replied on April 2, 2019 Show version history

You definitely have to get creative to make this work.

You can do a lot of custom stuff with HTML, Javascript, and CSS - but in order to get Forms to retain what you've done, it needs to end up in form fields somehow.

Here's one way to do it, trying to mimic the graphic you posted.

1. Add a table to your form.  Give it a CSS Class name of: sectionsTable.  Set it to a fixed amount of 36 rows.  Add 4 fields (number fields) named NW, NE, SW, and SE.  Set the default value of all of those fields to zero.  This table will actually be hidden, but this is where the actual values will be stored (stored as numbers 0, 1, 2, or 3).

2. Add a custom HTML element to your form, with text (centered) that says "North".  Give it CSS Class name of: northLabel.

3. Add a custom HTML element to your form, with text (centered) that says "South".  Give it CSS Class name of: southLabel.

4. Add this CSS to your form: 

.nw {width: 40px; height: 40px; margin-top: 0px; margin-left: 5px; margin-right: 0px; margin-bottom: 0px; display : inline-block; border: 1px solid black; background: none; -webkit-appearance: none;}
.ne {width: 40px; height: 40px; margin-top: 0px; margin-left: 0px; margin-right: 0px; margin-bottom: 0px; display : inline-block; border: 1px solid black; background: none; -webkit-appearance: none;}
.sw {width: 40px; height: 40px; margin-top: 0px; margin-left: 5px; margin-right: 0px; margin-bottom: 0px; display : inline-block; border: 1px solid black; background: none; -webkit-appearance: none;}
.se {width: 40px; height: 40px; margin-top: 0px; margin-left: 0px; margin-right: 0px; margin-bottom: 0px; display : inline-block; border: 1px solid black; background: none; -webkit-appearance: none;}
.spacing {width: 30px; text-align: right; display : inline-block;}
.holder {width: 100%; text-align: center;}
.north {border-top: 5px solid yellow!important;}
.east {border-right: 5px solid yellow!important;}
.south {border-bottom: 5px solid yellow!important;}
.west {border-left: 5px solid yellow!important;}
.sectionsTable {display : none;}

5. Add this Javascript to your form: 

$(document).ready(function () {
  
  var newHTML = '';
  
  //Create all the buttons 
  for (i2 = 3; i2 >= 1; i2--) {
    
    newHTML = '<div class="holder">';
    for (i = i2*12-5; i <= i2*12; i++) {
      newHTML = newHTML + '<div class="placeholder spacing">' + i + ':</div>'
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder nw" value="NW"></input>';
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder ne" value="NE"></input>';
    } 
    newHTML = newHTML + '<div class="placeholder spacing"></div></div>'
    $('.southLabel').before(newHTML);
    
    newHTML = '<div class="holder">';
    for (i = i2*12-5; i <= i2*12; i++) {
      newHTML = newHTML + '<div class="placeholder spacing"></div>'
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder sw" value="SW"></input>';
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder se" value="SE"></input>';
    } 
    newHTML = newHTML + '<div class="placeholder spacing"></div></div>'
    $('.southLabel').before(newHTML);
    
    newHTML = '<div class="holder">';
    for (i = i2*12-6; i >= i2*12-11; i--) {
      newHTML = newHTML + '<div class="placeholder spacing">' + i + ':</div>'
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder nw" value="NW"></input>';
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder ne" value="NE"></input>';
    } 
    newHTML = newHTML + '<div class="placeholder spacing"></div></div>'
    $('.southLabel').before(newHTML);
    
    newHTML = '<div class="holder">';
    for (i = i2*12-6; i >= i2*12-11; i--) {
      newHTML = newHTML + '<div class="placeholder spacing"></div>'
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder sw" value="SW"></input>';
      newHTML = newHTML + '<input type="button" data-section=' + i + ' class="location placeholder se" value="SE"></input>';
    } 
    newHTML = newHTML + '<div class="placeholder spacing"></div></div>'
    $('.southLabel').before(newHTML);
    
    newHTML = '<div class="holder"><div class="placeholder spacing"></div></div>';
    $('.southLabel').before(newHTML);
    
  } 
  
  //When the form is loaded, cycle through all properties and populate
  //the highlighting for the different sections
  $('.location').each(function() { 
    
    var nwVal = parseInt($('#Field1\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NW field in the table
    var neVal = parseInt($('#Field2\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NE field in the table
    var swVal = parseInt($('#Field5\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SW field in the table
    var seVal = parseInt($('#Field6\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SE field in the table
    if ($(this).val() == 'NW') { 
      if (nwVal == 1) { 
        $(this).addClass('north');
      }
      else if (nwVal == 2) { 
        $(this).addClass('west');
      }
      else if (nwVal == 3) { 
        $(this).addClass('north');
        $(this).addClass('west');
      }
      $('#Field1\\(' + $(this).data('section') + '\\)').val(nwVal);  //Be sure to set the correct Field # (the Q # for the NW field in the table
    }
    else if ($(this).val() == 'NE') { 
      if (neVal == 1) { 
        $(this).addClass('north');
      }
      else if (neVal == 2) { 
        $(this).addClass('east');
      }
      else if (neVal == 3) { 
        $(this).addClass('north');
        $(this).addClass('east');
      }
      $('#Field2\\(' + $(this).data('section') + '\\)').val(neVal);  //Be sure to set the correct Field # (the Q # for the NE field in the table
    }
    else if ($(this).val() == 'SW') { 
      if (swVal == 1) { 
        $(this).addClass('south');
      }
      else if (swVal == 2) { 
        $(this).addClass('west');
      }
      else if (swVal == 3) { 
        $(this).addClass('south');
        $(this).addClass('west');
      }
      $('#Field5\\(' + $(this).data('section') + '\\)').val(swVal);  //Be sure to set the correct Field # (the Q # for the SW field in the table
    }
    else if ($(this).val() == 'SE') { 
      if (seVal == 1) { 
        $(this).addClass('south');
      }
      else if (seVal == 2) { 
        $(this).addClass('east');
      }
      else if (seVal == 3) { 
        $(this).addClass('south');
        $(this).addClass('east');
      }
      $('#Field6\\(' + $(this).data('section') + '\\)').val(seVal);  //Be sure to set the correct Field # (the Q # for the SE field in the table
    }
    
  }); 
  
  //When a button is clicked, update the stored value for it (0, 1, 2, or 3)
  //And populate the highlighting for the button.  
  $('.location').click(function(){
    var nwVal = parseInt($('#Field1\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NW field in the table
    var neVal = parseInt($('#Field2\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NE field in the table
    var swVal = parseInt($('#Field5\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SW field in the table
    var seVal = parseInt($('#Field6\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SE field in the table
    if ($(this).val() == 'NW') { 
      if (nwVal == 0) { 
        nwVal = 1;
        $(this).addClass('north');
        $(this).removeClass('west');
      }
      else if (nwVal == 1) { 
        nwVal = 2;
        $(this).removeClass('north');
        $(this).addClass('west');
      }
      else if (nwVal == 2) { 
        nwVal = 3;
        $(this).addClass('north');
        $(this).addClass('west');
      }
      else if (nwVal == 3) { 
        nwVal = 0;
        $(this).removeClass('north');
        $(this).removeClass('west');
      }
      $('#Field1\\(' + $(this).data('section') + '\\)').val(nwVal);  //Be sure to set the correct Field # (the Q # for the NW field in the table
    }
    else if ($(this).val() == 'NE') { 
      if (neVal == 0) { 
        neVal = 1;
        $(this).addClass('north');
        $(this).removeClass('east');
      }
      else if (neVal == 1) { 
        neVal = 2;
        $(this).removeClass('north');
        $(this).addClass('east');
      }
      else if (neVal == 2) { 
        neVal = 3;
        $(this).addClass('north');
        $(this).addClass('east');
      }
      else if (neVal == 3) { 
        neVal = 0;
        $(this).removeClass('north');
        $(this).removeClass('east');
      }
      $('#Field2\\(' + $(this).data('section') + '\\)').val(neVal);  //Be sure to set the correct Field # (the Q # for the NE field in the table
    }
    else if ($(this).val() == 'SW') { 
      if (swVal == 0) { 
        swVal = 1;
        $(this).addClass('south');
        $(this).removeClass('west');
      }
      else if (swVal == 1) { 
        swVal = 2;
        $(this).removeClass('south');
        $(this).addClass('west');
      }
      else if (swVal == 2) { 
        swVal = 3;
        $(this).addClass('south');
        $(this).addClass('west');
      }
      else if (swVal == 3) { 
        swVal = 0;
        $(this).removeClass('south');
        $(this).removeClass('west');
      }
      $('#Field5\\(' + $(this).data('section') + '\\)').val(swVal);  //Be sure to set the correct Field # (the Q # for the SW field in the table
    }
    else if ($(this).val() == 'SE') { 
      if (seVal == 0) { 
        seVal = 1;
        $(this).addClass('south');
        $(this).removeClass('east');
      }
      else if (seVal == 1) { 
        seVal = 2;
        $(this).removeClass('south');
        $(this).addClass('east');
      }
      else if (seVal == 2) { 
        seVal = 3;
        $(this).addClass('south');
        $(this).addClass('east');
      }
      else if (seVal == 3) { 
        seVal = 0;
        $(this).removeClass('south');
        $(this).removeClass('east');
      }
      $('#Field6\\(' + $(this).data('section') + '\\)').val(seVal);  //Be sure to set the correct Field # (the Q # for the SE field in the table
    }
    
  }); 

}); 

6. Update the Javascript to reference the table fields.  In my case, the NW field was q1 (so there are 4 locations that refer to Field1), the NE field was q2 (so there are 4 locations that refer to Field2), the SW field was q5 (so there are 4 locations that refer to Field5), the SE field was q6 (so there are 4 locations that refer to Field6).  You will need to update the 16 field numbers in the Javscript.

Each time you click on one of the buttons, the stored value alternates between 0 (shows no highlights), 1 (shows the top or bottom highlighted), 2 (shows the left or right highlighted), and 3 (shows both the top/bottom and left/right highlighted).  So the user just clicks on the button and the highlighting cycles through.  Because the number value is stored in the table, the selection carries over across the submitted form.

I have tested this going from a submitted form to a user task and the values carried over.

I have not tested this with the form archived to the repository - and I suspect that it will not complete the highlighting there.  It will probably still generate the buttons, etc. - but the highlighting is dependent upon the val() of the fields in the table (to get the 0, 1, 2, or 3), and val() is not used in the archived version of the form.  If you need it to work on the archive version too, then you would need to tweak it to also check the text() item in addition to the val() item.

Here's a screenshot of my completed form:

I hope this is of some help to you!

1 0
replied on April 3, 2019

Wow, Matthew!  Thank you so much for your time on this.  Sorry, I was away yesterday so could not work on this right after you posted.

I have duplicated what you have here and changed the field references to match mine.  Beautiful results!  However, as you mention, it does not save the highlighted sections when Submit is pressed.

So, I'm trying to see what you're suggesting to change to make it save on the archived version of the form.  I'm sorry, I have little experience with JavaScript.  I have your code pasted into a Word document and used that to find all the Fields to change.  I'm thinking for this val() vs. text() you're not suggesting I just change out every val() with text().  Is that correct?

1 0
replied on April 4, 2019

So, crash course on selecting items in Javascript, particularly in LFForms.

The HTML items in your form have different ways you can select them.  They have the type of field, ID names, class names, etc.

Every field that you add to your form in LFForms has multiple components, it's not just an input field.  It has a label, help text above and below the field, pop-up help tips, the actual input field, etc., etc.

Each field has a "q" ID.  The q designation is something that LFForms does, if you are doing your own HTML, you can do whatever you want for the ID, but Forms uses this q structure.

When we say q1, we're referring to the entire field (labels, input, etc.) that Forms identifies as the 1st field.

Javascript requires us to use the # prefix when referring to an item by its ID number.

Like this:   $('#q1')

But that refers to the entire field, not just the input box.  So we can't grab the value from the field, like this: $('#q1').val();   because that's saying to grab the value from the entire field, and it doesn't have a value at that level.  So we need to get into the input element of the field.

Like this:   $('#q1 input').val();     This says "find the input element, within the group of elements, that have ID q1, and then return its value."

Another way we can do it is by the Field ID.  LFForms gives a field ID to the input element within the field that matches the q ID number.  Therefore, these two items are basically interchangeable:   $('#q1 input').val();   and   $('#Field1').val();

In the case of the code that I gave you, it's actually referencing the fields within table, so Field1(1), Field1(2), Field1(3), etc.  We have to use \\( and \\) instead of just ( and ) because those are special characters in Javascript and we have to "Escape" them to show right.  So this:   $('#Field1\\(3\\)').val();   basically says "find the third instance of the input elements that has ID if Field1, and then return its value."

Another way (often preferable way) to refer to fields is by their CSS Class name.  ID is going to refer to a very specific item which is uniquely set by Forms when the fields are created.  Class name can be set to you, can be a descriptive name, and isn't dependent upon the structure of how the form was built.  So using class names instead of ID is really good for code you want to reuse across multiple forms.

Javascript uses the . character to prefix a class name.  So if a field has a class name of myFieldName, you can refer to it like this:  $('.myFieldName')     Once again, we're referring to the entire field, not just the input element, so to get to the value of the input field, we have to include the element type;     $('.myFieldName input').val();

Side note - not all fields in LFForms use the input element, multi-line fields use the textarea element, and drop-down fields use the select element.  And although things like checkboxes and radio buttons use the input element, saying   $('.myCheckbox input').val();   isn't usually as helpful as something like this:   $('.myFieldName input:checked').val();   The first one gives you the value of any of the checkboxes, whereas the second one is the value of checked checkboxes.

TL;DR - I explained all that to explain this.  The archived version of the forms do not have the input elements, so we can't get the value of an element:   $('Field1').val()   because it doesn't exist.  So we have to get creative and refer to the input value on the active form, but refer to the field text on the archived form.  Give me a little bit and I'll see if I can get something posted for you.

1 0
SELECTED ANSWER
replied on April 4, 2019 Show version history

Lines 5 to 47 of the Javascript create the 36 sections of NW/NE/SW/SE buttons.  This is all done without needing to access input values, so it should work fine in the archival version.

Lines 112 to 212 of the Javascript create the highlighting when the user clicks the buttons.  This is dependent upon the input values, but only matters when the user is clicking the buttons, so it's not needed for the archive vesion of the form to work properly.  By the way, if you wanted a "Review" version of the form, that your team can see what the submitter selected, but not actually make changes, then this is the section that would need to be removed on that copy of the form - the buttons would still exist, but there wouldn't be any code to tell it what to do when they are clicked.

Lines 49 to 110 of the Javascript are what creates the highlighting based on existing values on the form (from prior submissions of the form).  This is what we need to edit to make it work for the archival version.  And really, all we need to edit is lines 53-56, where it is pulling in the values and storing them in variables.  We need to be able to pull in those values whether they are stored in input values or stored as text.

On my examination, I see that the IDs: Field1(1), Field(2), Field1(3), etc. are retained on the archival of the form - what's missing is the input elements (they have been converted to text elements).  So we should be able to make this work by checking for the value on the active form and the text on the archive form.

Replace lines 53-56 of the original Javascript, with these lines, and I think it will archive correctly for you.  So you know, I did not test this all the way through archiving to the repository, there is a way to see the archived form in LFForms, and I tested that it worked there once I made this change - it should work the same on the archival to the repository: 

    if ($('#Field1\\(1\\)').text() == '') {  //Be sure to set the correct Field # (the Q # for the NW field in the table
      //Processing the live version of the form.  
      var nwVal = parseInt($('#Field1\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NW field in the table
      var neVal = parseInt($('#Field2\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the NE field in the table
      var swVal = parseInt($('#Field5\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SW field in the table
      var seVal = parseInt($('#Field6\\(' + $(this).data('section') + '\\)').val());  //Be sure to set the correct Field # (the Q # for the SE field in the table
    } 
    else {   
      //Processing the archived version of the form.
      var nwVal = parseInt($('#Field1\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the NW field in the table
      var neVal = parseInt($('#Field2\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the NE field in the table
      var swVal = parseInt($('#Field5\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the SW field in the table
      var seVal = parseInt($('#Field6\\(' + $(this).data('section') + '\\)').text());  //Be sure to set the correct Field # (the Q # for the SE field in the table
    } 

 

0 0
replied on April 4, 2019

@████████ - please consider editing your original question and changing the type from "Discussion" to "Question" - and then if you like my post, marking that as the "Answer" to the question.  Thank you!

 

1 0
replied on April 8, 2019

Thanks, Matthew.  I just got back in the office this afternoon and will definitely check this out!  Will report in after I've had a chance to play with your suggestions.

0 0
replied on April 8, 2019

Hey, the changes worked!  The form saved the highlighted sections when it "Saved to Laserfiche".

Thanks for all your help, Matthew, and for the notes regarding the "crash course"!  I have set aside that information into my Forms Styling notes folder for future use!

1 0
replied on April 8, 2019

Hurray!  I'm glad this worked for you.

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.