-
FEATURED COMPONENTS
First time here? Check out the FAQ!
I was glad to find this new feature in ZK 5.0.2: add data binding support for custom attribute tag - ID: 2855116
However, it is not working when I apply events to annotation:
<textbox rows="3" width="90%" maxlength="500"> <custom-attributes CriNo="@{textCri.Criteria_No, converter='sas.application.TextCriAnsConverter', save-when='self.onChange'}" /> </textbox>
code: null<listbox id="textCriList" model="@{mainWin$composer.App.Scho.TextCriteria, load-after='mainWin.onDisplay'}" sizedByContent="false"> <listhead sizable="true"> <listheader label="Criteria" sort="auto" /> <listheader label="Reasons" /> </listhead> <listitem self="@{each='textCri'}" value="@{textCri}" height="25px"> <listcell label="@{textCri.Statement}" /> <listcell> <textbox rows="3" width="90%" maxlength="500"> <custom-attributes CriNo="@{textCri.Criteria_No, converter='sas.application.TextCriAnsConverter', save-when='self.onChange'}" /> </textbox> </listcell> </listitem> </listbox><br/> <br/>My converter: <div style="class=code" class="code"><pre><div class="error">code: null</div> public class TextCriAnsConverter implements TypeConverter { @Override public Object coerceToBean(Object val, Component comp) { if (val != null) { if (val instanceof Textbox) { Textbox ansField = (Textbox) val; int cri_No = (Integer) ansField.getAttribute("CriNo"); String Ans = ansField.getValue(); if (Ans.trim().length() > 0) { // get the application bound with textCriList Application binding_app = (Application) ((Listcell) ansField .getParent()).getListbox().getAttribute( "binding_app"); AppTextCriteria item = new AppTextCriteria(cri_No, Ans); binding_app.addTextCriteriaAns(item); } } } return null; } @Override public Object coerceToUi(Object val, Component comp) { if (val != null) { if (val instanceof Integer && comp instanceof Textbox) { int cri_No = (Integer) val; Textbox ansField = (Textbox) comp; // get the application bound with textCriList Application binding_app = (Application) ((Listcell) ansField .getParent()).getListbox().getAttribute("binding_app"); if (binding_app != null) { AppTextCriteria TextCriAns = binding_app .findTextCriteriaAns(cri_No); if (TextCriAns != null) { ansField.setValue(TextCriAns.getReason()); } } } } return null; } }
Thank you for your help in advance!
Here is my solution but.... it's just to avoid that problem. I still hope someone could tell me whether or not custom attributes support data binding annotation with events trigger like save-when, thank you a lot!
<listbox id="textCriList" model="@{mainWin$composer.App.Scho.TextCriteria, load-after='mainWin.onDisplay'}" sizedByContent="false"> <listhead sizable="true"> <listheader label="Criteria" sort="auto" /> <listheader label="Reasons" /> </listhead> <listitem self="@{each='textCri'}" value="@{textCri}" height="25px"> <listcell label="@{textCri.Statement}" /> <listcell> <custom-attributes CriNo="@{textCri.Criteria_No}" /> <textbox value="@{textCri.Criteria_No, converter='sas.application.TextCriAnsConverter', save-after='self.onBlur'}" rows="3" width="90%" maxlength="500"> </textbox> </listcell> </listitem> </listbox>
public class TextCriAnsConverter implements TypeConverter { @Override public Object coerceToBean(Object val, Component comp) { if (val != null) { if (val instanceof String) { // object val is extracted from the attribute which is bound // with annotation by its getter method String Ans = (String) val; Textbox ansField = (Textbox) comp; int cri_No = (Integer) ansField.getParent().getAttribute( "CriNo"); // get the application bound with textCriList Application binding_app = (Application) ((Listcell) ansField .getParent()).getListbox().getAttribute("binding_app"); AppTextCriteria item = new AppTextCriteria(cri_No, Ans); if (Ans.trim().length() > 0) { binding_app.addTextCriteriaAns(item); } else { binding_app.removeTextCriteriaAns(item); } } } // can NOT return null; because the receiving bean is int data type by // calling setCriteria_No(int criteriaNo) return TypeConverter.IGNORE; } @Override public Object coerceToUi(Object val, Component comp) { if (val != null) { if (comp instanceof Textbox) { Textbox ansField = (Textbox) comp; // wish to be get from val... :( int cri_No = (Integer) ansField.getParent().getAttribute( "CriNo"); // get the application bound with textCriList Application binding_app = (Application) ((Listcell) ansField .getParent()).getListbox().getAttribute("binding_app"); if (binding_app != null) { AppTextCriteria TextCriAns = binding_app .findTextCriteriaAns(cri_No); if (TextCriAns != null) { // indicate setValue(TextCriAns.getReason()) return cri_No+": "+TextCriAns.getReason(); } } } } return null; } }
Just an idea (not tested):
<textbox rows="3" width="90%" maxlength="500">
<custom-attributes CriNo="@{textCri.Criteria_No, converter='sas.application.TextCriAnsConverter', save-when='self.onChange'}" />
</textbox>
Maybe self don't work in the custom-attribute, try
<textbox id="tbid" ...
<ustom-attributes .....save-when='tbid.onChange'}"/>
/Robert
Thank you for this good idea. However, before trying it, could you tell me how to set distinct ID for each of my dynamically-generated textboxes component in ZUL? Can I use <textbox id="tbid_${textCriList.ItemCount}"... ? Or I have to set their IDs programmically?
because they are created depending on my listbox setModel() as you can see on my above code.
code: null<listbox id="textCriList" model="@{mainWin$composer.App.Scho.TextCriteria, load-after='mainWin.onDisplay'}" sizedByContent="false"> <listhead sizable="true"> <listheader label="Criteria" sort="auto" /> <listheader label="Reasons" /> </listhead> <listitem self="@{each='textCri'}" value="@{textCri}" height="25px"> <listcell label="@{textCri.Statement}" /> <listcell> <custom-attributes CriNo="@{textCri.Criteria_No}" /> <textbox id="tbid_${textCriList.ItemCount}" value="@{textCri.Criteria_No, converter='sas.application.TextCriAnsConverter', save-after='self.onBlur'}" rows="3" width="90%" maxlength="500"> </textbox> </listcell> </listitem> </listbox>code: null
Thanks for your concern, I have posted this issue on bug tracker.
I'm not sure about your case, custom-attributes seems to work for me. Maybe this is an special case (custom-attribute without binding for the value...).
About your question:
>> However, before trying it, could you tell me how to set distinct ID for each of my dynamically-generated textboxes
There is no need for an distinct ID. Databinding creates a template (including the eventlisteners) and copy the template
for each record (including the eventlisteners).
/Robert
As for my Textbox component,
@enix0907,
Have to specify the access to 'both'
----
<textbox rows="3" width="90%" maxlength="500">
<custom-attributes
CriNo="@{textCri.Criteria_No, converter='sas.application.TextCriAnsConverter', save-when='self.onChange', access='both'}" />
</textbox>
----
Which tells the data binder that the attribute CriNo is both "loadable" and "savable".
Search 'access' in JavaDoc for details.
http://www.zkoss.org/javadoc/5.0.0/zk/org/zkoss/zkplus/databind/AnnotateDataBinder.html
@henrichen,
Thank you for your assistance, now it is working correctly! :=) this attribute access controls whether or not to execute my converter when events assign to save/load attribute.
Asked: 2010-08-24 22:51:07 +0800
Seen: 725 times
Last updated: Aug 30 '10