Skip to content

Commit

Permalink
added yielding of current form data. issue #379 + tests (#540)
Browse files Browse the repository at this point in the history
* added yielding of current form data. #379 along with tests and updated test app

* updating documentation for usage

* using 'data' instead of 'effectiveData' to be consistent with field data yield'

* resolved typing error. however getting ELIFECYCLE error on lint

* linting passed.

* changed yielded data to not be optional

* changeset

---------

Co-authored-by: Simon Ihmig <[email protected]>
  • Loading branch information
ErvinSabic and simonihmig authored Jan 17, 2025
1 parent ad45c1a commit aa3cbda
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/tender-humans-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ember-headless-form": minor
---

Yield current form data as `form.data`.
4 changes: 4 additions & 0 deletions docs/usage/data/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ For pre-populating the form, you would need to pass an object, whose keys match

The primary way of getting the user entered data back to your application code is by letting the user submit the form. If you pass an action to `@onSubmit`, it will be called when the user submitted the form successfully (means: after passing optional [validation](../validation)). It will then receive the _changed_ data as an argument, letting you decide what should happen, i.e. how to mutate your application state.

## Displaying data in the form

For more dynamic forms, you may need to read the data as it is being modified. You can do this by accessing the form's yielded `data` property within the block. It may look something like `{{form.data.firstName}}` if we use the above form as an example.

## (Im-)mutable data

By default `@data` is immutable, i.e. the addon will only read from it. For handling the state of the _currently_ entered form data, a copy of that data is stored internally.
Expand Down
6 changes: 6 additions & 0 deletions packages/ember-headless-form/src/components/headless-form.gts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ export interface HeadlessFormComponentSignature<
* Yielded action that will reset form state, same as when triggering the native `reset` event on the form.
*/
reset: () => void;

/**
* The current form data that is yielded on the form itself and can be used within the template.
*/
data: DATA;
}
];
};
Expand Down Expand Up @@ -616,6 +621,7 @@ export default class HeadlessFormComponent<
validationState=this.validationState
submissionState=this.submissionState
isInvalid=this.hasValidationErrors
data=this.effectiveData
rawErrors=this.visibleErrors
submit=this.onSubmit
reset=this.onReset
Expand Down
5 changes: 4 additions & 1 deletion test-app/app/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
<field.Errors class='text-red-600' />
</div>
</form.Field>

{{#if form.data.firstName}}
You entered:
{{form.data.firstName}}
{{/if}}
<form.Field @name='lastName' as |field|>
<div class='my-2 flex flex-col'>
<field.Label class={{if field.isInvalid 'text-red-500'}}>Last name</field.Label>
Expand Down
17 changes: 17 additions & 0 deletions test-app/tests/integration/components/headless-form-basic-test.gts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ module('Integration Component HeadlessForm > Basics', function (hooks) {
);
});

test('form effective data renders correctly', async function (this: RenderingTestContext, assert) {
const data = { firstName: 'Hank'};

await render(
<template>
<HeadlessForm @data={{data}} as |form|>
<div data-test-effective-data>
{{form.data.firstName}}
</div>
</HeadlessForm>
</template>)

const testName = (this.element.querySelector("div[data-test-effective-data]") as HTMLElement).innerText;

assert.strictEqual(testName, data.firstName, "effective data within form matches given");
})

module('form.Field', function () {
test('form yields field component', async function (assert) {
const data = { firstName: 'Simon' };
Expand Down

0 comments on commit aa3cbda

Please sign in to comment.