{"id":30222820,"url":"https://github.com/coolsamson7/velix","last_synced_at":"2025-08-14T11:10:19.413Z","repository":{"id":309357798,"uuid":"1035969763","full_name":"coolsamson7/velix","owner":"coolsamson7","description":"flutter foundation library","archived":false,"fork":false,"pushed_at":"2025-08-11T12:56:07.000Z","size":67,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-11T13:13:33.711Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coolsamson7.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-11T11:15:11.000Z","updated_at":"2025-08-11T12:56:10.000Z","dependencies_parsed_at":"2025-08-11T13:14:40.553Z","dependency_job_id":"9495defc-0243-4a91-9465-08041e1615c9","html_url":"https://github.com/coolsamson7/velix","commit_stats":null,"previous_names":["coolsamson7/velix"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/coolsamson7/velix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fvelix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fvelix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fvelix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fvelix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coolsamson7","download_url":"https://codeload.github.com/coolsamson7/velix/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fvelix/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270323289,"owners_count":24564664,"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","status":"online","status_checked_at":"2025-08-13T02:00:09.904Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2025-08-14T11:10:14.103Z","updated_at":"2025-08-14T11:10:19.304Z","avatar_url":"https://github.com/coolsamson7.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n![License](https://img.shields.io/github/license/coolsamson7/velix)\n![Dart](https://img.shields.io/badge/Dart-3.0-blue)\n[![Docs](https://img.shields.io/badge/docs-online-blue?logo=github)](https://coolsamson7.github.io/velix/)\n[![Flutter CI](https://github.com/coolsamson7/velix/actions/workflows/flutter.yaml/badge.svg)](https://github.com/coolsamson7/velix/actions/workflows/flutter.yaml)\n\n\n \n \u003cimg width=\"1536\" height=\"1024\" alt=\"Futuristische Flutter App Arbeitsumgebung\" src=\"https://github.com/user-attachments/assets/e746b067-5fc1-464b-a16c-c9c9251698a4\" /\u003e\n \n # Model-driven forms for Flutter\n\nVelix is a dart / flutter based library that vastly simplifies data binding and validation in forms.\n\n# Motivation\n\nLooking at the effort required in Flutter to handle even simple forms i was shocked and started looking for \nalternatives that gave my about the same level of verbosity or productivity as i have known for example in Angular.\n\nWhile there are some form related libraries, they all skip the problem of binding widgets to values automatically, so i started my own\nlibrary reusing ideas, that i have known for at least 20 years :-)\nStarting with the form binding quickly other solutions where integrated as well, that simplify development. \n\n# Solution idea\n\nThe idea is a model based declarative approach, that utilizes\n- reflection information with respect to the bound classes and fields\n- including type constraints on field level\n- in combination with technical adapters that handle specific widgets and do the internal dirty work.\n\nAs a result, all the typical boilerplate code is completely gone, resulting in a fraction of necessary code.\n\n# Example\n\nLet's look at a simple form example first.\n\nBoth the reflection and validation information is covered by specific decorators:\n\n```dart\n@Dataclass()\nclass Address {\n  // instance data\n\n  @Attribute(type: \"length 100\")\n  final String city;\n  @Attribute(type: \"length 100\")\n  final String street;\n  \n  // constructor\n\n  Address({required this.city, required this.street});\n}\n\n@Dataclass()\nclass Person {\n  // instance data\n\n  @Attribute(type: \"length 100\")\n  String firstName;\n  @Attribute(type: \"length 100\")\n  String lastName;\n  @Attribute(type: \"\u003e= 0\")\n  int age;\n  @Attribute()\n  Address address;\n}\n```\n\nInside the state of the form page, we can bind values easily\n\n\n```dart\nclass PersonFormPageState extends State\u003cPersonFormPage\u003e {\n  // instance data\n\n  late FormMapper mapper;\n  \n  // override\n\n  @override\n  void initState() {\n    super.initState();\n\n    mapper = FormMapper(instance: widget.person, twoWay: true);\n\n    mapper.isDirty.addListener(() {\n      setState(() {\n      });\n    });\n  }\n\n  @override\n  void dispose() {\n    super.dispose();\n\n    mapper.dispose();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n\n    Widget result = Form(\n      autovalidateMode: AutovalidateMode.onUserInteraction,\n      key: mapper.getKey(),\n      ...\n      mapper.bind(CupertinoTextFormFieldRow, path: \"firstName\", context: context, args: {\"placeholder\": 'First Name'}), \n      mapper.bind(CupertinoTextFormFieldRow, path: \"lastName\", context: context, args: {\"placeholder\": 'Last Name'}),\n      mapper.bind(CupertinoTextFormFieldRow, path: \"age\", context: context, args: {\"placeholder\": 'Age'}),\n      mapper.bind(CupertinoTextFormFieldRow, path: \"address.city\", context: context, args: {\"placeholder\": 'City'}),\n      mapper.bind(CupertinoTextFormFieldRow, path: \"address.street\", context: context, args: {\"placeholder\": 'Street'}),\n    );\n\n    // set initial value\n\n    mapper.setValue(widget.person);\n\n    // done\n\n    return result;\n  }\n} \n```\n\nYou can already see some highlights:\n- automatic handling of type validation ( e.g. length constraints ) and generation of error messages\n- automatic coercion of types ( e.g. \"age\" bound to a test field )\n- handling of paths ( \"address.city\" ) including the necessary reconstruction of immutable classes ( with final fields )\n- two-way data-binding, if requested\n\nTwo-way databinding will modify the underlying model immediately after every change in a associated widget.\nIf disabled, you would have to explicitly call `form.getValue()` to retrieve the updated model. The additional benefit you\nwould gain here is that the form mapper remembers the initial values and will change its `dirty` state accordingly, which means that \na reverted change will bring the form back to a non-dirty state!\n\n\n# Benefits\nVelix drastically reduces the manual wiring and repetitive boilerplate that normally comes with Flutter forms.\nWith it, you get:\n\n- No manual controllers – Forget TextEditingController, FocusNode, and onChanged spaghetti for every single field.\n\n- Type-aware validation out of the box – Your @Attribute metadata drives validation rules automatically, without repeating them in the UI layer.\n\n- Immutable model support – Handles reconstruction of immutable (final) classes automatically when updating nested fields.\n\n- Two-way binding – Keep your widgets and model in sync without extra glue code; or opt for one-way binding with explicit getValue() retrieval.\n\n- Path-based binding – Easily bind deeply nested fields (address.city) without manually drilling down in your widget code.\n\n- Automatic dirty-state tracking – Know instantly if a form has unsaved changes and when it has been reverted to its original state.\n\n- Minimal code footprint – Complex forms can be expressed in a fraction of the lines you’d normally need.\n\n# Comparison to Existing Flutter Solutions\n\nWhile Flutter has some established form libraries like\nflutter_form_builder and reactive_forms, they still expect you to:\n\n- Define FormControl or TextEditingController instances manually\n\n- Wire each widget to its controller or form control\n\n- Duplicate validation rules across model and UI layers\n\n- Write boilerplate for converting between text and typed fields\n\nVelix takes a different route:\n\n- Model-driven – The form is generated from your annotated model, not from widget-level configuration.\n\n- Automatic widget adapters – You don’t manually connect a controller; you just tell Velix which property to bind.\n\n- Unified validation \u0026 transformation – Rules live once, in the model, and apply everywhere.\n\n- Nested object awareness – Works with object graphs, not just flat maps of fields.\n\nThe result is a WPF/Angular-style binding experience in Flutter — something currently missing from the ecosystem.\n\n# Installation\n\nThe library is hosted on Github ( https://github.com/coolsamson7/velix )\n\nand published on pub.dev (https://pub.dev/packages/velix )\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolsamson7%2Fvelix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoolsamson7%2Fvelix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolsamson7%2Fvelix/lists"}