You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by "Adam Zimowski (JIRA)" <ji...@apache.org> on 2011/04/26 15:04:03 UTC

[jira] [Created] (TAP5-1512) Select update via zone inside a form confuses form's ValidationTracker

Select update via zone inside a form confuses form's ValidationTracker
----------------------------------------------------------------------

                 Key: TAP5-1512
                 URL: https://issues.apache.org/jira/browse/TAP5-1512
             Project: Tapestry 5
          Issue Type: Bug
          Components: tapestry-core, tapestry-ioc
    Affects Versions: 5.2.5
            Reporter: Adam Zimowski
            Priority: Minor


Here is the use case:

We have a simple address form with Line 1, Line 2, City (all text fields), State (Select), Zip (Text Field) and Country (Select). State select is wrapped inside a Zone, which is tied to Country select, so that when country is selected, states get populated. Line 1, City, State, Zip and Country are all required. Form uses <t:error/> next to each field.

Here is the problem:

1. Select country and state (both have blank options therefore are required), but leave other fields empty.
2. Submit form. Validation on required fields (such as city, zip) results in form rendering error messages. Note: Country and State are
not in error at this point.
3. While correcting errors on the form, change country. As a result, state select component is repopulated (zone update), and default blank
option is select. Do not chose state.
4. Submit form with state *not* selected. Debugging select shows that ValidationTracker contains error (state required), yet attached field error is not displaying the error.

Upon debugging the framework I found the following:

IdAllocator used to generate component id, suffixes select with an increment even select is not inside a loop. It does this ONLY when Zone is updated, causing the very subsequent form submit record error for select under wrong key (a_state_1 rather than state), and so the <t:error/> is unable to locate the error when form eventually renders back with original select id (a_state).

In this case, what happens is that every time I update zone while form is in error, the ID of my select changes with incremented suffix:

ORIGINAL AS EXPECTED BY FORM: a_state

After resetting country causing state dropdown to repopulate, id becomes: 

a_state_1 then a_state_2 etc...

This causes ValidationTracker put error under wrong key, and consequently error to field binding in tracker's map cannot be
resolved, causing <t:error/> thinking that all is good. That's why <t:errors/> does display the error, as it simply loops over collection
of errors.

Out of lack of deep understanding of Tapestry, I coded a simple hack to verify that if select update via zone kept its original id things
would work, and indeed, the following hack fixes the problem for my case:

Tapestry 5.2.5, AbstractField line 183:

   private void setupControlName(String controlName)
   {
       if(controlName.startsWith("a_state"))
               this.controlName = "a_state";
       else
               this.controlName = controlName;
   }

Here is my source:

<t:form t:id="registrationForm">
<div class="kk-hdr">Address Information</div>
 <div class="kk-row">
 <div class="kk-label"><t:label for="a_line1"/> :</div>
 <div class="kk-field"><t:textfield t:id="a_line1" value="address.line1"/></div>
 <t:error class="literal:kk-error" for="a_line1"/>
 </div>
 <div class="kk-row">
 <div class="kk-label"><t:label for="a_line2"/> :</div>
 <div class="kk-field"><t:textfield t:id="a_line2" value="address.line2"/></div>
 <t:error class="literal:kk-error" for="a_line2"/>
 </div>
 <div class="kk-row">
 <div class="kk-label"><t:label for="a_line3"/> :</div>
 <div class="kk-field"><t:textfield t:id="a_line3" value="address.line3"/></div>
 <t:error class="literal:kk-error" for="a_line3"/>
 </div>
 <div class="kk-row">
 <div class="kk-label"><t:label for="a_city"/> :</div>
 <div class="kk-field"><t:textfield t:id="a_city" value="address.city"/></div>
 <t:error class="literal:kk-error" for="a_city"/>
 </div>
 <div class="kk-row">
 <div class="kk-label"><t:label for="a_zip"/> :</div>
 <div class="kk-field"><t:textfield t:id="a_zip" value="address.zipCode"/></div>
 <t:error class="literal:kk-error" for="a_zip"/>
 </div>
 <div class="kk-row">
 <div class="kk-label"><t:label for="a_state"/> :</div>
 <div class="kk-field" t:type="zone" t:id="stateModelZone"><t:select
t:id="a_state" model="stateModel" validate="required"
value="address.stateCode" blankOption="ALWAYS"
blankLabel="literal:--Please Select"/></div>
 <t:error class="literal:kk-error" for="a_state"/>
 </div>
 <div class="kk-row">
 <div class="kk-label"><t:label for="a_country"/> :</div>
 <div class="kk-field"><t:select t:id="a_country" model="countryModel"
value="address.countryCode" blankOption="NEVER"
zone="stateModelZone"/></div>
 </div>
 <p>
 <input t:type="submit" value="message:submit-label"/>
 </p>
</t:form>

public class Register extends BasePage {

       @Inject
       private Logger log;

       @Inject
       private UtilityServiceRemote utilityService;

       @Persist
       @Property
       private AddressUiBean address;

       @OnEvent(value=EventConstants.PREPARE)
       void initialize() {
               if(address == null) address = new AddressUiBean();
               if(contact == null) contact = new ContactUiBean();
               if(registration == null) registration = new RegisterUiBean();

               String countryCode = address.getCountryCode();
               if(countryCode == null) {
                       Locale locale = getLocale();
                       countryCode = locale.getCountry();
                       address.setCountryCode(countryCode);
               }

               log.debug("address state code {}", address.getStateCode());
       }

       @Cached
       public Map<String, String> getCountryModel() {
               Map<String, String> model = new LinkedHashMap<String, String>();
               List<CountryBean> countries =
                       utilityService.getAllCountries(getLocale());
               for(CountryBean country : countries) {
                       String code = country.getCodeIsoAlpha2();
                       String description = country.getShortName();
                       log.debug("code: {}, description: {}", code, description);
                       model.put(code, description);
               }
               return model;
       }

       @OnEvent(value=EventConstants.VALUE_CHANGED, component="a_country")
       public Object onCountrySelected(String aCountryCode) {
               log.debug("selected country: {}", aCountryCode);
               address.setStateCode(null);
               return stateModelZone.getBody();
       }

       @Cached
       public Map<String, String> getStateModel() {
               Map<String, String> model = new LinkedHashMap<String, String>();
               String countryCode = address.getCountryCode();
               List<StateProvinceBean> states =
                       utilityService.getAllStateProvincesForCountry(countryCode, getLocale());
               for(StateProvinceBean state : states) {
                       String code = state.getLookupCode();
                       String name = state.getLongName();
                       log.debug("code: {}, name {}", code, name);
                       model.put(code, name);
               }
               return model;
       }
}

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

[jira] [Commented] (TAP5-1512) Select update via zone inside a form confuses form's ValidationTracker

Posted by "Adam Zimowski (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/TAP5-1512?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13025263#comment-13025263 ] 

Adam Zimowski commented on TAP5-1512:
-------------------------------------

Complete Thread: http://tapestry.1045711.n5.nabble.com/T5-select-zone-update-in-a-form-tp4314488p4314488.html

> Select update via zone inside a form confuses form's ValidationTracker
> ----------------------------------------------------------------------
>
>                 Key: TAP5-1512
>                 URL: https://issues.apache.org/jira/browse/TAP5-1512
>             Project: Tapestry 5
>          Issue Type: Bug
>          Components: tapestry-core, tapestry-ioc
>    Affects Versions: 5.2.5
>            Reporter: Adam Zimowski
>            Priority: Minor
>
> Here is the use case:
> We have a simple address form with Line 1, Line 2, City (all text fields), State (Select), Zip (Text Field) and Country (Select). State select is wrapped inside a Zone, which is tied to Country select, so that when country is selected, states get populated. Line 1, City, State, Zip and Country are all required. Form uses <t:error/> next to each field.
> Here is the problem:
> 1. Select country and state (both have blank options therefore are required), but leave other fields empty.
> 2. Submit form. Validation on required fields (such as city, zip) results in form rendering error messages. Note: Country and State are
> not in error at this point.
> 3. While correcting errors on the form, change country. As a result, state select component is repopulated (zone update), and default blank
> option is select. Do not chose state.
> 4. Submit form with state *not* selected. Debugging select shows that ValidationTracker contains error (state required), yet attached field error is not displaying the error.
> Upon debugging the framework I found the following:
> IdAllocator used to generate component id, suffixes select with an increment even select is not inside a loop. It does this ONLY when Zone is updated, causing the very subsequent form submit record error for select under wrong key (a_state_1 rather than state), and so the <t:error/> is unable to locate the error when form eventually renders back with original select id (a_state).
> In this case, what happens is that every time I update zone while form is in error, the ID of my select changes with incremented suffix:
> ORIGINAL AS EXPECTED BY FORM: a_state
> After resetting country causing state dropdown to repopulate, id becomes: 
> a_state_1 then a_state_2 etc...
> This causes ValidationTracker put error under wrong key, and consequently error to field binding in tracker's map cannot be
> resolved, causing <t:error/> thinking that all is good. That's why <t:errors/> does display the error, as it simply loops over collection
> of errors.
> Out of lack of deep understanding of Tapestry, I coded a simple hack to verify that if select update via zone kept its original id things
> would work, and indeed, the following hack fixes the problem for my case:
> Tapestry 5.2.5, AbstractField line 183:
>    private void setupControlName(String controlName)
>    {
>        if(controlName.startsWith("a_state"))
>                this.controlName = "a_state";
>        else
>                this.controlName = controlName;
>    }
> Here is my source:
> <t:form t:id="registrationForm">
> <div class="kk-hdr">Address Information</div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line1"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line1" value="address.line1"/></div>
>  <t:error class="literal:kk-error" for="a_line1"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line2"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line2" value="address.line2"/></div>
>  <t:error class="literal:kk-error" for="a_line2"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line3"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line3" value="address.line3"/></div>
>  <t:error class="literal:kk-error" for="a_line3"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_city"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_city" value="address.city"/></div>
>  <t:error class="literal:kk-error" for="a_city"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_zip"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_zip" value="address.zipCode"/></div>
>  <t:error class="literal:kk-error" for="a_zip"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_state"/> :</div>
>  <div class="kk-field" t:type="zone" t:id="stateModelZone"><t:select
> t:id="a_state" model="stateModel" validate="required"
> value="address.stateCode" blankOption="ALWAYS"
> blankLabel="literal:--Please Select"/></div>
>  <t:error class="literal:kk-error" for="a_state"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_country"/> :</div>
>  <div class="kk-field"><t:select t:id="a_country" model="countryModel"
> value="address.countryCode" blankOption="NEVER"
> zone="stateModelZone"/></div>
>  </div>
>  <p>
>  <input t:type="submit" value="message:submit-label"/>
>  </p>
> </t:form>
> public class Register extends BasePage {
>        @Inject
>        private Logger log;
>        @Inject
>        private UtilityServiceRemote utilityService;
>        @Persist
>        @Property
>        private AddressUiBean address;
>        @OnEvent(value=EventConstants.PREPARE)
>        void initialize() {
>                if(address == null) address = new AddressUiBean();
>                if(contact == null) contact = new ContactUiBean();
>                if(registration == null) registration = new RegisterUiBean();
>                String countryCode = address.getCountryCode();
>                if(countryCode == null) {
>                        Locale locale = getLocale();
>                        countryCode = locale.getCountry();
>                        address.setCountryCode(countryCode);
>                }
>                log.debug("address state code {}", address.getStateCode());
>        }
>        @Cached
>        public Map<String, String> getCountryModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                List<CountryBean> countries =
>                        utilityService.getAllCountries(getLocale());
>                for(CountryBean country : countries) {
>                        String code = country.getCodeIsoAlpha2();
>                        String description = country.getShortName();
>                        log.debug("code: {}, description: {}", code, description);
>                        model.put(code, description);
>                }
>                return model;
>        }
>        @OnEvent(value=EventConstants.VALUE_CHANGED, component="a_country")
>        public Object onCountrySelected(String aCountryCode) {
>                log.debug("selected country: {}", aCountryCode);
>                address.setStateCode(null);
>                return stateModelZone.getBody();
>        }
>        @Cached
>        public Map<String, String> getStateModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                String countryCode = address.getCountryCode();
>                List<StateProvinceBean> states =
>                        utilityService.getAllStateProvincesForCountry(countryCode, getLocale());
>                for(StateProvinceBean state : states) {
>                        String code = state.getLookupCode();
>                        String name = state.getLongName();
>                        log.debug("code: {}, name {}", code, name);
>                        model.put(code, name);
>                }
>                return model;
>        }
> }

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

[jira] [Commented] (TAP5-1512) Select update via zone inside a form confuses form's ValidationTracker

Posted by "Adam Zimowski (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/TAP5-1512?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13025263#comment-13025263 ] 

Adam Zimowski commented on TAP5-1512:
-------------------------------------

Complete Thread: http://tapestry.1045711.n5.nabble.com/T5-select-zone-update-in-a-form-tp4314488p4314488.html

> Select update via zone inside a form confuses form's ValidationTracker
> ----------------------------------------------------------------------
>
>                 Key: TAP5-1512
>                 URL: https://issues.apache.org/jira/browse/TAP5-1512
>             Project: Tapestry 5
>          Issue Type: Bug
>          Components: tapestry-core, tapestry-ioc
>    Affects Versions: 5.2.5
>            Reporter: Adam Zimowski
>            Priority: Minor
>
> Here is the use case:
> We have a simple address form with Line 1, Line 2, City (all text fields), State (Select), Zip (Text Field) and Country (Select). State select is wrapped inside a Zone, which is tied to Country select, so that when country is selected, states get populated. Line 1, City, State, Zip and Country are all required. Form uses <t:error/> next to each field.
> Here is the problem:
> 1. Select country and state (both have blank options therefore are required), but leave other fields empty.
> 2. Submit form. Validation on required fields (such as city, zip) results in form rendering error messages. Note: Country and State are
> not in error at this point.
> 3. While correcting errors on the form, change country. As a result, state select component is repopulated (zone update), and default blank
> option is select. Do not chose state.
> 4. Submit form with state *not* selected. Debugging select shows that ValidationTracker contains error (state required), yet attached field error is not displaying the error.
> Upon debugging the framework I found the following:
> IdAllocator used to generate component id, suffixes select with an increment even select is not inside a loop. It does this ONLY when Zone is updated, causing the very subsequent form submit record error for select under wrong key (a_state_1 rather than state), and so the <t:error/> is unable to locate the error when form eventually renders back with original select id (a_state).
> In this case, what happens is that every time I update zone while form is in error, the ID of my select changes with incremented suffix:
> ORIGINAL AS EXPECTED BY FORM: a_state
> After resetting country causing state dropdown to repopulate, id becomes: 
> a_state_1 then a_state_2 etc...
> This causes ValidationTracker put error under wrong key, and consequently error to field binding in tracker's map cannot be
> resolved, causing <t:error/> thinking that all is good. That's why <t:errors/> does display the error, as it simply loops over collection
> of errors.
> Out of lack of deep understanding of Tapestry, I coded a simple hack to verify that if select update via zone kept its original id things
> would work, and indeed, the following hack fixes the problem for my case:
> Tapestry 5.2.5, AbstractField line 183:
>    private void setupControlName(String controlName)
>    {
>        if(controlName.startsWith("a_state"))
>                this.controlName = "a_state";
>        else
>                this.controlName = controlName;
>    }
> Here is my source:
> <t:form t:id="registrationForm">
> <div class="kk-hdr">Address Information</div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line1"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line1" value="address.line1"/></div>
>  <t:error class="literal:kk-error" for="a_line1"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line2"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line2" value="address.line2"/></div>
>  <t:error class="literal:kk-error" for="a_line2"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line3"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line3" value="address.line3"/></div>
>  <t:error class="literal:kk-error" for="a_line3"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_city"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_city" value="address.city"/></div>
>  <t:error class="literal:kk-error" for="a_city"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_zip"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_zip" value="address.zipCode"/></div>
>  <t:error class="literal:kk-error" for="a_zip"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_state"/> :</div>
>  <div class="kk-field" t:type="zone" t:id="stateModelZone"><t:select
> t:id="a_state" model="stateModel" validate="required"
> value="address.stateCode" blankOption="ALWAYS"
> blankLabel="literal:--Please Select"/></div>
>  <t:error class="literal:kk-error" for="a_state"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_country"/> :</div>
>  <div class="kk-field"><t:select t:id="a_country" model="countryModel"
> value="address.countryCode" blankOption="NEVER"
> zone="stateModelZone"/></div>
>  </div>
>  <p>
>  <input t:type="submit" value="message:submit-label"/>
>  </p>
> </t:form>
> public class Register extends BasePage {
>        @Inject
>        private Logger log;
>        @Inject
>        private UtilityServiceRemote utilityService;
>        @Persist
>        @Property
>        private AddressUiBean address;
>        @OnEvent(value=EventConstants.PREPARE)
>        void initialize() {
>                if(address == null) address = new AddressUiBean();
>                if(contact == null) contact = new ContactUiBean();
>                if(registration == null) registration = new RegisterUiBean();
>                String countryCode = address.getCountryCode();
>                if(countryCode == null) {
>                        Locale locale = getLocale();
>                        countryCode = locale.getCountry();
>                        address.setCountryCode(countryCode);
>                }
>                log.debug("address state code {}", address.getStateCode());
>        }
>        @Cached
>        public Map<String, String> getCountryModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                List<CountryBean> countries =
>                        utilityService.getAllCountries(getLocale());
>                for(CountryBean country : countries) {
>                        String code = country.getCodeIsoAlpha2();
>                        String description = country.getShortName();
>                        log.debug("code: {}, description: {}", code, description);
>                        model.put(code, description);
>                }
>                return model;
>        }
>        @OnEvent(value=EventConstants.VALUE_CHANGED, component="a_country")
>        public Object onCountrySelected(String aCountryCode) {
>                log.debug("selected country: {}", aCountryCode);
>                address.setStateCode(null);
>                return stateModelZone.getBody();
>        }
>        @Cached
>        public Map<String, String> getStateModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                String countryCode = address.getCountryCode();
>                List<StateProvinceBean> states =
>                        utilityService.getAllStateProvincesForCountry(countryCode, getLocale());
>                for(StateProvinceBean state : states) {
>                        String code = state.getLookupCode();
>                        String name = state.getLongName();
>                        log.debug("code: {}, name {}", code, name);
>                        model.put(code, name);
>                }
>                return model;
>        }
> }

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira

[jira] [Commented] (TAP5-1512) Select update via zone inside a form confuses form's ValidationTracker

Posted by "Ivan Khalopik (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/TAP5-1512?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13455774#comment-13455774 ] 

Ivan Khalopik commented on TAP5-1512:
-------------------------------------

I hope this solution can temporary fix such problems:
http://mutabra.blogspot.com/2012/09/tapestry-fixed-control-name-fixin.html
                
> Select update via zone inside a form confuses form's ValidationTracker
> ----------------------------------------------------------------------
>
>                 Key: TAP5-1512
>                 URL: https://issues.apache.org/jira/browse/TAP5-1512
>             Project: Tapestry 5
>          Issue Type: Bug
>          Components: tapestry-core, tapestry-ioc
>    Affects Versions: 5.2
>            Reporter: Adam Zimowski
>            Priority: Minor
>
> Here is the use case:
> We have a simple address form with Line 1, Line 2, City (all text fields), State (Select), Zip (Text Field) and Country (Select). State select is wrapped inside a Zone, which is tied to Country select, so that when country is selected, states get populated. Line 1, City, State, Zip and Country are all required. Form uses <t:error/> next to each field.
> Here is the problem:
> 1. Select country and state (both have blank options therefore are required), but leave other fields empty.
> 2. Submit form. Validation on required fields (such as city, zip) results in form rendering error messages. Note: Country and State are
> not in error at this point.
> 3. While correcting errors on the form, change country. As a result, state select component is repopulated (zone update), and default blank
> option is select. Do not chose state.
> 4. Submit form with state *not* selected. Debugging select shows that ValidationTracker contains error (state required), yet attached field error is not displaying the error.
> Upon debugging the framework I found the following:
> IdAllocator used to generate component id, suffixes select with an increment even select is not inside a loop. It does this ONLY when Zone is updated, causing the very subsequent form submit record error for select under wrong key (a_state_1 rather than state), and so the <t:error/> is unable to locate the error when form eventually renders back with original select id (a_state).
> In this case, what happens is that every time I update zone while form is in error, the ID of my select changes with incremented suffix:
> ORIGINAL AS EXPECTED BY FORM: a_state
> After resetting country causing state dropdown to repopulate, id becomes: 
> a_state_1 then a_state_2 etc...
> This causes ValidationTracker put error under wrong key, and consequently error to field binding in tracker's map cannot be
> resolved, causing <t:error/> thinking that all is good. That's why <t:errors/> does display the error, as it simply loops over collection
> of errors.
> Out of lack of deep understanding of Tapestry, I coded a simple hack to verify that if select update via zone kept its original id things
> would work, and indeed, the following hack fixes the problem for my case:
> Tapestry 5.2.5, AbstractField line 183:
>    private void setupControlName(String controlName)
>    {
>        if(controlName.startsWith("a_state"))
>                this.controlName = "a_state";
>        else
>                this.controlName = controlName;
>    }
> Here is my source:
> <t:form t:id="registrationForm">
> <div class="kk-hdr">Address Information</div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line1"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line1" value="address.line1"/></div>
>  <t:error class="literal:kk-error" for="a_line1"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line2"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line2" value="address.line2"/></div>
>  <t:error class="literal:kk-error" for="a_line2"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line3"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line3" value="address.line3"/></div>
>  <t:error class="literal:kk-error" for="a_line3"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_city"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_city" value="address.city"/></div>
>  <t:error class="literal:kk-error" for="a_city"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_zip"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_zip" value="address.zipCode"/></div>
>  <t:error class="literal:kk-error" for="a_zip"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_state"/> :</div>
>  <div class="kk-field" t:type="zone" t:id="stateModelZone"><t:select
> t:id="a_state" model="stateModel" validate="required"
> value="address.stateCode" blankOption="ALWAYS"
> blankLabel="literal:--Please Select"/></div>
>  <t:error class="literal:kk-error" for="a_state"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_country"/> :</div>
>  <div class="kk-field"><t:select t:id="a_country" model="countryModel"
> value="address.countryCode" blankOption="NEVER"
> zone="stateModelZone"/></div>
>  </div>
>  <p>
>  <input t:type="submit" value="message:submit-label"/>
>  </p>
> </t:form>
> public class Register extends BasePage {
>        @Inject
>        private Logger log;
>        @Inject
>        private UtilityServiceRemote utilityService;
>        @Persist
>        @Property
>        private AddressUiBean address;
>        @OnEvent(value=EventConstants.PREPARE)
>        void initialize() {
>                if(address == null) address = new AddressUiBean();
>                if(contact == null) contact = new ContactUiBean();
>                if(registration == null) registration = new RegisterUiBean();
>                String countryCode = address.getCountryCode();
>                if(countryCode == null) {
>                        Locale locale = getLocale();
>                        countryCode = locale.getCountry();
>                        address.setCountryCode(countryCode);
>                }
>                log.debug("address state code {}", address.getStateCode());
>        }
>        @Cached
>        public Map<String, String> getCountryModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                List<CountryBean> countries =
>                        utilityService.getAllCountries(getLocale());
>                for(CountryBean country : countries) {
>                        String code = country.getCodeIsoAlpha2();
>                        String description = country.getShortName();
>                        log.debug("code: {}, description: {}", code, description);
>                        model.put(code, description);
>                }
>                return model;
>        }
>        @OnEvent(value=EventConstants.VALUE_CHANGED, component="a_country")
>        public Object onCountrySelected(String aCountryCode) {
>                log.debug("selected country: {}", aCountryCode);
>                address.setStateCode(null);
>                return stateModelZone.getBody();
>        }
>        @Cached
>        public Map<String, String> getStateModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                String countryCode = address.getCountryCode();
>                List<StateProvinceBean> states =
>                        utilityService.getAllStateProvincesForCountry(countryCode, getLocale());
>                for(StateProvinceBean state : states) {
>                        String code = state.getLookupCode();
>                        String name = state.getLongName();
>                        log.debug("code: {}, name {}", code, name);
>                        model.put(code, name);
>                }
>                return model;
>        }
> }

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

[jira] [Commented] (TAP5-1512) Select update via zone inside a form confuses form's ValidationTracker

Posted by "Ivan Khalopik (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/TAP5-1512?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13455774#comment-13455774 ] 

Ivan Khalopik commented on TAP5-1512:
-------------------------------------

I hope this solution can temporary fix such problems:
http://mutabra.blogspot.com/2012/09/tapestry-fixed-control-name-fixin.html
                
> Select update via zone inside a form confuses form's ValidationTracker
> ----------------------------------------------------------------------
>
>                 Key: TAP5-1512
>                 URL: https://issues.apache.org/jira/browse/TAP5-1512
>             Project: Tapestry 5
>          Issue Type: Bug
>          Components: tapestry-core, tapestry-ioc
>    Affects Versions: 5.2
>            Reporter: Adam Zimowski
>            Priority: Minor
>
> Here is the use case:
> We have a simple address form with Line 1, Line 2, City (all text fields), State (Select), Zip (Text Field) and Country (Select). State select is wrapped inside a Zone, which is tied to Country select, so that when country is selected, states get populated. Line 1, City, State, Zip and Country are all required. Form uses <t:error/> next to each field.
> Here is the problem:
> 1. Select country and state (both have blank options therefore are required), but leave other fields empty.
> 2. Submit form. Validation on required fields (such as city, zip) results in form rendering error messages. Note: Country and State are
> not in error at this point.
> 3. While correcting errors on the form, change country. As a result, state select component is repopulated (zone update), and default blank
> option is select. Do not chose state.
> 4. Submit form with state *not* selected. Debugging select shows that ValidationTracker contains error (state required), yet attached field error is not displaying the error.
> Upon debugging the framework I found the following:
> IdAllocator used to generate component id, suffixes select with an increment even select is not inside a loop. It does this ONLY when Zone is updated, causing the very subsequent form submit record error for select under wrong key (a_state_1 rather than state), and so the <t:error/> is unable to locate the error when form eventually renders back with original select id (a_state).
> In this case, what happens is that every time I update zone while form is in error, the ID of my select changes with incremented suffix:
> ORIGINAL AS EXPECTED BY FORM: a_state
> After resetting country causing state dropdown to repopulate, id becomes: 
> a_state_1 then a_state_2 etc...
> This causes ValidationTracker put error under wrong key, and consequently error to field binding in tracker's map cannot be
> resolved, causing <t:error/> thinking that all is good. That's why <t:errors/> does display the error, as it simply loops over collection
> of errors.
> Out of lack of deep understanding of Tapestry, I coded a simple hack to verify that if select update via zone kept its original id things
> would work, and indeed, the following hack fixes the problem for my case:
> Tapestry 5.2.5, AbstractField line 183:
>    private void setupControlName(String controlName)
>    {
>        if(controlName.startsWith("a_state"))
>                this.controlName = "a_state";
>        else
>                this.controlName = controlName;
>    }
> Here is my source:
> <t:form t:id="registrationForm">
> <div class="kk-hdr">Address Information</div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line1"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line1" value="address.line1"/></div>
>  <t:error class="literal:kk-error" for="a_line1"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line2"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line2" value="address.line2"/></div>
>  <t:error class="literal:kk-error" for="a_line2"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_line3"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_line3" value="address.line3"/></div>
>  <t:error class="literal:kk-error" for="a_line3"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_city"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_city" value="address.city"/></div>
>  <t:error class="literal:kk-error" for="a_city"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_zip"/> :</div>
>  <div class="kk-field"><t:textfield t:id="a_zip" value="address.zipCode"/></div>
>  <t:error class="literal:kk-error" for="a_zip"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_state"/> :</div>
>  <div class="kk-field" t:type="zone" t:id="stateModelZone"><t:select
> t:id="a_state" model="stateModel" validate="required"
> value="address.stateCode" blankOption="ALWAYS"
> blankLabel="literal:--Please Select"/></div>
>  <t:error class="literal:kk-error" for="a_state"/>
>  </div>
>  <div class="kk-row">
>  <div class="kk-label"><t:label for="a_country"/> :</div>
>  <div class="kk-field"><t:select t:id="a_country" model="countryModel"
> value="address.countryCode" blankOption="NEVER"
> zone="stateModelZone"/></div>
>  </div>
>  <p>
>  <input t:type="submit" value="message:submit-label"/>
>  </p>
> </t:form>
> public class Register extends BasePage {
>        @Inject
>        private Logger log;
>        @Inject
>        private UtilityServiceRemote utilityService;
>        @Persist
>        @Property
>        private AddressUiBean address;
>        @OnEvent(value=EventConstants.PREPARE)
>        void initialize() {
>                if(address == null) address = new AddressUiBean();
>                if(contact == null) contact = new ContactUiBean();
>                if(registration == null) registration = new RegisterUiBean();
>                String countryCode = address.getCountryCode();
>                if(countryCode == null) {
>                        Locale locale = getLocale();
>                        countryCode = locale.getCountry();
>                        address.setCountryCode(countryCode);
>                }
>                log.debug("address state code {}", address.getStateCode());
>        }
>        @Cached
>        public Map<String, String> getCountryModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                List<CountryBean> countries =
>                        utilityService.getAllCountries(getLocale());
>                for(CountryBean country : countries) {
>                        String code = country.getCodeIsoAlpha2();
>                        String description = country.getShortName();
>                        log.debug("code: {}, description: {}", code, description);
>                        model.put(code, description);
>                }
>                return model;
>        }
>        @OnEvent(value=EventConstants.VALUE_CHANGED, component="a_country")
>        public Object onCountrySelected(String aCountryCode) {
>                log.debug("selected country: {}", aCountryCode);
>                address.setStateCode(null);
>                return stateModelZone.getBody();
>        }
>        @Cached
>        public Map<String, String> getStateModel() {
>                Map<String, String> model = new LinkedHashMap<String, String>();
>                String countryCode = address.getCountryCode();
>                List<StateProvinceBean> states =
>                        utilityService.getAllStateProvincesForCountry(countryCode, getLocale());
>                for(StateProvinceBean state : states) {
>                        String code = state.getLookupCode();
>                        String name = state.getLongName();
>                        log.debug("code: {}, name {}", code, name);
>                        model.put(code, name);
>                }
>                return model;
>        }
> }

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira