Yew: Use a complex onclick

Created on 19 Jul 2018  路  2Comments  路  Source: yewstack/yew

I'm struggling with complex onclick.

My Model has a function:

...
let on_click = |editing : EditSensor| -> Msg {
            if !editing.is_valid() {
                Msg::Nothing
            }
            else {
                let sensor = Sensor {
                    id: editing.id,
                    latitude: editing.latitude.unwrap(),
                    longitude: editing.longitude.unwrap()
                };
                Msg::AddSensor(sensor)
            }
        };
        let editing = self.editing_sensor.clone();

        html! {
            <form>
                <fieldset class="uk-fieldset",>
                    <legend class="uk-legend",>{"Sensor"}</legend>
                    <input class={form_input_state(self.editing_sensor.has_valid_id())}, placeholder="Sensor ID", value=&self.editing_sensor.id, oninput=|e| Msg::EditingSensorId(e.value), />
                    <input class={form_input_state(self.editing_sensor.has_valid_latitude())}, placeholder="Latitude", value=latitude, oninput=|e|Msg::EditingSensorLatitude(e.value.parse::<f64>().ok()), />
                    <input class={form_input_state(self.editing_sensor.has_valid_longitude())}, placeholder="Longitude", value=longitude, oninput=|e| Msg::EditingSensorLongitude(e.value.parse::<f64>().ok()), />
                    <button class="uk-button uk-button-default",
                            disabled={!self.editing_sensor.is_valid()},
                            onclick= |_| {
                                on_click(editing)
                            },>
                            {"Add Sensor"}
                    </button>
                </fieldset>
            </form>
        }

I cannot get on_click to work (lifetime issues). All of the examples have onclick simply returning a Msg but I want to do some validation and construct a Msg.

question

Most helpful comment

The typical way to accomplish this is to create a new Msg variant and in update, put the logic you currently have defined in your on_click closure for that variant. Call self.update(Msg::AddSensor) at end of your variants logic instead of returning it (also return false for ShouldRender..
in your onclick, return that message.

An abbreviated version of your example might look like;


/// update
    match msg {
        Msg::NewVariant => {
            let editing = self.editing_sensor.clone(); // cloning may not be necessary here
            if !editing.is_valid() {
                self.update(Msg::Nothing) // Technically, you probably shouldn't redirect to a no-op message, instead, just do nothing.
            }
            else {
                let sensor = Sensor {
                    id: editing.id,
                    latitude: editing.latitude.unwrap(),
                    longitude: editing.longitude.unwrap()
                };
                self.update(Msg::AddSensor(sensor))
            }
            return false;
        }
        Msg::AddSensor(sensor) => {},
        Msg::Nothing => {}
    }

/// view
html! {
    <button onclick=|_| Msg::NewVariant, > {"Add Sensor"} </button>
}

Ultimately, Yew forces you to move as much of your logic that is dependent on your component's state into the update method. Keep your callbacks simple will make your life easier.

All 2 comments

The typical way to accomplish this is to create a new Msg variant and in update, put the logic you currently have defined in your on_click closure for that variant. Call self.update(Msg::AddSensor) at end of your variants logic instead of returning it (also return false for ShouldRender..
in your onclick, return that message.

An abbreviated version of your example might look like;


/// update
    match msg {
        Msg::NewVariant => {
            let editing = self.editing_sensor.clone(); // cloning may not be necessary here
            if !editing.is_valid() {
                self.update(Msg::Nothing) // Technically, you probably shouldn't redirect to a no-op message, instead, just do nothing.
            }
            else {
                let sensor = Sensor {
                    id: editing.id,
                    latitude: editing.latitude.unwrap(),
                    longitude: editing.longitude.unwrap()
                };
                self.update(Msg::AddSensor(sensor))
            }
            return false;
        }
        Msg::AddSensor(sensor) => {},
        Msg::Nothing => {}
    }

/// view
html! {
    <button onclick=|_| Msg::NewVariant, > {"Add Sensor"} </button>
}

Ultimately, Yew forces you to move as much of your logic that is dependent on your component's state into the update method. Keep your callbacks simple will make your life easier.

Question was answered

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sanpii picture sanpii  路  3Comments

IngwiePhoenix picture IngwiePhoenix  路  4Comments

sackery picture sackery  路  3Comments

agausmann picture agausmann  路  3Comments

nixpulvis picture nixpulvis  路  4Comments