0

request for the binding of the bean property by the object

asked 2012-06-15 12:49:04 +0800

khcyt gravatar image khcyt
216 1 1

Hi folks from ZK Bind,

sometimes I have a large amount of listmodel objects. Only a subset of these are displayed on the screen. Until runtime decides which are to be reported.
The data for the lists I receive discontinuous.

For this reason, I did the listmodels not bound by name. The binding is done using a method from view model:
listbox model="@bind(vm.getLM(each))"

Unfortunately, all properties are bound internally with the name "getLM".
After receiving the data for a list so I can send only one notification for all lists.
org.zkoss.bind.BindUtils.postNotifyChange(null, null, this, "getLM");

Is it possible to extend the functionality of the ZK library so that objects can be bound directly?. Then i can call
org.zkoss.bind.BindUtils.postNotifyChange(null, null, this, lm);

Kai

Hmm, the preview shows me index-based acces as <i> or not at all. I hope you understand the code anyway

<zk>
    <zscript><![CDATA[
	int[] involved= { 3, 7, 1, 9 }; // Simulate the involved listmodel objects
       
	class VM
        {
            private ListModelList[] models= new ListModelList[10];

            public VM()
            {
                  for (int i= 0; i< models.length; ++i) models<i >= new ListModelList();
            }
            
            // Give the correct item from the list
            public ListModelList getLM(int index)      { return models; }

         	// Simulate asynchron data receive. Any data, which come from somewhere
            public void simulateData(int index) 		
            {	
                int n_data= (int) (java.lang.Math.random()* 5+ 1);
				
                ListModelList lm= getLM(index); lm.clear();
                for (int i= 0; i< n_data; ++i)
                {
                    lm.add("Data "+ String.valueOf(i)+ " for ListModel "+ String.valueOf(index)); 
                }

                org.zkoss.bind.BindUtils.postNotifyChange(null, null, this, "getLM");
            }

            // Return a list containing the indices of the involved listmodel objects
            private java.util.List indexes_= null;	
            public java.util.List	getIndexes()		
            {
                if (null== indexes_)
                {
                    indexes_= new java.util.ArrayList();
                    for (int i= 0; i< involved.length; ++i) indexes_.add(new Integer(involved<i >)); 
                }
                return indexes_;
            }
       }

   ]]></zscript>

     <window id="win" title="Window" border="normal" width="600px" 
    		apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('VM')" >
      	   <grid>
    		<rows children= "@load(vm.indexes)">
    			<template name="children">
			    	<row >
			    		<label value="${each}"/>
			    		<listbox model="@bind(vm.getLM(each))">		<!-- Access ListModel via function getLM() -->
			    			<template name="model">
				    			<listitem>
				    				<listcell label="@load(each)"/>
				    			</listitem>
							</template>
						</listbox>
			    		<button label= "Simulate data receive for Model ${each}" attributes.i="@load(each)">
			    			<attribute name="onClick">vm.simulateData(((Integer)self.getAttribute("i")).intValue());</attribute>
			    		</button>
					</row>
				</template>		    	
    		</rows>
    	</grid>
    </window>
</zk>

delete flag offensive retag edit

7 Replies

Sort by ยป oldest newest

answered 2012-06-15 14:03:55 +0800

MontyPan gravatar image MontyPan
435 3
http://xitop.blogspot.com...

Maybe use EventsQueue.lookup() in every ListModel is more direct and clear. Because, in my personal opinion, the fourth parameter of BindsUtil() is property name of bean. If it can pass any variable freely, the routine of NotifyChange will become complex and lose control.

btw, you can use

<button label="..." onClick="@command('simulateData', 3)" />

and add @NotifyChange("lM") on simulateData(), then you won't need to use BindUtils.postNotifyChange().

link publish delete flag offensive edit

answered 2012-06-15 20:11:27 +0800

khcyt gravatar image khcyt
216 1 1

Hello MonthyPan, thanks for your answer.

Your hint to EventQueue.lookup () I do not understand yet. On the basis of which event I should call the method and for what purpose?

onCommand I normally use. At this point it was not because the Java code is in the zul file. BeanShell does, however, an error at Annontation.
FYI getLM() has the following implementation. The single quotes you have to think away. As I wrote, my source code is not displayed correctly. ???

public ListModelList getLM(int index) { return models'['index']'; }

If I NotifyChange @ ("lM") add, how then the correct index is passed to this method?

Kai

link publish delete flag offensive edit

answered 2012-06-16 06:28:21 +0800

MontyPan gravatar image MontyPan
435 3
http://xitop.blogspot.com...

updated 2012-06-16 06:29:13 +0800

In every ListModel, use EVentQueue.lookup().subscribe() to catch event in EventQueue.
In the simulateData(), you use EventQueue.lookup().publish() to send an event.
Thus, when simulateData() is called, every ListModel will get the event to do something as your requirement.

NotifyChange("foo") will trigger @bind(vm.foo) or @load(vm.foo) in zul, they will call getFoo() in view model.
The code I provide is a pseudo code, maybe not fit your situation at all. (sorry)

link publish delete flag offensive edit

answered 2012-06-18 09:34:37 +0800

khcyt gravatar image khcyt
216 1 1

Hi MonthyPan, I've changed the example again and hope that the problem will be shown better. Because Listbox processed INTERVAL_ADDED, all
items are updated automatically. However, if I children binding use, is not so. Only if I call postNotifyChange(). For the call but I need a unique name for the
bean property. All models, however, are bound with "getLM". This gives notification to all vlayout elements, although only one model has been updated.
I think that EventQueue does not help me. I think that UI elements with children binding should process LastDataEvents.

Kai

<zk>
    <zscript><![CDATA[
		int[] involved= { 3, 7, 1, 9 }; // Simulate the involved listmodel objects
        String eq_name= "eq0";
		
		class VM
        {
            private ListModelList[] models= new ListModelList[10];
            boolean has_subscribed= false;

            public VM()
            {
            	for (int i= 0; i< models.length; ++i) models<i >= new ListModelList();
            }
            
            public ListModelList getLM(int index) 		{ return models'['index']'; }

         	// Simulate asynchron data receive. Any data, which come from somewhere
            public void simulateData(int index) 		
            {	
            	if (!has_subscribed)
            	{
            	    has_subscribed= true;
            	    // Subscribe for each model is probably not necessary
            	    if (EventQueues.exists(eq_name))
            			EventQueues.lookup(eq_name).subscribe(new org.zkoss.zk.ui.event.EventListener() 
            			{
							public void onEvent(Event e) 
							{
							    if (e instanceof PropertyChangeEvent)
							    {
							        PropertyChangeEvent pe= (PropertyChangeEvent) e;
								    System.out.print("\nProcess event: "+ e+ " base/property "+ pe.getBase()+ " / "+ pe.getProperty()); 
							    }
							    else System.out.print("\nProcess event: "+ e+ " for ListModel no."+ ((Integer) e.getData())); 
							}
            			});
          	    }

            	int n_data= (int) (java.lang.Math.random()* 5+ 1);
				
                ListModelList lm= getLM(index); lm.clear();
                for (int i= 0; i< n_data; ++i)
                {
                    lm.add("Data "+ String.valueOf(i)+ " for ListModel "+ String.valueOf(index)); 
                }

                String eqn= EventQueues.exists(eq_name) ? eq_name : null;
                BindUtils.postNotifyChange(eqn, null, this, "getLM");
                EventQueues.lookup(eq_name).publish(new Event("onData", null, new Integer(index)));     
            }

            // Return a list containing the indices of the involved listmodel objects
            private java.util.List indexes_= null;	
            public java.util.List	getIndexes()		
            {
                if (null== indexes_)
                {
                    indexes_= new java.util.ArrayList();
                    for (int i= 0; i< involved.length; ++i) indexes_.add(new Integer(involved'['i']')); 
                }
                return indexes_;
            }
       }

   ]]></zscript>

	<window id="win" title="Window" border="normal" width="600px" 
    		apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('VM')"
    		binder="@init(queueName='eq0')" >
    	<grid>
    		<rows children= "@load(vm.indexes)">
    			<template name="children">
			    	<row >
			    		<label value="${each}"/>
			    		<vlayout children="@load(vm.getLM(each))">		<!-- Access ListModel via function getLM() -->
			    			<template name="children">
				    			<label value="@load(each)"/>
							</template>
						</vlayout>
					</row>
				</template>		    	
    		</rows>
    	</grid>
    	<separator spacing="100px"/>
    	<grid>
    		<rows children= "@load(vm.indexes)">
    			<template name="children">
			    	<row >
			    		<label value="${each}"/>
			    		<listbox model="@bind(vm.getLM(each))">		<!-- Access ListModel via function getLM() -->
			    			<template name="model">
				    			<listitem label="@load(each)"/>
							</template>
						</listbox>
			    		<button label= "Simulate data receive for Model ${each}" attributes.i="@load(each)">
			    			<attribute name="onClick">vm.simulateData(((Integer)self.getAttribute("i")).intValue());</attribute>
			    		</button>
					</row>
				</template>		    	
    		</rows>
    	</grid>
    </window>
</zk>

link publish delete flag offensive edit

answered 2012-06-21 05:36:31 +0800

khcyt gravatar image khcyt
216 1 1

Hi MonthyPan, can you give me some more hints. What do you think about the necessary processing of ListDataEvents, when the components have children binding? Opinions of others are also welcome.

Kai

link publish delete flag offensive edit

answered 2012-06-22 04:43:51 +0800

MontyPan gravatar image MontyPan
435 3
http://xitop.blogspot.com...

Ok, here we are.......

I rewrite your code in pure MVVM without EventQueues (that's my fault, sorry), I think it's cleaner and more readable.
Hope it's helpful.

Code on Gist.

link publish delete flag offensive edit

answered 2012-06-22 09:13:00 +0800

khcyt gravatar image khcyt
216 1 1

updated 2012-06-26 11:39:23 +0800

benbai gravatar image benbai
2228 6
http://www.zkoss.org

Hello MonthyPan,

your example works well. Thank you for that. I have now modified your example again (but only a little :-) ).

NotifyChange ('*') we need not, if only list boxes would contain. Moreover, it do not like, because it tells you that all properties have changed.
That is not true. Only one change at a time. Therefore there is no update in the vlayout elements of the second grid, if I NotifyChange ('*') comment out.
How can I send a message about the change only of a list model. Or even better would be to process ListData events for all UI components with children binding such as listbox for model binding.

Oh, and I have a function to access the lists by index

public ListModelList< String > getModel(final int index) { return models.get(index); }

... and in the zul file I would rather prefer write

<listbox model="@load(vm.model(each))">

instead of write

<listbox model="@load(vm.models.get(each))">

However, the function getModel(int) is not found, during parsing the expressions?

Kai


package foo;

import java.util.ArrayList;
import java.util.List;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zul.ListModelList;

public class VM
{
    private static int[] involved = { 3, 7, 1, 9 };
    private java.util.List< ListModelList< String > > models= new java.util.ArrayList< ListModelList< String > >();

    public TestVM() 
    {
        for (int i= 0; i< 10; ++i)
        {
            models.add(new ListModelList< String >());
            mockModel(models.get(i), i);
        }
    }

    private void mockModel(final ListModelList< String > lm, final int index)
    {
        int n_data = (int) (java.lang.Math.random() * 5 + 1);
        for (int i= 0; i< n_data; ++i) 
        {
            lm.add("Data " + i + " for ListModel " + index);
        }
    }

    public java.util.List< ListModelList< String > > getModels()    { return models; }
    public ListModelList< String > getModel(final int index)        { return models.get(index); }
 
    @Command
// @NotifyChange("*")
    public void simulateData(@BindingParam("index")int index) 
    {
        ListModelList< String > lm = getModel(index);
        lm.clear();
        mockModel(lm, index);
    }

    private List< Integer > indexes_ = null;

    public List<Integer> getIndexes() 
    {
        if (null == indexes_) 
        {
            indexes_ = new ArrayList<Integer>();
            for (int i= 0; i< involved.length; ++i) indexes_.add(new Integer(involved<i >));
        }
        return indexes_;
    }
}

<zk>
	<window id="win" title="Window" border="normal" width="600px"
			apply="org.zkoss.bind.BindComposer" viewModel="@id('vm') @init('foo.VM')" >
		<grid>
			<rows children="@load(vm.indexes)">
				<template name="children">
					<row>
						<label value="@load(each)" ></label>
						<listbox model="@load(vm.models.get(each))">
							<template name="model">
								<listitem label="@load(each)" ></listitem>
							</template>
						</listbox>
						<button	label="Simulate for Model ${each}"
							    onClick="@command('simulateData', index=each)" ></button>
					</row>
				</template>
			</rows>
		</grid>
    	<separator spacing="100px"></separator>
    	<grid>
    		<rows children= "@load(vm.indexes)">
    			<template name="children">
			    	<row >
			    		<label value="@load(each)"></label>
			    		<vlayout children="@load(vm.models.get(each))">
			    			<template name="children">
				    			<label value="@load(each)"></label>
							</template>
						</vlayout>
					</row>
				</template>		    	
    		</rows>
    	</grid>
	</window>
</zk>

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-06-15 12:49:04 +0800

Seen: 409 times

Last updated: Jun 22 '12

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