Search code examples
javascriptcallbacksveltesveltekit

Sveltekit on change function not being called when added to a component


I've got the following component called NumericField:

<script>
    import {isNumber} from "../../helpers/index.js";
    import {onMount} from "svelte";

    export let name;
    export let id;
    export let value;
    export let readOnly=false;
    export let disabled=false; // use disabled so we don't submit the value.
    export let styleClass="input w-full py-4 font-medium bg-gray-100 border-gray-200 text-sm\n" +
        "                                  focus:outline-none focus:border-gray-400 focus:bg-white";


    onMount(() => {
        // if a value is provided for the field then format it and place it in it.
        if (value !== null && value !== undefined) {
            value = formatNumber(value);
            return;
        }

        // if a value was not provided or is not a valid numeric field then set the field value to empty.
        value="";
    });

    const formatNumber = e => {

        // on keyup validate if the value is "", if so return. This is to avoid placing a NaN on the field.
        if (e.target?.value == "") {
            return
        }

        if (parseInt(String(e).replace(/,/g,'')) === NaN) {
            e.target.value = "";
            return
        }

        // if e is not an event (event is of type object) but a number (this will apply for on edit mode or read only fields).
        if (typeof e !== 'object' && (isNumber(e) || isNumber(parseInt(e)))) {
            console.log("not an event. value = ", e)
            // remove all commas (,) from the number and return it.
            return parseInt(String(e).replace(/,/g,'')).toLocaleString("en-US");
        }

        // reformat the given number by adding commas to it but since this is recalculated on the fly first we
        // have to remove any existing commas.
        e.target.value = parseInt(e.target.value.replace(/,/g,'')).toLocaleString("en-US");
    }
</script>

<input
    id={id}
    on:keyup={formatNumber}
    name={name}
    readonly={readOnly}
    disabled={disabled}
    type="text"
    bind:value
    class={styleClass} />

And I've got a form in which I'm using the component:

<NumericField
    on:change={updateTotal}
    bind:purchasedPrice
    id="purchasedPrice"
    name="purchased_price" />

I'm calling updateTotal to calculate the total based on the value inputed in the component, but my function is never called:

const updateTotal = () => {
    console.log("here in updateTotal")
}

what am I doing wrong?

What I need at the end of the day is to simply calculate a total based on the value of NumericField, so that's the way I'm trying to do it, but before I had something like:

$: total += total + purchasedPrice

but purchasedPrice is not reactive for some reason, if I do:

$: console.log("purchasedPrice: ", purchasedPrice)

I just got 0 once, when the parent component is initialized, but everytime purchasedPrice the message is not printed again.


Solution

  • Edit:

    After reading the comment, the handler seems like unnecessary. Funny I've been manually dispatching it for a while.

    It may be becuase you forgot to dispatch the change event from your NumericField component.

    Try adding in the component:

    ... 
    <input on:change   <--- this part 
            id={id}
            on:keyup={formatNumber}
            name={name}
            readonly={readOnly}
            disabled={disabled}
            type="text"
            bind:value
            class={styleClass}
        />
    ...