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

Question

Question

JavaScript help: Pass different fields as variables to the same 'function'

asked on July 6, 2018

I am hoping someone can help with the correct syntax to make my code a littler cleaner.  I have code that takes a voltage rating input field and compares it to some ranges in combination with the value from another field, then fills the background color and sets a 3rd field to PASS or F.  The section of code doing that comparison stays the same and could be reused many time in my form, but I don't know the correct syntax to call that code and pass the variables that would be different to it.  It's something like this...

$(document).ready(function(){
  $(document).on('change', '.InsResistTest3 input', function(){
	  
	  //VRating needs to reference the q# for Voltage Rating from the Nameplate Section
	  var VRating = parseFloat($('#q309 input').val().replace(/,/g,''));
	  //PFField references the field that is set to either F or PASS and is checked by the overall pass fail field formula
	  var PFField = $('#q345 input');
	
//The variables above would be different based on which VRating and PFField were being referenced.
//The code below could be called mutiple times, with different VRating and PFField variables passed to it.
  
   if ((VRating <= 250) && ($(this).val() < 0.025)){
		this.setAttribute('style', 'background-color: tomato !important')
        PFField.val('F').change();
		}
	else if ((VRating > 250) && (VRating <= 1000) && ($(this).val() < 0.100)){
		this.setAttribute('style', 'background-color: tomato !important')
        PFField.val('F').change();
		}
	else if ((VRating > 1000) && (VRating <= 2500) && ($(this).val() < 0.500)){
		this.setAttribute('style', 'background-color: tomato !important')
        PFField.val('F').change();
		}
	else if ((VRating > 2500) && (VRating <= 5000) && ($(this).val() < 1.000)){
		this.setAttribute('style', 'background-color: tomato !important')
        PFField.val('F').change();
		}
	else if ((VRating > 5000) && (VRating <= 8000) && ($(this).val() < 2.000)){
		this.setAttribute('style', 'background-color: tomato !important')
        PFField.val('F').change();
    	}
	else if ((VRating > 8000) && (VRating <= 15000) && ($(this).val() < 5.000)){
		this.setAttribute('style', 'background-color: tomato !important')
        PFField.val('F').change();
		}
	else if ((VRating > 15000) && (VRating <= 25000) && ($(this).val() < 20.000)){
		this.setAttribute('style', 'background-color: tomato !important')
        PFField.val('F').change();
		}
    else {
      $(this).css('background-color', 'white')
      PFField.val('PASS').change();
    }
  });
});

Thanks in advance for any help!

0 0

Answer

SELECTED ANSWER
replied on July 9, 2018 Show version history

I'm not 100% clear on what you're trying to accomplish, but it sounds like you just want a reusable function. If that is the case, then you just need to define the reusable function outside of $(document).ready() and call that function inside your event handlers.

First, instead of changing the style directly like that, just add a CSS class to the form; this makes it a lot easier to manage the styling as you can update the CSS without digging through the JavaScript and you can simply add/remove the class as needed.

In the CSS section add the following (or whatever you want to name it)

.ratingError,
input[backend-readonly].ratingError {
  background-color:tomato !important;
}

Then, try the following code in your JavaScript

$(document).ready(function(){
    // You can assign the change handler directly to the element
    // This is much easier to read/manage than using $(document).on('change') and specifying a target
    $('.InsResistTest3 input').change(function(){
      // Call the generic function and pass in the objects that will be compared/updated
      // Passing in your PFField, VField, and object that triggered the event
      rateComparison($('#q345 input'),$('#q309 input'),$(this));
    });
});

function rateComparison(PFField, VField, Target){
    // Get your rating and values from the inputs
    var VRating = parseFloat(VField.val().replace(/,/g,''));
    // Target is your $(this) object passed in from the calling event handler
    // Getting the value and storing it to a variable is more efficient than calling $(this).val() over and over
    var TValue = Target.val();

    // Use the OR || operator so any of the conditions will trigger the associated changes
    // All of your IFs have the same result so there's no real reason to split them up
    if ((VRating <= 250 && TValue < 0.025) || 
        (VRating > 250 && VRating <= 1000 && TValue < 0.100) ||
        (VRating > 1000 && VRating <= 2500 && TValue < 0.500) ||
        (VRating > 2500 && VRating <= 5000 && TValue < 1.000) ||
        (VRating > 5000 && VRating <= 8000 && TValue < 2.000) ||
        (VRating > 8000 && VRating <= 15000 && TValue < 5.000) ||
        (VRating > 15000 && VRating <= 25000 && TValue < 20.000)){
            // Instead of changing the style just add class reference
            // This will give you more control and make maintenance easier
            // because you can edit the CSS instead of the JavaScript
            Target.addClass('ratingError');
            PFField.val('F').change();
    }
    else {
      // Remove the custom class so the default color will show and it will
      // match the other fields even if you make any adjustments to the themes
      Target.removeClass('ratingError');
      PFField.val('PASS').change();
    }
}

Now, if you want to reuse this function, you just assign another event handler to the other field, reference the same function, and pass in the new elements to be compared/updated. However, one thing I would suggest is to also add custom classes to your other fields so you don't have to reference them by the q# and you can make them match up easier.

For example,

    $('.InsResist4 input').change(function(){
      // Call the generic function and pass in the objects that will be compared/updated
      // Passing in your PFField, VField, and object that triggered the event
      rateComparison($('.PFField4 input'),$('.VField4 input'),$(this));
    });

If you do that, you can even get fancy and reference the other fields dynamically by pulling a number value from the class of the element calling the function.

EDIT: Increased the specificity of CSS class to override default styling of read-only elements.

1 0
replied on July 9, 2018

Jason,

This is exactly what I was look for.  Thanks for the thorough explanation and advice on more elegant code!  I do have a couple of problems though:

1.  Target.addClass('ratingError'); isn't doing anything.  I added that to the CSS section and looked for typos, but can't figure it out.

2.  If I manually add that class to a field it makes the background of the label red, instead of just the background of the input field.

0 0
replied on July 9, 2018

If you're getting the label as red, then you actually added the class to the wrapper around the field rather than the input element.

Each item on a Laserfiche form is encased in a div element that holds the label and input; this div element is the one that actually gets the class assigned in the advanced tab.

However, the method I provided should be assigning the "ratingError" class directly to the input element.

Can you repost with your updated code so I can take a look? Also, inspect the page to look for JavaScript errors, and to determine whether the class is not getting added at all or if it just isn't affecting the style.

0 0
replied on July 9, 2018

Here is the code I added

$(document).ready(function(){
    // You can assign the change handler directly to the element
    // This is much easier to read/manage than using $(document).on('change') and specifying a target
    $('.InsResistTest3 input').change(function(){
      // Call the generic function and pass in the objects that will be compared/updated
      // Passing in your PFField, VField, and object that triggered the event
      rateComparison($('#q345 input'),$('#q309 input'),$(this));
    });
});

function rateComparison(PFField, VField, Target){
    // Get your rating and values from the inputs
    var VRating = parseFloat(VField.val().replace(/,/g,''));
    // Target is your $(this) object passed in from the calling event handler
    // Getting the value and storing it to a variable is more efficient than calling $(this).val() over and over
    var TValue = Target.val();
  alert(Target);
  alert('before if'); 
  
    // Use the OR || operator so any of the conditions will trigger the associated changes
    // All of your IFs have the same result so there's no real reason to split them up
    if ((VRating <= 250 && TValue < 0.025) || 
        (VRating > 250 && VRating <= 1000 && TValue < 0.100) ||
        (VRating > 1000 && VRating <= 2500 && TValue < 0.500) ||
        (VRating > 2500 && VRating <= 5000 && TValue < 1.000) ||
        (VRating > 5000 && VRating <= 8000 && TValue < 2.000) ||
        (VRating > 8000 && VRating <= 15000 && TValue < 5.000) ||
        (VRating > 15000 && VRating <= 25000 && TValue < 20.000)){
            // Instead of changing the style just add class reference
            // This will give you more control and make maintenance easier
            // because you can edit the CSS instead of the JavaScript
            
      		Target.addClass('red');
      		//this.setAttribute('style', 'background-color: tomato !important');
            PFField.val('F').change();
    }
    else {
      // Remove the custom class so the default color will show and it will
      // match the other fields even if you make any adjustments to the themes
      alert('else');
      Target.removeClass('red');
      PFField.val('PASS').change();
    }
}

and my css

/*Makes background red to indicate a failed test result, called by javascript */
.red {
  background-color:tomato !important;
}

 

0 0
replied on July 9, 2018

It isn't working because the field I am trying to 'highlight' tomato is read-only.  Do you know how to work around that?

0 0
replied on July 9, 2018 Show version history

Sorry, I'm a bit confused. The way the code is written the field it is trying to highlight is the field with the event handler.

If the field is read-only, what is triggering the change event?

In either case, if it is read-only you'll have to increase the specificity of the CSS selector to make sure it overrides the default styling.

Try this

.red,
input[backend-readonly].red {
  background-color:tomato !important;
}

If the field is read-only you don't technically need the ".red," portion, but I left it in for comparison.

1 0
replied on July 9, 2018

The field has a formula applied to it.  The formula takes the value from the field above it and runs a calculation to temperature adjust it.  I think that answers your question?  I am learning as I go here.

0 0
replied on July 9, 2018

If I try to use 

Target.setAttribute('style', 'background-color: tomato !important');

in place of 

Target.addClass('failedTest');

The console (in Chrome) shows Target.setAttribute is not a function

0 0
replied on July 9, 2018

Jason,

The CSS to increase the specificity did the trick!  Thanks so much for all of your help!  If you can edit your original response to include that tidbit for working with read only fields I will mark it as the answer!

0 0
replied on July 9, 2018

Glad it worked!

Just to provide some additional information for you, the reason setAttribute() did not work is because this is using JQuery objects and the setAttribute() method only works when referencing objects with vanilla JavaScript.

JQuery does have .attr() and .removeAttr(), but for something like this CSS would be preferable.

0 0
replied on July 9, 2018

I updated the original post to include the CSS required to override read-only styling.

0 0

Replies

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

Sign in to reply to this post.