0

ZK6 SelectorComposer + Data binding

asked 2012-03-30 10:28:04 +0800

cyiannoulis gravatar image cyiannoulis
1191 10
Hi again to all, I have used in the past the GenericForwardComposer with DataBinding without problems. Now in ZK 6 it's not clear to me anymore what to use. The books recommend the use of the MVVM pattern. IMHO i think that MVVM needs some more work to be done. On the other hand i like very much the SelectorComposer and the way annotated listeners are working. The problem is that i notice some strange behavior trying to apply databinding inside a SelectorComposer. I am assembling a collection of samples to demonstrate various cases. But for now i need to know whether or not the following approach is acceptable. Should i use the new @bind() or the old @{ } annotation inside a Zul driven by a SelectorComposer? Or should i continue using the old GenericForwardComposer? Anyone else using the same approach or everybody now uses MVVM :) I have searched the documentation and i couldn't find anything relevant. A simple zul:
<?page contentType="text/html;charset=UTF-8"?>
<zk>
<window id="winTestListbox" title="Test Listbox" border="normal" closable="false"
		apply="wwwsnippets.SampleListboxController" height="100%" width="100%" >

		<vlayout vflex="true">
		
			<groupbox height="50px" closable="false" >
				<label value="Code" />
				<textbox id="txtCode" value="@bind( vm.customer.customerCode )" />
				<label value="Name" />
				<textbox id="txtName" value="@bind( vm.customer.customerName )" />
			</groupbox>
			
			<listbox model="@bind( vm.addresses )" selectedItem="@bind( vm.selectedAddress )" vflex="true">
			
				<auxhead>
				    <auxheader label="Listbox :: Addresses" colspan="2" align="center" />
				</auxhead>
													
				<listhead sizable="true">
					<listheader label="Area" width="200px" />
					<listheader label="Street" hflex="true" />
				</listhead>
				
				<listitem self="@{each='addressItem'}" value="@bind( addressItem.street )" >			
					<listcell label="@bind( addressItem.area )" />			
					<listcell label="@bind( addressItem.street )" />			
				</listitem>
				
			</listbox>	
					
		</vlayout>
</window>
</zk>
The SelectorComposer:
package wwwsnippets;

import java.util.ArrayList;
import java.util.List;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zkplus.databind.AnnotateDataBinder;

public class SampleListboxController extends SelectorComposer {

	private static final long serialVersionUID = 1L;
	
	/*
	 * Databinder / Models
	 */
	private AnnotateDataBinder binder;
	
	private CustomerBean customer;
	private List<AddressBean> addresses;
	private AddressBean selectedAddress;
	
	@Override
	public void doAfterCompose(Component comp) throws Exception {
		
		try {
			super.doAfterCompose(comp);
		} 
		catch (Exception e) {
			e.printStackTrace();
		}
		
		binder = new AnnotateDataBinder(comp);
		binder.bindBean("vm", this);
		
		createModels();
	}
	
	private void createModels() {
		
		customer = new CustomerBean("1234", "costas");
		
		addresses = new ArrayList<AddressBean>();
		for (int i = 0; i < 100; i++) {
			addresses.add( new AddressBean("address " + i, "area " + i ));
		}
		
	}

	@Listen("onCreate = window#winTestListbox")	
	public void onCreate(Event event) {
		
		binder.loadAll();
	}
	
	public AnnotateDataBinder getBinder() {
		return binder;
	}

	public void setBinder(AnnotateDataBinder binder) {
		this.binder = binder;
	}

	public CustomerBean getCustomer() {
		return customer;
	}

	public void setCustomer(CustomerBean customer) {
		this.customer = customer;
	}

	public List<AddressBean> getAddresses() {
		return addresses;
	}

	public void setAddresses(List<AddressBean> addresses) {
		this.addresses = addresses;
	}

	public AddressBean getSelectedAddress() {
		return selectedAddress;
	}

	public void setSelectedAddress(AddressBean selectedAddress) {
		this.selectedAddress = selectedAddress;
	}

}
And some beans:
package wwwsnippets;

public class CustomerBean {

	private String customerCode; 
	private String customerName;
	
	public String getCustomerCode() {
		return customerCode;
	}
	public void setCustomerCode(String customerCode) {
		this.customerCode = customerCode;
	}
	public String getCustomerName() {
		return customerName;
	}
	public void setCustomerName(String customerName) {
		this.customerName = customerName;
	}
	
	public CustomerBean(String customerCode, String customerName) {
		super();
		this.customerCode = customerCode;
		this.customerName = customerName;
	}
	
}
package wwwsnippets;

public class AddressBean {

	private String street; 
	private String area;
	
	public String getStreet() {
		return street;
	}
	public void setStreet(String street) {
		this.street = street;
	}
	public String getArea() {
		return area;
	}
	public void setArea(String area) {
		this.area = area;
	}
	
	public AddressBean(String address, String area) {
		super();
		this.street = address;
		this.area = area;
	}
	
}
Thank you very much for your help.
delete flag offensive retag edit

9 Replies

Sort by ยป oldest newest

answered 2012-04-05 01:49:16 +0800

rdgrimes gravatar image rdgrimes
735 7

As a relatively new ZK developer myself, I've been researching the best approach to putting things together as well. It's my understanding that, with MVVM, you should not use SelectorComposer as this is only preferred if you want to take advantage of annotations and wire objects into your composer class. This is contrary to the whole objective of the MVVM model, wherein the View knows about the ViewModel, but the ViewModel knows nothing of the View.

So, bottom line is this. With MVVM, you are not using any composer other than the built in BindComposer that stands between the View and the ViewModel. It's not a question of using SelectorComposer or GenericForwardComposer. Neither is used.

Ron

link publish delete flag offensive edit

answered 2012-04-05 13:06:20 +0800

Zachi gravatar image Zachi
24

Hi,

I also made some tests with the new MVVM approach. The idea behind is very cool, because you can easily make JUnit tests on the program logic. Unfortunately this approach has some very big disadvantages. If you do not use a composer, which is aware of the GUI you cannot do everything. Here is an example:

If you want to open a new window as a dialog, you have to use the current Execution and create the component. Furthermore you also want to retrieve data from the dialog and paste it to ViewModel. This can be done by GlobalCommands, so no real problem. But for this you need at least a GenericForwardComposer or a SelectorComposer. Fortunately you can easily use both.

But I think there are some difficulties in using both together. For example the new databinding does not work on custom-attributes. This disallows to exchange data between MVC and MVVM. So, if you do not want any GUI knowledge in your ViewModel, but want to paste Modelinformation to a new window, this is not possible right now :(
To use MVVM in production will need some time. At this state of development it is not usable for me.

Regards, Stephan

link publish delete flag offensive edit

answered 2012-04-05 14:47:15 +0800

cyiannoulis gravatar image cyiannoulis
1191 10

Thank you guys. So, Stephan you think that it is ok to continue using the composer (either GenericForward or Selector) with the "old" AnnotateDataBinder? Would it be "safer" to stick with the ZK 5 version? It would be a pity because i think that annotated listeners in SelectorComposer are very elegant.

Thanks again

/costas

link publish delete flag offensive edit

answered 2012-04-05 15:17:44 +0800

rdgrimes gravatar image rdgrimes
735 7

updated 2012-04-05 15:18:46 +0800

Stephan:

I don't see any reason to paste the results of dialogue box into the ViewModel directly. The component that dynamically spawned the child dialogue window has access to its results. The dialogue box's parent component can then turn around and @save any required value to the ViewModel to which it has bound itself, assuming of course that the ViewModel supports storage of that object.

Ron

link publish delete flag offensive edit

answered 2012-04-05 20:41:46 +0800

Matze2 gravatar image Matze2
773 7

I agree, that there are still a few cases, especially "Executions.createComponents()" where some knowledge on the ZUL structure is needed.
For me it is acceptable to wire these limited number of components into the ViewModel.
To achieve this, you just call

Selectors.wireComponents(ctx.getBinder().getView(), this, false);
in your @Init method.

link publish delete flag offensive edit

answered 2012-04-06 07:28:57 +0800

yaminglin1977 gravatar image yaminglin1977
36 2

updated 2012-04-06 07:31:41 +0800

"http://books.zkoss.org/wiki/ZK%20Developer's%20Reference/MVVM/Advance/Wire%20Components " show how to wire component in viewModel,below is the example:
public class SearchAutowireVM{
//UI component
@Wire("#msgPopup")
Popup popup;
@Wire("#msg")
Label msg;
@Init
public void init(@ContextParam(ContextType.VIEW) Component view){
Selectors.wireComponents(view, this, false);
}
}
i think the more testable solution is using "ZK Developer's Reference/MVVM/Advance/Parameters" , you can test your viewModel in Junit,if you not intend to test the command method which access component by parameters.

link publish delete flag offensive edit

answered 2012-04-06 11:07:10 +0800

Zachi gravatar image Zachi
24

@ rdgrimes / Ron:

Your approach sounds good. Unfortunately I didn't get your point on how to retrieve results from a dialogue window and use it with databinding 2. Would you be so kind and give us an example on ZKfiddle.org? I always search for good solutions on how to handle things in ZK :)

Regards, Stephan

link publish delete flag offensive edit

answered 2012-04-06 11:14:36 +0800

Zachi gravatar image Zachi
24

@ costas:
I don't think that it is a good solution to use ZK 5 anymore. Sooner or later you have to switch to ZK 6. There is no reason to take the old ZK 5. I migrated my project to ZK 6 and didn't find any problems with it. In ZK 6 you can also use GenericForwardComposer. Furthermore you should try to use MVVM as soon as possible, because databinding 2 supports EL 2.2, which is very nice in many cases. More and more I get the point on how to model my old concepts with the new MVVM and it seems to work in most cases. If there is a case in which it does not give you everything, you can use the old GenericForwardComposer with the AnnotateDataBinder ;-)

Another hint of mine, you can also use SelectorComposer together with the BindComposer and MVVM. And use the strength of MVC and MVVM, but be aware that you should not store any model information in your selector composer. Otherwise the pattern is not correctly used and you can run into concept problems.

link publish delete flag offensive edit

answered 2012-04-06 14:56:58 +0800

cyiannoulis gravatar image cyiannoulis
1191 10

Thanks Stephan and all the other guys. I will explore a little bit further the MVVM+MVC combination.

/costas

link publish delete flag offensive edit
Your reply
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow

RSS

Stats

Asked: 2012-03-30 10:28:04 +0800

Seen: 1,787 times

Last updated: Apr 06 '12

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More