{"id":13688510,"url":"https://github.com/jfbilodeau/yew_form","last_synced_at":"2025-04-05T01:06:49.017Z","repository":{"id":39979491,"uuid":"242811953","full_name":"jfbilodeau/yew_form","owner":"jfbilodeau","description":"Components to simplify handling forms with Yew","archived":false,"fork":false,"pushed_at":"2022-03-23T23:24:11.000Z","size":134,"stargazers_count":96,"open_issues_count":10,"forks_count":16,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-29T00:09:02.116Z","etag":null,"topics":["rust","yew","yew-form"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jfbilodeau.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-24T18:31:33.000Z","updated_at":"2024-10-25T14:08:13.000Z","dependencies_parsed_at":"2022-06-26T00:44:29.032Z","dependency_job_id":null,"html_url":"https://github.com/jfbilodeau/yew_form","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfbilodeau%2Fyew_form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfbilodeau%2Fyew_form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfbilodeau%2Fyew_form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfbilodeau%2Fyew_form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jfbilodeau","download_url":"https://codeload.github.com/jfbilodeau/yew_form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247271530,"owners_count":20911587,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["rust","yew","yew-form"],"created_at":"2024-08-02T15:01:15.621Z","updated_at":"2025-04-05T01:06:48.998Z","avatar_url":"https://github.com/jfbilodeau.png","language":"Rust","funding_links":[],"categories":["Rust","Crates"],"sub_categories":["Components"],"readme":"[![License:MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![License:Apache](https://img.shields.io/badge/License-Apache-yellow.svg)](https://opensource.org/licenses/Apache-2.0)\n# Yew Form\nBringing MVC to Yew! A set of mildly opinionated Yew component to map and validate a model to a HTML form.\n\n[Live demo](http://chronogears.com/yew-form/)\n\nSupports:\n- 2-way Binding to struct (with support for nested structs)\n- Validation ([using Keats Validator](https://github.com/Keats/validator))\n- Only `String` and `bool` fields are supported presently. More to come\n\n## Usage\nCargo.toml:\n```toml\n[dependencies]\nvalidator = \"0.14\"\nvalidator_derive = \"0.14\"\nyew = \"0.18\"\nyew_form = \"0.1\"\nyew_form_derive = \"0.1\"\n```\nmain.rs:\n```rust\n#[macro_use]\nextern crate validator_derive;\nextern crate yew_form;\n#[macro_use]\nextern crate yew_form_derive;\n```\n\n## Example\nConsider the following model:\n```rust\n#[derive(Model, Validate, PartialEq, Clone)]\nstruct Address {\n    #[validate(length(min = 1, message=\"Street is required\"))]\n    street: String,\n    #[validate(length(min = 1, message=\"City name is required\"))]\n    city: String,\n    #[validate(regex(path=\"PROVINCE_RE\", message=\"Enter 2 digit province code\"))]\n    province: String,\n    postal_code: String,\n    country: String,\n}\n\n#[derive(Model, Validate, PartialEq, Clone)]\nstruct Registration {\n    #[validate(length(min = 1, message=\"First name is required\"))]\n    first_name: String,\n    #[validate(length(min = 1, message=\"Last name is required\"))]\n    last_name: String,\n    quantity: u32,\n    price: f64,\n    #[validate]\n    address: Address,\n    #[validate(custom = \"must_be_true\")]\n    accept_terms: bool,\n}\n```\n\nThe struct can be bound to a Yew form using the following definition:\n\n```rust\nstruct App {\n    form: Form\u003cRegistration\u003e,\n    ...\n}\n```\n\nFor now, the `Form` needs to be instantiated as follows:\n```rust\nfn create(_props: Self::Properties, link: ComponentLink\u003cSelf\u003e) -\u003e Self {\n    // Create model initial state\n    let model = Registration {\n        first_name: String::from(\"J-F\"),\n        last_name: String::from(\"Bilodeau\"),\n        address: Address {\n            street: String::new(),\n            city: String::from(\"Ottawa\"),\n            province: String::from(\"ONT\"),\n            postal_code: String::from(\"K2P 0A4\"),\n            country: String::new(),\n        },\n    };\n\n    Self {\n        form: Form::new(model),\n        ...\n    }\n    ...\n```\n\nFields can then be added to the form as follows:\n```html\n\u003cField\u003cRegistration\u003e \n    form=\u0026self.form \n\u003c\u003c\u003c\u003c\u003c\u003c\u003c HEAD\n    field_name=\"first_name\"\n    autocomplete=\"given-name\"\n=======\n    field_name=\"first_name\" \n\u003e\u003e\u003e\u003e\u003e\u003e\u003e 0ab668b7f3fb9ba13e1e0d4d97bee619280f3a3d\n    oninput=self.link.callback(|_: InputData| AppMessage::Update) /\u003e\n\n\u003c!-- here we use custom css classes --\u003e\n\u003cField\u003cRegistration\u003e \n    form=\u0026self.form \n    field_name=\"address.street\"\n    class=\"form-control\"\n    class_invalid=\"is-invalid red-border\"\n    class_valid=\"is-valid green-border\"\n    oninput=self.link.callback(|_: InputData| AppMessage::Update) /\u003e\n...\n\u003cCheckBox\u003cRegistration\u003e field_name=\"accept_terms\" form=\u0026self.form /\u003e\n```\nThe `Field` component takes care of two way binding between `struct Registration` and the HTML `\u003cinput\u003e`\n\nValidation is done automatically when the user edits the form or programmatically.\n\n```rust\nif self.form.validate() {\n    ...\n}\n```\n\nTodo/Wish List:\n- [ ] Add documentation (In progress)\n- [ ] ~~Remove clone requirement from model~~\n- [X] Add `derive` for model to remove need for `vec!` of fields\n- [X] Make `oninput` optional\n- [ ] Make Yew update the view when `Field` is updated\n- [ ] Need to add additional HTML attribute to `Field`\n- [X] Remove hard-coded Bootstrap styles\n- [X] Add support for additional types such as `i32`\n- [ ] Support `Vec\u003cT\u003e`\n- [X] Support Rust Stable\n\n## Change Log\n\n### 0.1.8\n- Remove hardcoded Bootstrap css classes\n- Fix `examples/form`\n- Add `autocomplete` attribute\n\n### 0.1.7\n- Remove `#![feature(get_mut_unchecked)]` from code (Thanks [L0g4n](https://github.com/L0g4n))\n\n### 0.1.6\n- Removed unsafe code\n- Updated yew_form version in documentation\n\n### 0.1.5\n- Updated to Yew 0.17\n\n### 0.1.4\n- Added blanket implementation for FieldValue to support `i32`, `bool`, etc...\n\n### 0.1.3\n**BREAKING CHANGES**\n- Added `#[derive(Model)]`\n- No need to manually pass a vector of fields to `Form::new()`\n\n### 0.1.2\n- Added CheckBox\n\n### 0.1.1\n- Make `Field::oninput` optional\n\n\n(Made with ❤️ with Rust)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfbilodeau%2Fyew_form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjfbilodeau%2Fyew_form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfbilodeau%2Fyew_form/lists"}