Yew: How to handle forms?

Created on 20 Feb 2019  路  3Comments  路  Source: yewstack/yew

Description

  • [x] question
  • [ ] feature request
  • [ ] bug report

Find a smart way to handle a form.

Expected Results

<form onsubmit=|e| { e.prevent_default(); Msg::Submit(FormData::from(e.target()) },>
    <input type="text", value=&self.search, />
    <button>{ "Search" }</button>
</form>

Retrieving a FormData object from an HTML form.

Actual Results

If I correctly understand, to handle a form I need a message for each input to update model state and a message for the submit button.

<div>
    <input type="text", value=&self.search, oninput=|e| Msg::Update(e.value) />
    <button onclick=|_| Msg::Submit>{ "Search" }</button>
</div>

I don鈥檛 know if my proposal is the good way to do that (I discovert FormData while writing this issue) but it seems less painful than added one message per input.

Most helpful comment

I play with stdweb to implement FormData, and here is a real example:

use stdweb::web::FormData;
use stdweb::web::event::IEvent;
use stdweb::unstable::TryInto;
use yew::{html,  Component, ComponentLink, Html, Renderable, ShouldRender};

#[derive(Default)]
pub struct Model {
    state: State,
}

#[derive(Debug, Default)]
pub struct State {
    terms: String,
    strict: bool,
}

impl From<FormData> for State {
    fn from(data: FormData) -> Self {
        Self {
            terms: data.get("terms").into_string().unwrap(),
            strict: data.get("strict").as_str() == Some("on"),
        }
    }
}

impl std::fmt::Display for State {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

pub enum Msg {
    Submit(FormData),
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
        Default::default()
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::Submit(data) => self.state = data.into(),
        }

        true
    }
}

impl Renderable<Model> for Model {
    fn view(&self) -> Html<Self> {
        html! {
            <div>
                <form onsubmit=|e| { e.prevent_default(); Msg::Submit(FormData::new(&e.target().unwrap().try_into().unwrap())) },>
                    <input type="text", name="terms", value=&self.state.terms, />
                    <input type="checkbox", name="strict", checked=self.state.strict, />
                    <button>{ "Search" }</button>
                </form>
            </div>

            <div>{ &self.state }</div>
        }
    }
}

All 3 comments

I play with stdweb to implement FormData, and here is a real example:

use stdweb::web::FormData;
use stdweb::web::event::IEvent;
use stdweb::unstable::TryInto;
use yew::{html,  Component, ComponentLink, Html, Renderable, ShouldRender};

#[derive(Default)]
pub struct Model {
    state: State,
}

#[derive(Debug, Default)]
pub struct State {
    terms: String,
    strict: bool,
}

impl From<FormData> for State {
    fn from(data: FormData) -> Self {
        Self {
            terms: data.get("terms").into_string().unwrap(),
            strict: data.get("strict").as_str() == Some("on"),
        }
    }
}

impl std::fmt::Display for State {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:?}", self)
    }
}

pub enum Msg {
    Submit(FormData),
}

impl Component for Model {
    type Message = Msg;
    type Properties = ();

    fn create(_: Self::Properties, _: ComponentLink<Self>) -> Self {
        Default::default()
    }

    fn update(&mut self, msg: Self::Message) -> ShouldRender {
        match msg {
            Msg::Submit(data) => self.state = data.into(),
        }

        true
    }
}

impl Renderable<Model> for Model {
    fn view(&self) -> Html<Self> {
        html! {
            <div>
                <form onsubmit=|e| { e.prevent_default(); Msg::Submit(FormData::new(&e.target().unwrap().try_into().unwrap())) },>
                    <input type="text", name="terms", value=&self.state.terms, />
                    <input type="checkbox", name="strict", checked=self.state.strict, />
                    <button>{ "Search" }</button>
                </form>
            </div>

            <div>{ &self.state }</div>
        }
    }
}

Looks like this has been fixed!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zethra picture zethra  路  5Comments

djahandarie picture djahandarie  路  3Comments

ghost picture ghost  路  4Comments

sackery picture sackery  路  3Comments

thienpow picture thienpow  路  3Comments