@@ -1513,6 +1513,125 @@ def form_config
15131513
15141514 end
15151515
1516+ describe "supports custom form input components on dynamically added child forms" do
1517+
1518+ before do
1519+ @dummy_model = DummyModel . create ( title : "existing-dummy-model-title" )
1520+
1521+ class Components ::CustomFormInputTest < Matestack ::Ui ::VueJs ::Components ::Form ::Input
1522+ vue_name "custom-form-input-test" # defined in app/spec/dummy/javascript/components.js
1523+
1524+ def response
1525+ div class : "custom-input-markup" do
1526+ label "my form input"
1527+ span ":id" : "'input_uid'+vc.$parent.nestedFormRuntimeId" do
1528+ plain "UID: {{ vc.props['component_uid'] }}"
1529+ end
1530+ input input_attributes
1531+ button "change value" , "@click" : "vc.changeValueViaJs(42)" , type : :button
1532+ render_errors
1533+ end
1534+ end
1535+
1536+ register_self_as ( :custom_form_input_test )
1537+ end
1538+
1539+ class ExamplePage < Matestack ::Ui ::Page
1540+
1541+ def prepare
1542+ @dummy_model = DummyModel . last
1543+ end
1544+
1545+ def response
1546+ matestack_form form_config do
1547+ form_input key : :title , type : :text , label : "dummy_model_title_input" , id : "dummy_model_title_input"
1548+
1549+ @dummy_model . dummy_child_models . each do |dummy_child_model |
1550+ dummy_child_model_form dummy_child_model
1551+ end
1552+
1553+ form_fields_for_add_item key : :dummy_child_models_attributes , prototype : method ( :dummy_child_model_form ) do
1554+ button "add" , type : :button # type: :button is important! otherwise remove on first item is triggered on enter
1555+ end
1556+
1557+ br
1558+ plain "data: {{vc.data}}"
1559+ br
1560+
1561+ button "Submit me!"
1562+
1563+ toggle show_on : "success" , hide_after : 1000 do
1564+ plain "success!"
1565+ end
1566+ toggle show_on : "failure" , hide_after : 1000 do
1567+ plain "failure!"
1568+ end
1569+ end
1570+ end
1571+
1572+ def dummy_child_model_form dummy_child_model = DummyChildModel . new ( title : "init-value" )
1573+ form_fields_for dummy_child_model , key : :dummy_child_models_attributes do
1574+ span ":id" : "'uid'+vc.nestedFormRuntimeId" do
1575+ plain "UID: {{ vc.props['component_uid'] }}"
1576+ end
1577+ form_input key : :title , type : :text , label : "dummy-child-model-title-input"
1578+ custom_form_input_test key : :bar , type : :text , id : "bar"
1579+ form_fields_for_remove_item do
1580+ button "remove" , ":id" : "'remove'+vc.nestedFormRuntimeId" , type : :button # id is just required in this spec, but type: :button is important! otherwise remove on first item is triggered on enter
1581+ end
1582+ end
1583+ end
1584+
1585+ def form_config
1586+ {
1587+ for : @dummy_model ,
1588+ method : :put ,
1589+ path : nested_forms_spec_submit_update_path ( id : @dummy_model . id ) ,
1590+ success : { emit : "success" } ,
1591+ failure : { emit : "failure" }
1592+ }
1593+ end
1594+ end
1595+ end
1596+
1597+ it "dynamically adds unlimited new nested forms with different UIDs enabling proper getElement() usage when working with child form DOM" do
1598+ # relevant form form input components accessing their child form DOM via UID
1599+
1600+ dummy_model = DummyModel . last
1601+ child_model_0 = dummy_model . dummy_child_models . create ( title : "existing-child-model-title" )
1602+
1603+ visit "/example"
1604+ # sleep
1605+ uids = [ ]
1606+ expect ( page ) . to have_selector ( '#dummy_model_title_input' )
1607+ expect ( page ) . to have_selector ( '#title_dummy_child_models_attributes_child_0' )
1608+ within "#dummy_child_models_attributes_child_0" do
1609+ uids << page . find_by_id ( "uid_dummy_child_models_attributes_child_0" )
1610+ uids << page . find_by_id ( "input_uid_dummy_child_models_attributes_child_0" )
1611+ end
1612+ expect ( page ) . to have_xpath ( '//matestack-component-template[@id="dummy_child_models_attributes_child_0"]//div[@class="custom-input-markup"]/input[@id="bar" and @class="js-added-class"]' )
1613+ click_on "add"
1614+ within "#dummy_child_models_attributes_child_1" do
1615+ uids << page . find_by_id ( "uid_dummy_child_models_attributes_child_1" )
1616+ uids << page . find_by_id ( "input_uid_dummy_child_models_attributes_child_1" )
1617+ click_on "change value"
1618+ end
1619+ expect ( page ) . to have_xpath ( '//div[@class="matestack-form-fields-for" and @id="dummy_child_models_attributes_child_1"]//div[@class="custom-input-markup"]/input[@id="bar" and @class="js-added-class"]' )
1620+ click_on "add"
1621+ within "#dummy_child_models_attributes_child_2" do
1622+ uids << page . find_by_id ( "uid_dummy_child_models_attributes_child_2" )
1623+ uids << page . find_by_id ( "input_uid_dummy_child_models_attributes_child_2" )
1624+ end
1625+ expect ( page ) . to have_xpath ( '//div[@class="matestack-form-fields-for" and @id="dummy_child_models_attributes_child_2"]//div[@class="custom-input-markup"]/input[@id="bar" and @class="js-added-class"]' )
1626+
1627+ expect ( uids . count ) . to eq ( uids . uniq . count )
1628+
1629+ expect ( page ) . to have_content ( "data: { \" dummy_child_models_attributes\" : [ { \" _destroy\" : false, \" id\" : \" #{ child_model_0 . id } \" , \" title\" : \" existing-child-model-title\" , \" bar\" : null }, { \" _destroy\" : false, \" id\" : null, \" title\" : \" init-value\" , \" bar\" : 42 }, { \" _destroy\" : false, \" id\" : null, \" title\" : \" init-value\" , \" bar\" : null } ], \" title\" : \" existing-dummy-model-title\" }" )
1630+
1631+ end
1632+
1633+ end
1634+
15161635 end
15171636
15181637end
0 commit comments