Tommertom / svelte-ionic-npm

NPM package that goes along with Ionic Svelte integration demo
MIT License
19 stars 0 forks source link

bind:value to input elements does not work #11

Open Tommertom opened 1 year ago

Tommertom commented 1 year ago

Copy from https://github.com/Tommertom/svelte-ionic-app/issues/33

Reason why this is not work : https://github.com/sveltejs/svelte/issues/4838

Workaround - grab ionChange event on ion-input and use the event.detail.value to change the variable.

Or if you are using bigger forms, an integrated forms-suite that handles this for you is even better. Then you get more goodies https://github.com/Tommertom/svelte-ionic-app/issues/33#issuecomment-1193364960

The earlier mentioned alternative to create svelte native wrappers like IonInput.svelte will resolve this too, but then we run into other problems with respect to styling of elements. So that route seems a dead end for now.

Keeping this issue open until something better comes up

kutoman commented 1 year ago

@Tommertom I would suggest another workaround: using actions. This way neither wrappers for the actual components (having the styling issue) have to be written nor the event listeners have to be set manually. The only drawback is, as far as I can grasp, that writeable stores have to be used instead of plain component properties.

<script lang="ts">
    import { bindIonInputValue } from "../ionActions";

    let text = writable("text")
</script>
<ion-input use:bindIonInputValue={text} label={"my label"}/>

ionActions

import type { InputChangeEventDetail, IonInputCustomEvent } from "@ionic/core/dist/types/components";
import { type Writable, get } from "svelte/store";

export function bindIonInputValue(element: HTMLIonInputElement, store: Writable<string | number>): ActionReturn<Writable<string | number>> {

    function eventListener(e: IonInputCustomEvent<InputChangeEventDetail>) {
        store.set(e.detail.value)
    }

    function _set(store: Writable<string | number>) {
        element.value = get(store)
        element.addEventListener('ionInput', eventListener)
    }

    _set(store)
    return {
        update: _set,
        destroy: () => element.removeEventListener('ionInput', eventListener)
    }
}

export interface ActionReturn<Parameter = any> {
    update?: (parameter: Parameter) => void;
    destroy?: () => void;
}
Tommertom commented 1 year ago

@Tommertom

I would suggest another workaround: using actions. This way neither wrappers for the actual components (having the styling issue) have to be written nor the event listeners have to be set manually. The only drawback is, as far as I can grasp, that writeable stores have to be used instead of plain component properties.


<script lang="ts">

    import { bindIonInputValue } from "../ionActions";

    let text = writable("text")

</script>

<ion-input use:bindIonInputValue={text} label={"my label"}/>

ionActions


import type { InputChangeEventDetail, IonInputCustomEvent } from "@ionic/core/dist/types/components";

import { type Writable, get } from "svelte/store";

export function bindIonInputValue(element: HTMLIonInputElement, store: Writable<string | number>): ActionReturn<Writable<string | number>> {

    function eventListener(e: IonInputCustomEvent<InputChangeEventDetail>) {

        store.set(e.detail.value)

    }

    function _set(store: Writable<string | number>) {

        element.value = get(store)

        element.addEventListener('ionInput', eventListener)

    }

    _set(store)

    return {

        update: _set,

        destroy: () => element.removeEventListener('ionInput', eventListener)

    }

}

export interface ActionReturn<Parameter = any> {

  update?: (parameter: Parameter) => void;

  destroy?: () => void;

}

Thanks for sharing - got to think this through. I like to avoid creating documentation and deviations from the ionic api docs- but it does look interesting

CatchABus commented 10 months ago

@Tommertom I'll answer here to avoid out-of-topic posts in svelte thread.

For svelte-native, we use svelte-native-preprocessor As of what it's doing, here's an example:

Before preprocessing:

<textfield bind:text={myText}/>

After:

<textfield text={myText} on:textChange={(e) => myText = e.value}/>

Each NativeScript attribute has support for a corresponding event and that's why this is possible. This preprocessing is a bit slow however, as it's developed to turn markup content to AST and traverses it to modify binding attributes. I truly hope this helps you somehow, until svelte makes a decision.