Skip to content

Commit 338104b

Browse files
Merge pull request #283 from basemate/fixing_issue_139
added follow_response option for form transitions
2 parents 9bf3c53 + 8262054 commit 338104b

File tree

5 files changed

+187
-67
lines changed

5 files changed

+187
-67
lines changed

app/concepts/matestack/ui/core/form/form.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,27 @@ const componentDef = {
104104
if (self.componentConfig["success"] != undefined && self.componentConfig["success"]["emit"] != undefined) {
105105
matestackEventHub.$emit(self.componentConfig["success"]["emit"], response.data);
106106
}
107-
if (self.componentConfig["success"] != undefined && self.componentConfig["success"]["transition"] != undefined && self.$store != undefined) {
107+
if (self.componentConfig["success"] != undefined
108+
&& self.componentConfig["success"]["transition"] != undefined
109+
&& (
110+
self.componentConfig["success"]["transition"]["follow_response"] == undefined
111+
||
112+
self.componentConfig["success"]["transition"]["follow_response"] === false
113+
)
114+
&& self.$store != undefined
115+
) {
108116
let path = self.componentConfig["success"]["transition"]["path"]
109117
self.$store.dispatch('navigateTo', {url: path, backwards: false})
118+
return;
119+
}
120+
if (self.componentConfig["success"] != undefined
121+
&& self.componentConfig["success"]["transition"] != undefined
122+
&& self.componentConfig["success"]["transition"]["follow_response"] === true
123+
&& self.$store != undefined
124+
) {
125+
let path = response.data["transition_to"]
126+
self.$store.dispatch('navigateTo', {url: path, backwards: false})
127+
return;
110128
}
111129
self.setProps(self.data, null);
112130
self.initValues()

docs/components/form.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,49 @@ We then get displayed our nice success message (`server says: form submitted suc
275275

276276
If we fill in the the input field there and hit the submit button, we not only see the failure messages (`server says: form had errors` and `'foo': [ 'seems to be invalid' ]`), we also get transferred back to the first page, just the way we specified this behavior in the page definition above!
277277

278+
### Example 3.1: Async submit request with success transition - dynamically determined by server
279+
280+
In the example shown above, the `success` `transition` is statically defined. Sometimes the `transition` needs to be dynamically controlled within the server action.
281+
Imagine creating a new Active Record instance with a `form`. If you want to show the fresh instance on another page and therefore want to define a `transition` after successful form submission, you would need to know the ID of the fresh instance! That is not possible, as the ID is auto-generated and depends on the current environment/state. Therefore you can tell the `form` component to follow a transition, which the server action defines after creating the new instance (and now knowing the ID):
282+
283+
On the `page`:
284+
```ruby
285+
#...
286+
287+
def form_config
288+
return {
289+
for: :my_object,
290+
method: :post,
291+
path: :success_form_test_path,
292+
success: {
293+
emit: 'my_form_success',
294+
transition: {
295+
follow_response: true # follow the serverside transition
296+
}
297+
}
298+
}
299+
end
300+
```
301+
On the `controller` `action`:
302+
303+
```ruby
304+
#...
305+
def model_submit
306+
@test_model = TestModel.create(model_params)
307+
if @test_model.errors.any?
308+
render json: {
309+
message: 'server says: something went wrong!',
310+
errors: @test_model.errors
311+
}, status: :unproccessable_entity
312+
else
313+
render json: {
314+
message: 'server says: form submitted successfully!',
315+
transition_to: some_other_path(id: @test_model.id) #tell the form component where to transition to with the id, which was not available before
316+
}, status: :ok
317+
end
318+
end
319+
```
320+
278321
### Example 4: Multiple input fields of different types
279322

280323
Of course, our input core component accepts not only 'text', but very different input types: In this example, we will introduce 'password', 'number', 'email', 'textarea' types!

spec/usage/components/form_spec.rb

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ def success_submit
2424
render json: { message: "server says: form submitted successfully" }, status: 200
2525
end
2626

27+
def success_submit_with_transition
28+
render json: {
29+
message: "server says: form submitted successfully",
30+
transition_to: form_test_page_4_path(id: 42)
31+
}, status: 200
32+
end
33+
2734
def failure_submit
2835
render json: {
2936
message: "server says: form had errors",
@@ -35,6 +42,7 @@ def failure_submit
3542

3643
Rails.application.routes.append do
3744
post '/success_form_test/:id', to: 'form_test#success_submit', as: 'success_form_test'
45+
post '/success_form_test_with_transition/:id', to: 'form_test#success_submit_with_transition', as: 'success_form_test_with_transition'
3846
post '/failure_form_test/:id', to: 'form_test#failure_submit', as: 'failure_form_test'
3947
end
4048
Rails.application.reload_routes!
@@ -376,6 +384,108 @@ def page2
376384

377385
end
378386

387+
it "Example 5 - Async submit request with success transition determined by server response" do
388+
class Apps::ExampleApp < Matestack::Ui::App
389+
390+
def response
391+
components {
392+
heading size: 1, text: "My Example App Layout"
393+
main do
394+
page_content
395+
end
396+
async show_on: "my_form_success", hide_after: 300 do
397+
plain "{{event.data.message}}"
398+
end
399+
async show_on: "my_form_failure", hide_after: 300 do
400+
plain "{{event.data.message}}"
401+
plain "{{event.data.errors}}"
402+
end
403+
}
404+
end
405+
406+
end
407+
408+
module Pages::ExampleApp
409+
410+
end
411+
412+
class Pages::ExampleApp::ExamplePage3 < Matestack::Ui::Page
413+
414+
def response
415+
components {
416+
heading size: 2, text: "This is Page 3"
417+
form form_config, :include do
418+
form_input id: "my-test-input-on-page-3", key: :foo, type: :text
419+
form_submit do
420+
button text: "Submit me!"
421+
end
422+
end
423+
}
424+
end
425+
426+
def form_config
427+
return {
428+
for: :my_object,
429+
method: :post,
430+
path: :success_form_test_with_transition_path,
431+
params: {
432+
id: 42
433+
},
434+
success: {
435+
emit: "my_form_success",
436+
transition: {
437+
follow_response: true
438+
}
439+
}
440+
}
441+
end
442+
443+
end
444+
445+
class Pages::ExampleApp::ExamplePage4 < Matestack::Ui::Page
446+
447+
def response
448+
components {
449+
heading size: 2, text: "This is Page 4"
450+
}
451+
end
452+
453+
end
454+
455+
class ExampleAppPagesController < ExampleController
456+
include Matestack::Ui::Core::ApplicationHelper
457+
458+
def page3
459+
responder_for(Pages::ExampleApp::ExamplePage3)
460+
end
461+
462+
def page4
463+
responder_for(Pages::ExampleApp::ExamplePage4)
464+
end
465+
466+
end
467+
468+
Rails.application.routes.append do
469+
scope :form_test do
470+
get 'page3', to: 'example_app_pages#page3', as: 'form_test_page_3'
471+
get 'page4/:id', to: 'example_app_pages#page4', as: 'form_test_page_4'
472+
end
473+
end
474+
Rails.application.reload_routes!
475+
476+
visit "form_test/page3"
477+
478+
expect(page).to have_content("This is Page 3")
479+
480+
fill_in "my-test-input-on-page-3", with: "bar"
481+
click_button "Submit me!"
482+
483+
expect(page).to have_content("server says: form submitted successfully")
484+
485+
expect(page).to have_content("This is Page 4")
486+
487+
end
488+
379489
describe "Form Input Component" do
380490

381491
it "Example 1 - Supports 'text', 'password', 'number', 'email', 'textarea' type" do

vendor/assets/javascripts/matestack-ui-core.js

Lines changed: 14 additions & 65 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/assets/javascripts/matestack-ui-core.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)