Whats the Problem?
In web development, enhancing user interaction and ensuring data validation are crucial for providing a seamless experience. Our goal was to create an interactive calculator that dynamically updates results based on user input while providing immediate feedback for invalid entries. However, during implementation, we faced issues such as:
- Validating numeric input in real-time.
- Dynamically updating multiple fields based on calculations.
- Handling invalid form submissions gracefully.
- Ensuring compatibility with a Gravity Forms hidden field to store data.
The Solution
We developed a jQuery-based solution to address these challenges effectively.
<script>
var input = $('#nh-calculator__visits');
var gross = $('#gross');
var referrals = $('#referrals');
var hoursSaved = $('#hours-saved');
var yearOne = $('#year-one');
var yearTwo = $('#year-two');
var yearThree = $('#year-three');
var button = $('.nh-calculator__button');
var close = $('.nh-calculator__modal-close');
var modal = $('.nh-calculator__modal-wrapper');
```
**2. Linking with Gravity Forms:**
We ensured our script works seamlessly with Gravity Forms:
```javascript
var form = $('.gform_wrapper');
var id = form.length > 0 ? form.attr('id') : null;
var hidden = id ? $('#input_' + id.split('').pop() + '_6') : null;
```
**3. Input Validation with Debounce:**
To prevent performance issues, we used a debounce function to validate input in real-time:
```javascript
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);
};
}
```
**4. Validating Input:**
We ensured only numeric values are accepted and provided instant feedback for invalid entries:
```javascript
var validate = debounce(function (e) {
var element = $(e.target);
var text = element.val();
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());
}
if (hidden) hidden.val('');
} else {
element.removeClass('nhc-border-red');
$('.nh-calculator').find('.nh-calculator__error').remove();
if (hidden) hidden.val(text);
woundCalculate();
}
}, 250);
```
**5. Calculation Function:**
We performed calculations based on user input and updated the results dynamically:
```javascript
function stripComma(value) {
return value.replace(/,/g, '');
}
function woundCalculate() {
var visits = stripComma(input.val());
if (isNaN(visits) || visits === "") {
visits = 0;
}
var grossTotal = Math.floor((visits * 165 * 0.1) - (visits * 165 * 0.07));
var referralsTotal = Math.floor(visits / 3 * 0.01 * 165 * 16);
var hoursTotal = Math.floor(visits * 5 / 60 * 0.75 * 165);
var yearOneTotal = grossTotal * 12;
var yearTwoTotal = grossTotal * 24;
var yearThreeTotal = grossTotal * 36;
gross.html('+ $' + grossTotal.toLocaleString('en-US'));
referrals.html('+ $' + referralsTotal.toLocaleString('en-US'));
hoursSaved.html('+ $' + hoursTotal.toLocaleString('en-US'));
yearOne.html('+ $' + yearOneTotal.toLocaleString('en-US'));
yearTwo.html('+ $' + yearTwoTotal.toLocaleString('en-US'));
yearThree.html('+ $' + yearThreeTotal.toLocaleString('en-US'));
console.log(visits);
}
```
**6. Event Handlers:**
We set up event handlers for user interactions:
```javascript
input.on('keyup', validate);
input.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');
});
</script>