Whats the Problem?
In modern web applications, dynamic user interactions are crucial for providing a seamless experience. Specifically, we needed to implement a calculator that processes user inputs and displays results in real-time, while also integrating a modal popup to present supplementary details. The challenges included ensuring accurate data validation, calculating values based on user input, and managing the modal’s visibility. Proper handling of these aspects is essential to enhance user experience and ensure data integrity.
The Solution
The solution involves a combination of JavaScript and jQuery to create a functional calculator with real-time validation and updates, alongside a modal popup for additional information. Here’s how the solution is structured:
Input Validation
- Functionality: Validates user inputs to ensure they are numeric and handle comma-separated values.
- Implementation: Utilizes a debounce function to limit the frequency of validation checks, improving performance and responsiveness. Inputs are validated on
keyup
andblur
events.
Data Calculation
- Functionality: Calculates various metrics based on user input, including manual hours, automated hours, and associated costs.
- Implementation: Processes the user inputs to compute values and dynamically updates the display elements with formatted results.
Modal Popup
- Functionality: Toggles the visibility of a modal popup for displaying additional content.
- Implementation: Uses jQuery to handle click events for opening and closing the modal. Ensures smooth user interaction by applying and removing the `modal-active` class.
Handling Hidden Fields
- Functionality: Updates hidden form fields with processed values for further use.
- Implementation: Dynamically retrieves the form’s ID to select and update hidden fields based on user input.
Here is the JavaScript code that achieves these functionalities:
<script>
( function( $ ) {
var inputs = $( '.nh-calculator__input' );
var manualHoursTarget = $( '#manual-hours' );
var manualCostTarget = $( '#manual-cost' );
var automatedHoursTarget = $( '#automated-hours' );
var automatedCostTarget = $( '#automated-cost' );
var savingsHoursTarget = $( '#savings-hours' );
var savingsCostTarget = $( '#savings-cost' );
var button = $( '.nh-calculator__button' );
var close = $( '.nh-calculator__modal-close' );
var modal = $( '.nh-calculator__modal-wrapper' );
var form = $( '.gform_wrapper' );
var id = form.attr( 'id' ) ? form.attr( 'id' ).toString().split( '' ).pop() : '';
var hiddenPhysicals = $( '#input_' + id + '_6' );
var hiddenRate = $( '#input_' + id + '_7' );
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var validate = debounce( function( e ) {
var physicals = stripComma( $( '#nh-calculator__physicals' ).val() );
var rate = $( '#nh-calculator__hourly' ).val() === "" ? '118' : stripComma( $( '#nh-calculator__hourly' ).val() );
var element = $( e.target );
var error = $( '<span />', {
class: 'nh-calculator__error',
html: 'Please enter a number'
});
if ( ! e.target.validity.valid ) {
element.addClass( 'nhc-border-red' );
if ( ! element.next( '.nh-calculator__error' ).length ) {
error.appendTo( element.parent() );
}
hiddenPhysicals.val( '' );
hiddenRate.val( '' );
} else {
element.removeClass( 'nhc-border-red' );
$( '.nh-calculator' ).find( '.nh-calculator__error' ).remove();
hiddenPhysicals.val( physicals );
hiddenRate.val( rate );
agilityCalculate();
}
}, 250 );
function stripComma( value ) {
return value.replace( /,/g, '' );
}
function agilityCalculate() {
var physicals = stripComma( $( '#nh-calculator__physicals' ).val() );
var rate = $( '#nh-calculator__hourly' ).val() === "" ? '118' : stripComma( $( '#nh-calculator__hourly' ).val() );
var manualHours = Math.floor( physicals * 7 / 60 );
var manualCost = manualHours * rate;
var automatedHours = Math.floor( physicals * 4 / 60 );
var automatedCost = automatedHours * rate;
var savingsHours = manualHours - automatedHours;
var savingsCost = savingsHours * rate;
manualHoursTarget.html( manualHours.toLocaleString( 'en-US' ) );
manualCostTarget.html( '$' + manualCost.toLocaleString( 'en-US' ) );
automatedHoursTarget.html( automatedHours.toLocaleString( 'en-US' ) );
automatedCostTarget.html( '$' + automatedCost.toLocaleString( 'en-US' ) );
savingsHoursTarget.html( savingsHours.toLocaleString( 'en-US' ) );
savingsCostTarget.html( '$' + savingsCost.toLocaleString( 'en-US' ) );
}
inputs.on( 'keyup', validate );
inputs.on( 'blur', validate );
button.on( 'click', function( e ) {
e.preventDefault();
modal.toggleClass( 'modal-active' );
});
close.on( 'click', function( e ) {
e.preventDefault();
modal.removeClass( 'modal-active' );
});
} )( jQuery );
<script>