From aa3cbda30179fe483274abf0e357e1321e16d71f Mon Sep 17 00:00:00 2001 From: Ervin Sabic Date: Fri, 17 Jan 2025 02:35:26 -0600 Subject: [PATCH] added yielding of current form data. issue #379 + tests (#540) * 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 --- .changeset/tender-humans-return.md | 5 +++++ docs/usage/data/index.md | 4 ++++ .../src/components/headless-form.gts | 6 ++++++ test-app/app/templates/index.hbs | 5 ++++- .../components/headless-form-basic-test.gts | 17 +++++++++++++++++ 5 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 .changeset/tender-humans-return.md diff --git a/.changeset/tender-humans-return.md b/.changeset/tender-humans-return.md new file mode 100644 index 00000000..09ef7b91 --- /dev/null +++ b/.changeset/tender-humans-return.md @@ -0,0 +1,5 @@ +--- +"ember-headless-form": minor +--- + +Yield current form data as `form.data`. diff --git a/docs/usage/data/index.md b/docs/usage/data/index.md index b21fcd52..8106a740 100644 --- a/docs/usage/data/index.md +++ b/docs/usage/data/index.md @@ -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. diff --git a/packages/ember-headless-form/src/components/headless-form.gts b/packages/ember-headless-form/src/components/headless-form.gts index 1e68d8bd..04b566f2 100644 --- a/packages/ember-headless-form/src/components/headless-form.gts +++ b/packages/ember-headless-form/src/components/headless-form.gts @@ -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; } ]; }; @@ -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 diff --git a/test-app/app/templates/index.hbs b/test-app/app/templates/index.hbs index d7a5aea4..fc7c8ab0 100644 --- a/test-app/app/templates/index.hbs +++ b/test-app/app/templates/index.hbs @@ -15,7 +15,10 @@ - + {{#if form.data.firstName}} + You entered: + {{form.data.firstName}} + {{/if}}
Last name diff --git a/test-app/tests/integration/components/headless-form-basic-test.gts b/test-app/tests/integration/components/headless-form-basic-test.gts index dedeacb6..9e4a2939 100644 --- a/test-app/tests/integration/components/headless-form-basic-test.gts +++ b/test-app/tests/integration/components/headless-form-basic-test.gts @@ -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( + ) + + 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' };