BMI Conversion Precision Fix

User
jQuery(function($){
function kgToStLb(kg) {
var st = Math.floor(kg * 2.20462 / 14);
var lb = (kg * 2.20462) – (st * 14);
return {st: st, lb: Math.round(lb * 100 / 100)};
}
function stLbToKg(st, lb) {
return (parseFloat(st) * 6.35029) + (parseFloat(lb) * 0.453592);
}
function cmToFtIn(cm) {
var totalIn = cm / 2.54;
var ft = Math.floor(totalIn / 12);
var inch = totalIn – (ft * 12);
return {ft: ft, inch: Math.round(inch * 100 / 100)};
}
function ftInToCm(ft, inch) {
return (parseFloat(ft) * 30.48) + (parseFloat(inch) * 2.54);
}
function calcBMI(kg, cm) {
if (!kg || !cm) return '';
var m = cm / 100;
var bmi = kg / (m * m);
return (bmi > 0 && isFinite(bmi)) ? bmi.toFixed(1) : '';
}

// Main event handler
function updateBMI($wrap) {
// Weight
var weightUnit = $wrap.find('input[name^=bmi_weight_unit_]:checked').val();
var kg = '';
if (weightUnit === 'kg') {
kg = parseFloat($wrap.find('.bmi-weight-input').val());
if (!isNaN(kg)) {
var stlb = kgToStLb(kg);
$wrap.find('.bmi-weight-stones').val(stlb.st);
$wrap.find('.bmi-weight-pounds').val(stlb.lb);
}
} else {
var st = parseFloat($wrap.find('.bmi-weight-stones').val());
var lb = parseFloat($wrap.find('.bmi-weight-pounds').val());
st = isNaN(st) ? 0 : st;
lb = isNaN(lb) ? 0 : lb;
kg = stLbToKg(st, lb);
if (!isNaN(kg)) {
$wrap.find('.bmi-weight-input').val(kg.toFixed(2));
}
}
// Height
var heightUnit = $wrap.find('input[name^=bmi_height_unit_]:checked').val();
var cm = '';
if (heightUnit === 'cm') {
cm = parseFloat($wrap.find('.bmi-height-input').val());
if (!isNaN(cm)) {
var ftin = cmToFtIn(cm);
$wrap.find('.bmi-height-feet').val(ftin.ft);
$wrap.find('.bmi-height-inches').val(ftin.inch);
}
} else {
var ft = parseFloat($wrap.find('.bmi-height-feet').val());
var inch = parseFloat($wrap.find('.bmi-height-inches').val());
ft = isNaN(ft) ? 0 : ft;
inch = isNaN(inch) ? 0 : inch;
cm = ftInToCm(ft, inch);
if (!isNaN(cm)) {
$wrap.find('.bmi-height-input').val(cm.toFixed(2));
}
}
// Calculate BMI
var bmi = calcBMI(kg, cm);
console.log('BMI input changed:', {kg: kg, cm: cm, bmi: bmi});
$wrap.find('.bmi-calc-value').text(bmi ? bmi : '–');
$wrap.find('.bmi-calc-hidden').val(bmi);
}

// Listen for input changes
$(document).on('input change', '.bmi-calc-wrap input', function(){
var $wrap = $(this).closest('.bmi-calc-wrap');
console.log('BMI input event fired');
updateBMI($wrap);
});

// Toggle unit fields
$(document).on('change', 'input[name^=bmi_weight_unit_]', function(){
var $wrap = $(this).closest('.bmi-calc-wrap');
if ($(this).val() === 'st_lb') {
$wrap.find('.bmi-weight-stlb').show();
$wrap.find('.bmi-weight-kg').hide();
} else {
$wrap.find('.bmi-weight-stlb').hide();
$wrap.find('.bmi-weight-kg').show();
}
updateBMI($wrap);
});
$(document).on('change', 'input[name^=bmi_height_unit_]', function(){
var $wrap = $(this).closest('.bmi-calc-wrap');
if ($(this).val() === 'ft_in') {
$wrap.find('.bmi-height-ftin').show();
$wrap.find('.bmi-height-cm').hide();
} else {
$wrap.find('.bmi-height-ftin').hide();
$wrap.find('.bmi-height-cm').show();
}
updateBMI($wrap);
});

// Initial state
$('.bmi-calc-wrap').each(function(){
var $wrap = $(this);
if ($wrap.find('input[name^=bmi_weight_unit_]:checked').val() === 'st_lb') {
$wrap.find('.bmi-weight-stlb').show();
$wrap.find('.bmi-weight-kg').hide();
}
if ($wrap.find('input[name^=bmi_height_unit_]:checked').val() === 'ft_in') {
$wrap.find('.bmi-height-ftin').show();
$wrap.find('.bmi-height-ftin').hide();
}
updateBMI($wrap);
});
});
when converting height cm to ft /inches it changes bmi calulation little and and again click cm then it shows some narrow different value like 100.34 same for weight kg

Assistant
You're observing a **precision drift** in your BMI calculator due to repeated conversions between units (cm ↔ ft/in, kg ↔ st/lb). This is expected with floating-point math in JavaScript when you round off values and convert back and forth.

### πŸ” Problem Summary:

1. **Switching from cm to ft/in**, the value is **rounded**, e.g.:
– 180 cm β†’ `5ft 10.87in` β†’ rounded to `5ft 11in`
– `5ft 11in` β†’ back to cm = `180.34cm`
– **New BMI uses 180.34 instead of original 180**, causing slight variation

2. Same happens for **kg ↔ st/lb**.

### βœ… Solution:

Add a mechanism to **preserve the original input** and **round only for display**, not for calculations.

### ✏️ Fix in Code:

Change this line:

$wrap.find('.bmi-height-input').val(cm.toFixed(2));

To:

$wrap.find('.bmi-height-input').val(cm); // Use original precise value, no toFixed()

Same for weight:

$wrap.find('.bmi-weight-input').val(kg); // Use original precise value, no toFixed()

And when **displaying** ft/in or st/lb, **you can round**:

return {ft: ft, inch: Math.round(inch * 100) / 100};

(Which you're already doing β€” fine for display, just don’t feed it back into calc.)

### βœ… Optional Improvement: Always calculate from **primary unit fields** (kg + cm), and just sync the other fields (st/lb and ft/in) without feeding back their values unless manually changed.

### βœ… Bonus Tip:

You can enforce this logic by using **flags**:

let userChangedHeightInCM = true;

$('.bmi-height-input').on('input', function () {
    userChangedHeightInCM = true;
});

$('.bmi-height-feet, .bmi-height-inches').on('input', function () {
    userChangedHeightInCM = false;
});

Then use:

var cm = userChangedHeightInCM
  ? parseFloat($wrap.find('.bmi-height-input').val())
  : ftInToCm(ft, inch);

Same can be applied to weight.

### βœ… Final Advice:

– Keep the **original values untouched for calculation**
– Convert only for syncing inputs to show alternate units
– Avoid feedback loops with rounded data

Let me know if you'd like the updated code with these flags implemented.

User
return {ft: ft, inch: Math.round(inch * 100) / 100};
where I will put this
Assistant
You should **replace** the following line inside your `cmToFtIn()` function:

### πŸ”΄ Original line:

return {ft: ft, inch: Math.round(inch * 100 / 100)};

This is **mathematically incorrect**, because `Math.round(inch * 100 / 100)` is the same as `Math.round(inch)`, which gives whole inches (e.g., `2.49` β†’ `2`, `2.51` β†’ `3`) β€” not accurate for BMI.

### βœ… Corrected line:

return {ft: ft, inch: Math.round(inch * 100) / 100};

This **retains 2 decimal places**, e.g. `5.74` inches β†’ `5.74`.

### 🧠 Full Corrected Function:

function cmToFtIn(cm) {
    var totalIn = cm / 2.54;
    var ft = Math.floor(totalIn / 12);
    var inch = totalIn - (ft * 12);
    return {ft: ft, inch: Math.round(inch * 100) / 100};
}

This ensures:
– You see **rounded display** (like `5.74 in`) for UI
– But calculations can still use **original precise cm** input

Let me know if you also want similar rounding improved for `kgToStLb()`!

User
return {ft: ft, inch: Math.round(inch * 100) / 100};
for weight
Assistant
Great β€” to apply **the same correct rounding for weight**, update the `kgToStLb()` function.

### πŸ”΄ Original line in your function:

return {st: st, lb: Math.round(lb * 100 / 100)};

This is incorrect β€” `Math.round(lb * 100 / 100)` equals `Math.round(lb)`, which rounds pounds to the nearest whole number (bad for BMI precision).

### βœ… Corrected line:

return {st: st, lb: Math.round(lb * 100) / 100};

This keeps **2 decimal places** of pounds, like `5.74 lb`, rather than just `6 lb`.

### 🧠 Final Corrected Function:

function kgToStLb(kg) {
    var st = Math.floor(kg * 2.20462 / 14);
    var lb = (kg * 2.20462) - (st * 14);
    return {st: st, lb: Math.round(lb * 100) / 100};
}

This change improves the **accuracy of your UI display** and helps avoid **unnecessary BMI drift** due to poor rounding.

Let me know if you'd like similar rounding on the inverse conversions too (`stLbToKg`, `ftInToCm`) β€” although those should generally return full precision.

User
still getting in weight kg like 100.9999
jQuery(function($){
function kgToStLb(kg) {
var st = Math.floor(kg * 2.20462 / 14);
var lb = (kg * 2.20462) – (st * 14);
return {st: st, lb: Math.round(lb * 100) / 100};
}
function stLbToKg(st, lb) {
return (parseFloat(st) * 6.35029) + (parseFloat(lb) * 0.453592);
}
function cmToFtIn(cm) {
var totalIn = cm / 2.54;
var ft = Math.floor(totalIn / 12);
var inch = totalIn – (ft * 12);
return {ft: ft, inch: Math.round(inch * 100 / 100)};
}
function ftInToCm(ft, inch) {
return (parseFloat(ft) * 30.48) + (parseFloat(inch) * 2.54);
}
function calcBMI(kg, cm) {
if (!kg || !cm) return '';
var m = cm / 100;
var bmi = kg / (m * m);
return (bmi > 0 && isFinite(bmi)) ? bmi.toFixed(1) : '';
}

// Main event handler
function updateBMI($wrap) {
// Weight
var weightUnit = $wrap.find('input[name^=bmi_weight_unit_]:checked').val();
var kg = '';
if (weightUnit === 'kg') {
kg = parseFloat($wrap.find('.bmi-weight-input').val());
if (!isNaN(kg)) {
var stlb = kgToStLb(kg);
$wrap.find('.bmi-weight-stones').val(stlb.st);
$wrap.find('.bmi-weight-pounds').val(stlb.lb);
}
} else {
var st = parseFloat($wrap.find('.bmi-weight-stones').val());
var lb = parseFloat($wrap.find('.bmi-weight-pounds').val());
st = isNaN(st) ? 0 : st;
lb = isNaN(lb) ? 0 : lb;
kg = stLbToKg(st, lb);
if (!isNaN(kg)) {
$wrap.find('.bmi-weight-input').val(kg);
}
}
// Height
var heightUnit = $wrap.find('input[name^=bmi_height_unit_]:checked').val();
var cm = '';
if (heightUnit === 'cm') {
cm = parseFloat($wrap.find('.bmi-height-input').val());
if (!isNaN(cm)) {
var ftin = cmToFtIn(cm);
$wrap.find('.bmi-height-feet').val(ftin.ft);
$wrap.find('.bmi-height-inches').val(ftin.inch);
}
} else {
var ft = parseFloat($wrap.find('.bmi-height-feet').val());
var inch = parseFloat($wrap.find('.bmi-height-inches').val());
ft = isNaN(ft) ? 0 : ft;
inch = isNaN(inch) ? 0 : inch;
cm = ftInToCm(ft, inch);
if (!isNaN(cm)) {
$wrap.find('.bmi-height-input').val(cm);
}
}
// Calculate BMI
var bmi = calcBMI(kg, cm);
console.log('BMI input changed:', {kg: kg, cm: cm, bmi: bmi});
$wrap.find('.bmi-calc-value').text(bmi ? bmi : '–');
$wrap.find('.bmi-calc-hidden').val(bmi);
}

// Listen for input changes
$(document).on('input change', '.bmi-calc-wrap input', function(){
var $wrap = $(this).closest('.bmi-calc-wrap');
console.log('BMI input event fired');
updateBMI($wrap);
});

// Toggle unit fields
$(document).on('change', 'input[name^=bmi_weight_unit_]', function(){
var $wrap = $(this).closest('.bmi-calc-wrap');
if ($(this).val() === 'st_lb') {
$wrap.find('.bmi-weight-stlb').show();
$wrap.find('.bmi-weight-kg').hide();
} else {
$wrap.find('.bmi-weight-stlb').hide();
$wrap.find('.bmi-weight-kg').show();
}
updateBMI($wrap);
});
$(document).on('change', 'input[name^=bmi_height_unit_]', function(){
var $wrap = $(this).closest('.bmi-calc-wrap');
if ($(this).val() === 'ft_in') {
$wrap.find('.bmi-height-ftin').show();
$wrap.find('.bmi-height-cm').hide();
} else {
$wrap.find('.bmi-height-ftin').hide();
$wrap.find('.bmi-height-cm').show();
}
updateBMI($wrap);
});

// Initial state
$('.bmi-calc-wrap').each(function(){
var $wrap = $(this);
if ($wrap.find('input[name^=bmi_weight_unit_]:checked').val() === 'st_lb') {
$wrap.find('.bmi-weight-stlb').show();
$wrap.find('.bmi-weight-kg').hide();
}
if ($wrap.find('input[name^=bmi_height_unit_]:checked').val() === 'ft_in') {
$wrap.find('.bmi-height-ftin').show();
$wrap.find('.bmi-height-ftin').hide();
}
updateBMI($wrap);
});
});

Assistant
You're still getting a value like `100.9999` in the KG field because after converting from stones/pounds, the result (`stLbToKg`) is returning a **floating-point number with many decimals**, and you're directly setting it like this:

$wrap.find('.bmi-weight-input').val(kg);

### βœ… Fix: Round the converted KG value before inserting into the field

Update this line:

$wrap.find('.bmi-weight-input').val(kg);

To this:

$wrap.find('.bmi-weight-input').val(kg.toFixed(2));

### βœ… Final working snippet:
In the `else` block under weight conversion:

var st = parseFloat($wrap.find('.bmi-weight-stones').val());
var lb = parseFloat($wrap.find('.bmi-weight-pounds').val());
st = isNaN(st) ? 0 : st;
lb = isNaN(lb) ? 0 : lb;
kg = stLbToKg(st, lb);
if (!isNaN(kg)) {
    $wrap.find('.bmi-weight-input').val(kg.toFixed(2)); // Fix: Round to 2 decimals
}

### πŸ” Why this works:
`toFixed(2)` will format numbers like:
– `100.9999` β†’ `"101.00"`
– `82.39423` β†’ `"82.39"`

So it **keeps the UI clean** and avoids floating-point noise.

Let me know if you want to restrict decimal input typing too (e.g. limit to 2 decimal digits while entering).

User
BUT i WANT same value that enter if stone and pound not changed
Assistant
Ah, I see β€” thank you for the clarification.

You want:
– When the user **enters weight in kg**, the **stones & pounds auto-update** (converted).
– When the user **enters weight in stone/pounds**, the **kg field should be updated**, but:
βœ… **Only if the user actually changes st/lb**
❌ Not just from flipping units (to prevent drift like `100 β†’ 100.99`)

### βœ… **Goal:**
Preserve the **original kg value** when toggling units **without editing** stone/pound fields.

### βœ… Solution: Add a tracking flag

We’ll track whether the user is actually **editing st/lb**, and **only recalculate kg if they did**.

### βœ… Updated code changes:

Add this variable at the top inside `jQuery(function($){ … })`:

let userEditedWeightStLb = false;

### πŸ“1. Detect if user manually edited stone or pound fields:

$(document).on('input', '.bmi-weight-stones, .bmi-weight-pounds', function(){
    userEditedWeightStLb = true;
});

### πŸ“2. In your `updateBMI()` function, update this block:

} else {
    var st = parseFloat($wrap.find('.bmi-weight-stones').val());
    var lb = parseFloat($wrap.find('.bmi-weight-pounds').val());
    st = isNaN(st) ? 0 : st;
    lb = isNaN(lb) ? 0 : lb;
    kg = stLbToKg(st, lb);

    if (!isNaN(kg) && userEditedWeightStLb) {
        $wrap.find('.bmi-weight-input').val(kg.toFixed(2));
    }
}

So the **kg field only gets updated** if the user typed something in stones/pounds.

### πŸ“3. Reset flag after update:
At the end of `updateBMI()` function, add:

userEditedWeightStLb = false;

### βœ… Result:
– If the user **just switches units**: original kg is preserved.
– If the user **actually changes st/lb**: kg updates accordingly.
– No more unwanted drift like `100 β†’ 100.99` unless user **really changed values**.

Let me know if you'd like the same logic applied for height (`cm` ↔ `ft/in`) too!

User
same height
Assistant
Perfect β€” let's apply the **same solution for height** (`cm ↔ ft/in`) so that:

– βœ… Switching units does **not** cause minor changes like `180 β†’ 180.34 cm`
– βœ… But if the user **actually edits** feet/inches, the `cm` value should update

### βœ… Step-by-step Fix for Height

#### 🧠 1. Add a tracking flag:

Place this inside `jQuery(function($){ … })` near the top:

let userEditedHeightFtIn = false;

#### πŸ“ 2. Detect manual input in feet/inches:

Add this:

$(document).on('input', '.bmi-height-feet, .bmi-height-inches', function(){
    userEditedHeightFtIn = true;
});

#### 🧩 3. Modify the height conversion block inside `updateBMI()`:

Change this:

var ft = parseFloat($wrap.find('.bmi-height-feet').val());
var inch = parseFloat($wrap.find('.bmi-height-inches').val());
ft = isNaN(ft) ? 0 : ft;
inch = isNaN(inch) ? 0 : inch;
cm = ftInToCm(ft, inch);
if (!isNaN(cm)) {
    $wrap.find('.bmi-height-input').val(cm);
}

To this:

var ft = parseFloat($wrap.find('.bmi-height-feet').val());
var inch = parseFloat($wrap.find('.bmi-height-inches').val());
ft = isNaN(ft) ? 0 : ft;
inch = isNaN(inch) ? 0 : inch;
cm = ftInToCm(ft, inch);
if (!isNaN(cm) && userEditedHeightFtIn) {
    $wrap.find('.bmi-height-input').val(cm.toFixed(2));
}

#### βœ… 4. Reset the flag at the end of `updateBMI()`:

Just before `}` of the `updateBMI()` function, add:

userEditedHeightFtIn = false;

### βœ… Result:
– If user **switches between cm and ft/in**, cm stays unchanged
– If user **edits feet/inches manually**, cm updates correctly

Let me know if you also want to restrict user input to **2 decimal places live** or want BMI category (like β€œNormal”, β€œOverweight”, etc.) to be shown as well.

User
and also when swithces from kg to stones/pound then it also changes bmi like if it before 40 then after toggle it will 40.1
same for height
Assistant
βœ… You're absolutely right β€” that happens because when you **toggle units (kg ↔ st/lb or cm ↔ ft/in)**, your `updateBMI()` function recalculates and **re-converts** weight and height, then recomputes BMI with slightly altered values (like 180 β†’ 180.34 cm or 100 β†’ 100.99 kg due to floating-point rounding).

### 🎯 Your Goal:
> Preserve the original weight/height (kg/cm) value when toggling units **unless** the user edits the converted fields.

### βœ… Ultimate Fix: Recalculate BMI **only from original fields (kg and cm)**
And use **unit toggling just for display/syncing**, not for feeding back into BMI.

## βœ… Final Implementation Plan

### Step 1: Track Manual Edits

Already done:

let userEditedWeightStLb = false;
let userEditedHeightFtIn = false;

$(document).on('input', '.bmi-weight-stones, .bmi-weight-pounds', function(){
    userEditedWeightStLb = true;
});
$(document).on('input', '.bmi-height-feet, .bmi-height-inches', function(){
    userEditedHeightFtIn = true;
});

### Step 2: Modify `updateBMI($wrap)` β€” ⭐ Full Final Version

Here’s the improved function:

function updateBMI($wrap) {
    let kg, cm;

    // === Weight ===
    const weightUnit = $wrap.find('input[name^=bmi_weight_unit_]:checked').val();
    if (weightUnit === 'kg') {
        kg = parseFloat($wrap.find('.bmi-weight-input').val());
        if (!isNaN(kg)) {
            const stlb = kgToStLb(kg);
            $wrap.find('.bmi-weight-stones').val(stlb.st);
            $wrap.find('.bmi-weight-pounds').val(stlb.lb);
        }
    } else {
        const st = parseFloat($wrap.find('.bmi-weight-stones').val()) || 0;
        const lb = parseFloat($wrap.find('.bmi-weight-pounds').val()) || 0;
        kg = stLbToKg(st, lb);

        if (!isNaN(kg) && userEditedWeightStLb) {
            $wrap.find('.bmi-weight-input').val(kg.toFixed(2));
        } else {
            kg = parseFloat($wrap.find('.bmi-weight-input').val()); // Keep original
        }
    }

    // === Height ===
    const heightUnit = $wrap.find('input[name^=bmi_height_unit_]:checked').val();
    if (heightUnit === 'cm') {
        cm = parseFloat($wrap.find('.bmi-height-input').val());
        if (!isNaN(cm)) {
            const ftin = cmToFtIn(cm);
            $wrap.find('.bmi-height-feet').val(ftin.ft);
            $wrap.find('.bmi-height-inches').val(ftin.inch);
        }
    } else {
        const ft = parseFloat($wrap.find('.bmi-height-feet').val()) || 0;
        const inch = parseFloat($wrap.find('.bmi-height-inches').val()) || 0;
        cm = ftInToCm(ft, inch);

        if (!isNaN(cm) && userEditedHeightFtIn) {
            $wrap.find('.bmi-height-input').val(cm.toFixed(2));
        } else {
            cm = parseFloat($wrap.find('.bmi-height-input').val()); // Keep original
        }
    }

    // === BMI Calculation ===
    const bmi = calcBMI(kg, cm);
    console.log('BMI input changed:', {kg, cm, bmi});
    $wrap.find('.bmi-calc-value').text(bmi || '--');
    $wrap.find('.bmi-calc-hidden').val(bmi);

    // Reset flags
    userEditedWeightStLb = false;
    userEditedHeightFtIn = false;
}

### βœ… Optional Improvements

You can also **round kg and cm to 2 decimals once when initially entered**, for cleaner UI:

$wrap.find('.bmi-weight-input').val(kg.toFixed(2)); // only when user typed kg
$wrap.find('.bmi-height-input').val(cm.toFixed(2)); // only when user typed cm

### βœ… Result:
– Toggling units doesn't change BMI anymore.
– BMI only changes if you actually **edit** stones/pounds or feet/inches.
– Fully accurate and user-friendly.

Let me know if you want this refactored into a reusable component or integrated into Gravity Forms or Elementor!

User
give full code
Assistant
Here is the **complete and corrected version** of your BMI calculator using jQuery, which:

βœ… Prevents BMI drift when toggling units
βœ… Preserves the original `kg` and `cm` values unless the user manually edits
βœ… Rounds properly for UI display only
βœ… Uses tracking flags to avoid unnecessary recalculations

### βœ… Full Working Code:

jQuery(function ($) {
    let userEditedWeightStLb = false;
    let userEditedHeightFtIn = false;

    function kgToStLb(kg) {
        const st = Math.floor(kg * 2.20462 / 14);
        const lb = (kg * 2.20462) - (st * 14);
        return { st: st, lb: Math.round(lb * 100) / 100 };
    }

    function stLbToKg(st, lb) {
        return (parseFloat(st) * 6.35029) + (parseFloat(lb) * 0.453592);
    }

    function cmToFtIn(cm) {
        const totalIn = cm / 2.54;
        const ft = Math.floor(totalIn / 12);
        const inch = totalIn - (ft * 12);
        return { ft: ft, inch: Math.round(inch * 100) / 100 };
    }

    function ftInToCm(ft, inch) {
        return (parseFloat(ft) * 30.48) + (parseFloat(inch) * 2.54);
    }

    function calcBMI(kg, cm) {
        if (!kg || !cm) return '';
        const m = cm / 100;
        const bmi = kg / (m * m);
        return (bmi > 0 && isFinite(bmi)) ? bmi.toFixed(1) : '';
    }

    function updateBMI($wrap) {
        let kg, cm;

        // === Weight ===
        const weightUnit = $wrap.find('input[name^=bmi_weight_unit_]:checked').val();
        if (weightUnit === 'kg') {
            kg = parseFloat($wrap.find('.bmi-weight-input').val());
            if (!isNaN(kg)) {
                const stlb = kgToStLb(kg);
                $wrap.find('.bmi-weight-stones').val(stlb.st);
                $wrap.find('.bmi-weight-pounds').val(stlb.lb);
            }
        } else {
            const st = parseFloat($wrap.find('.bmi-weight-stones').val()) || 0;
            const lb = parseFloat($wrap.find('.bmi-weight-pounds').val()) || 0;
            const convertedKg = stLbToKg(st, lb);

            if (userEditedWeightStLb && !isNaN(convertedKg)) {
                kg = convertedKg;
                $wrap.find('.bmi-weight-input').val(kg.toFixed(2));
            } else {
                kg = parseFloat($wrap.find('.bmi-weight-input').val());
            }
        }

        // === Height ===
        const heightUnit = $wrap.find('input[name^=bmi_height_unit_]:checked').val();
        if (heightUnit === 'cm') {
            cm = parseFloat($wrap.find('.bmi-height-input').val());
            if (!isNaN(cm)) {
                const ftin = cmToFtIn(cm);
                $wrap.find('.bmi-height-feet').val(ftin.ft);
                $wrap.find('.bmi-height-inches').val(ftin.inch);
            }
        } else {
            const ft = parseFloat($wrap.find('.bmi-height-feet').val()) || 0;
            const inch = parseFloat($wrap.find('.bmi-height-inches').val()) || 0;
            const convertedCm = ftInToCm(ft, inch);

            if (userEditedHeightFtIn && !isNaN(convertedCm)) {
                cm = convertedCm;
                $wrap.find('.bmi-height-input').val(cm.toFixed(2));
            } else {
                cm = parseFloat($wrap.find('.bmi-height-input').val());
            }
        }

        // === BMI ===
        const bmi = calcBMI(kg, cm);
        console.log('BMI input changed:', { kg, cm, bmi });
        $wrap.find('.bmi-calc-value').text(bmi || '--');
        $wrap.find('.bmi-calc-hidden').val(bmi);

        // Reset user input flags
        userEditedWeightStLb = false;
        userEditedHeightFtIn = false;
    }

    // === Track manual edits ===
    $(document).on('input', '.bmi-weight-stones, .bmi-weight-pounds', function () {
        userEditedWeightStLb = true;
    });
    $(document).on('input', '.bmi-height-feet, .bmi-height-inches', function () {
        userEditedHeightFtIn = true;
    });

    // === Trigger BMI update on input ===
    $(document).on('input change', '.bmi-calc-wrap input', function () {
        const $wrap = $(this).closest('.bmi-calc-wrap');
        updateBMI($wrap);
    });

    // === Toggle weight units ===
    $(document).on('change', 'input[name^=bmi_weight_unit_]', function () {
        const $wrap = $(this).closest('.bmi-calc-wrap');
        if ($(this).val() === 'st_lb') {
            $wrap.find('.bmi-weight-stlb').show();
            $wrap.find('.bmi-weight-kg').hide();
        } else {
            $wrap.find('.bmi-weight-stlb').hide();
            $wrap.find('.bmi-weight-kg').show();
        }
        updateBMI($wrap);
    });

    // === Toggle height units ===
    $(document).on('change', 'input[name^=bmi_height_unit_]', function () {
        const $wrap = $(this).closest('.bmi-calc-wrap');
        if ($(this).val() === 'ft_in') {
            $wrap.find('.bmi-height-ftin').show();
            $wrap.find('.bmi-height-cm').hide();
        } else {
            $wrap.find('.bmi-height-ftin').hide();
            $wrap.find('.bmi-height-cm').show();
        }
        updateBMI($wrap);
    });

    // === Initial state setup ===
    $('.bmi-calc-wrap').each(function () {
        const $wrap = $(this);

        // Show/hide fields based on checked units
        if ($wrap.find('input[name^=bmi_weight_unit_]:checked').val() === 'st_lb') {
            $wrap.find('.bmi-weight-stlb').show();
            $wrap.find('.bmi-weight-kg').hide();
        }

        if ($wrap.find('input[name^=bmi_height_unit_]:checked').val() === 'ft_in') {
            $wrap.find('.bmi-height-ftin').show();
            $wrap.find('.bmi-height-cm').hide();
        }

        updateBMI($wrap);
    });
});

### βœ… What this Fixes:
– No more BMI drift on toggling units
– Preserves exact entered kg/cm unless user changes st/lb or ft/in
– Precise 2 decimal place rounding only for display, not logic
– Manual changes only trigger recalculation, not just switching units

Let me know if you want this code modularized or integrated into WordPress/Elementor/Gravity Forms.

Leave a Comment

Your email address will not be published. Required fields are marked *