@@ -1395,6 +1395,123 @@ def form_config
13951395
13961396 end
13971397
1398+ describe "supports addition of nested forms/models on top of EXISTING instances" do
1399+
1400+ before do
1401+ @dummy_model = DummyModel . create ( title : "existing-dummy-model-title" )
1402+
1403+ class ExamplePage < Matestack ::Ui ::Page
1404+
1405+ def prepare
1406+ @dummy_model = DummyModel . last
1407+ end
1408+
1409+ def response
1410+ matestack_form form_config do
1411+ form_input key : :title , type : :text , label : "dummy_model_title_input" , id : "dummy_model_title_input"
1412+
1413+ @dummy_model . dummy_child_models . each do |dummy_child_model |
1414+ dummy_child_model_form dummy_child_model
1415+ end
1416+
1417+ form_fields_for_add_item key : :dummy_child_models_attributes , prototype : method ( :dummy_child_model_form ) do
1418+ button "add" , type : :button # type: :button is important! otherwise remove on first item is triggered on enter
1419+ end
1420+
1421+ br
1422+ plain "data: {{data}}"
1423+ br
1424+
1425+ button "Submit me!"
1426+
1427+ toggle show_on : "success" , hide_after : 1000 do
1428+ plain "success!"
1429+ end
1430+ toggle show_on : "failure" , hide_after : 1000 do
1431+ plain "failure!"
1432+ end
1433+ end
1434+ end
1435+
1436+ def dummy_child_model_form dummy_child_model = DummyChildModel . new ( title : "init-value" )
1437+ form_fields_for dummy_child_model , key : :dummy_child_models_attributes do
1438+ form_input key : :title , type : :text , label : "dummy-child-model-title-input"
1439+ form_fields_for_remove_item do
1440+ button "remove" , ":id" : "'remove'+nestedFormRuntimeId" , type : :button # id is just required in this spec, but type: :button is important! otherwise remove on first item is triggered on enter
1441+ end
1442+ end
1443+ end
1444+
1445+ def form_config
1446+ {
1447+ for : @dummy_model ,
1448+ method : :put ,
1449+ path : nested_forms_spec_submit_update_path ( id : @dummy_model . id ) ,
1450+ success : { emit : "success" } ,
1451+ failure : { emit : "failure" }
1452+ }
1453+ end
1454+ end
1455+ end
1456+
1457+ it "dynamically adds unlimited new nested forms and enable proper clientside data binding" do
1458+
1459+ visit "/example"
1460+ # sleep
1461+ expect ( page ) . to have_selector ( '#dummy_model_title_input' )
1462+ expect ( page ) . not_to have_selector ( '#title_dummy_child_models_attributes_child_0' )
1463+ expect ( page ) . not_to have_selector ( '#title_dummy_child_models_attributes_child_1' )
1464+
1465+ expect ( page ) . to have_content ( 'data: { "title": "existing-dummy-model-title" }' )
1466+
1467+ click_on "add"
1468+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_0' )
1469+
1470+ expect ( page ) . to have_content ( 'data: { "title": "existing-dummy-model-title", "dummy_child_models_attributes": [ { "_destroy": false, "id": null, "title": "init-value" } ] }' )
1471+
1472+ click_on "add"
1473+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_1' )
1474+
1475+ expect ( page ) . to have_content ( 'data: { "title": "existing-dummy-model-title", "dummy_child_models_attributes": [ { "_destroy": false, "id": null, "title": "init-value" }, { "_destroy": false, "id": null, "title": "init-value" } ] }' )
1476+
1477+ fill_in "title_dummy_child_models_attributes_child_1" , with : "new-value"
1478+
1479+ expect ( page ) . to have_content ( 'data: { "title": "existing-dummy-model-title", "dummy_child_models_attributes": [ { "_destroy": false, "id": null, "title": "init-value" }, { "_destroy": false, "id": null, "title": "new-value" } ] }' )
1480+
1481+ click_on ( "remove_dummy_child_models_attributes_child_0" )
1482+
1483+ expect ( page ) . to have_content ( 'data: { "title": "existing-dummy-model-title", "dummy_child_models_attributes": [ { "_destroy": true, "id": null, "title": "init-value" }, { "_destroy": false, "id": null, "title": "new-value" } ] }' )
1484+ end
1485+
1486+ it "dynamically adds unlimited new nested forms and enable proper clientside data binding with initially present child models" do
1487+
1488+ dummy_model = DummyModel . last
1489+ child_model_0 = dummy_model . dummy_child_models . create ( title : "existing-child-model-title" )
1490+
1491+ visit "/example"
1492+ # sleep
1493+ expect ( page ) . to have_selector ( '#dummy_model_title_input' )
1494+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_0' )
1495+ expect ( page ) . not_to have_selector ( '#title_dummy_child_models_attributes_child_1' )
1496+
1497+ expect ( page ) . to have_content ( "data: { \" dummy_child_models_attributes\" : [ { \" _destroy\" : false, \" id\" : \" #{ child_model_0 . id } \" , \" title\" : \" existing-child-model-title\" } ], \" title\" : \" existing-dummy-model-title\" }" )
1498+
1499+ click_on "add"
1500+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_1' )
1501+
1502+ expect ( page ) . to have_content ( "data: { \" dummy_child_models_attributes\" : [ { \" _destroy\" : false, \" id\" : \" #{ child_model_0 . id } \" , \" title\" : \" existing-child-model-title\" }, { \" _destroy\" : false, \" id\" : null, \" title\" : \" init-value\" } ], \" title\" : \" existing-dummy-model-title\" }" )
1503+
1504+ fill_in "title_dummy_child_models_attributes_child_1" , with : "new-value"
1505+
1506+ expect ( page ) . to have_content ( "data: { \" dummy_child_models_attributes\" : [ { \" _destroy\" : false, \" id\" : \" #{ child_model_0 . id } \" , \" title\" : \" existing-child-model-title\" }, { \" _destroy\" : false, \" id\" : null, \" title\" : \" new-value\" } ], \" title\" : \" existing-dummy-model-title\" }" )
1507+
1508+ click_on ( "remove_dummy_child_models_attributes_child_0" )
1509+
1510+ expect ( page ) . to have_content ( "data: { \" dummy_child_models_attributes\" : [ { \" _destroy\" : true, \" id\" : \" #{ child_model_0 . id } \" , \" title\" : \" existing-child-model-title\" }, { \" _destroy\" : false, \" id\" : null, \" title\" : \" new-value\" } ], \" title\" : \" existing-dummy-model-title\" }" )
1511+ end
1512+
1513+ end
1514+
13981515 end
13991516
14001517end
0 commit comments