Skip to content

Feature request: data-[identifier]-model to implement equivalent of Vue's v-model #859

@christophehenry

Description

@christophehenry

So this is a pattern I frenquently come accross when using Stimulus on forms: reacting to <input>'s value change like displaying parts of a form according to a checkbox. Currently, the way I implement it is like this:

<input type="checkbox" data-action="[identifier]#OnChange" />
<fieldset data-[identfier]-target="fieldset"></fieldset>
import {Controller} from "Stimulus";

class FormController extends Controller {
    static targets = ["fieldset"]

    onChange({target: {checked}}) {
        if(checked) { this.fieldsetTarget.setAttribute("hidden", "hidden"); }
        else { this.fieldsetTarget.removeAttribute("hidden", "hidden"); }
    }
}

However, since events are only fired on user interactions, this forces us to add some boilerplate to get the correct display upon init:

<input data-[identfier]-target="checkbox" type="checkbox" data-action="[identifier]#OnChange" />
<fieldset data-[identfier]-target="fieldset"></fieldset>
import {Controller} from "Stimulus";

class FormController extends Controller {
    static targets = ["fieldset", "checkbox"]

    onChange({target: {checked}}) {
        this.mutateFieldsetVisibility(checked)
    }

    checkboxTargetConnected(el) {
        this.mutateFieldsetVisibility(el.checked);
    }

    mutateFieldsetVisibility(visible) {
        if(checked) { this.fieldsetTarget.setAttribute("hidden", "hidden"); }
        else { this.fieldsetTarget.removeAttribute("hidden", "hidden"); }
    }
}

Just to get the correct init, we need to declare a target on the input that will only be used once in the controller's lifetime.

What I propose propose to add a new data-[identifier]-model that would work exactly like Vue's v-model:

<input data-[identfier]-model="checkbox" type="checkbox" />
<fieldset data-[identfier]-target="fieldset"></fieldset>
import {Controller} from "Stimulus";

class FormController extends Controller {
    static targets = ["fieldset"]
    static models = ["checkbox"]

    checkboxModelChange(value) {
        // or can be accessed through `this.checkboxModel`
        if(value) { this.fieldsetTarget.setAttribute("hidden", "hidden"); }
        else { this.fieldsetTarget.removeAttribute("hidden", "hidden"); }
    }
}

If this is too inconvenient to implement, can you indicate me how to leverage Stimulus' API to implement it as an extension similar to stimulus-use? This would require dynamic target and value binding and I don't believe this can be done after controller's initialize() lifecycle phase, can it?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions