Revision history [back]

click to hide/show revision 1
initial version

answered 2016-04-18 11:51:07 +0800

chillworld gravatar image chillworld flag of Belgium

https://github.com/chillw...

I can give a work around for the getting each value of the subsubBean :

public SubBean() {
    strings = new ArrayList<String>() {
        private static final long serialVersionUID = 1L;

        {
            add("One");
            add("Two");
            add("Three");
            add("Four");
            add("Five");
            add("Six");
            add("Seven");
            add("Eight");
            add("Nine");
            add("Ten");
        }
    };
    subSubBeans = new HashMap<String, SubSubBean>() {
        @Override
        public SubSubBean get(Object key) {
            SubSubBean subSubBean = super.get(key);
            if (subSubBean == null) {
                subSubBean = new SubSubBean();
                put((String)key, subSubBean);
            }
            return subSubBean;
        }
    };
}

So actually, I'm overriding the get of the HashMap and put your initializing code there.

Like this you could use the EL expressions in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" hflex="1" />

And that problem could be solved.
For the formStatus I don't have the answer yet.

Greetz Chill.

I can give a work around for the getting each value of the subsubBean :

public SubBean() {
    strings = new ArrayList<String>() {
        private static final long serialVersionUID = 1L;

        {
            add("One");
            add("Two");
            add("Three");
            add("Four");
            add("Five");
            add("Six");
            add("Seven");
            add("Eight");
            add("Nine");
            add("Ten");
        }
    };
    subSubBeans = new HashMap<String, SubSubBean>() {
        @Override
        public SubSubBean get(Object key) {
            SubSubBean subSubBean = super.get(key);
            if (subSubBean == null) {
                subSubBean = new SubSubBean();
                put((String)key, subSubBean);
            }
            return subSubBean;
        }
    };
}

So actually, I'm overriding the get of the HashMap and put your initializing code there.

Like this you could use the EL expressions in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" hflex="1" />

And that problem could be solved.
For the formStatus I don't have the answer yet.

Greetz Chill.

I can give a work around for the getting each value of the subsubBean :

public SubBean() {
    strings = new ArrayList<String>() {
        private static final long serialVersionUID = 1L;

        {
            add("One");
            add("Two");
            add("Three");
            add("Four");
            add("Five");
            add("Six");
            add("Seven");
            add("Eight");
            add("Nine");
            add("Ten");
        }
    };
    subSubBeans = new HashMap<String, SubSubBean>() {
        @Override
        public SubSubBean get(Object key) {
            SubSubBean subSubBean = super.get(key);
            if (subSubBean == null) {
                subSubBean = new SubSubBean();
                put((String)key, subSubBean);
            }
            return subSubBean;
        }
    };
}

So actually, I'm overriding the get of the HashMap and put your initializing code there.

Like this you could use the EL expressions in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" hflex="1" />

For the formStatus I formStatus, I inspected a little deeper.
First of all, I added a command with the onChange and passed the form status to the viewmodel.
Like this I could inspect if the form status was updated correctly or not.
I know it looks strange but take in mind that if the binder
don't get notified, your status is also never updated.
The result is that the dirty status is correct. => so the binder isn't notified.

So a temp workaround :

@Command
public void change(@BindingParam("proxy")Form form) {
    System.out.println(form.getFormStatus().isDirty());
    BindUtils.postNotifyChange(null, null, form.getFormStatus(), ".");
}

and in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" onChange="@command('change', proxy = fx)" hflex="1" />

I hope this can help you, I know it's pitty you have the answer yet.to send the fx to your viewmodel.

Greetz Chill.

I can give a work around for the getting each value of the subsubBean :

public SubBean() {
    strings = new ArrayList<String>() {
        private static final long serialVersionUID = 1L;

        {
            add("One");
            add("Two");
            add("Three");
            add("Four");
            add("Five");
            add("Six");
            add("Seven");
            add("Eight");
            add("Nine");
            add("Ten");
        }
    };
    subSubBeans = new HashMap<String, SubSubBean>() {
        @Override
        public SubSubBean get(Object key) {
            SubSubBean subSubBean = super.get(key);
            if (subSubBean == null) {
                subSubBean = new SubSubBean();
                put((String)key, subSubBean);
            }
            return subSubBean;
        }
    };
}

So actually, I'm overriding the get of the HashMap and put your initializing code there.

Like this you could use the EL expressions in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" hflex="1" />

For the formStatus, I inspected a little deeper.
First of all, I added a command with the onChange and passed the form status to the viewmodel.
Like this I could inspect if the form status was updated correctly or not.
I know it looks strange but take in mind that if the binder don't get notified, your status is also never updated.
The result is that the dirty status is correct. => so the binder isn't notified.

So a temp workaround :

@Command
public void change(@BindingParam("proxy")Form form) {
    System.out.println(form.getFormStatus().isDirty());
    BindUtils.postNotifyChange(null, null, form.getFormStatus(), ".");
}

and in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" onChange="@command('change', proxy = fx)" hflex="1" />

I hope this can help you, I know it's pitty you have to send the fx to your viewmodel.

Update:

Looks like I was a little to fast.
The first problem is resolved, but only when you mark the method getSubSubBeans @Immutable, otherwise you will never get in your get method.

Now the second problem can't(yet) be fixed when the @Immutable is on the getter.
If you go back to the previous with getSubSubBean(each) and remove the @Immutable => the solution will work perfect, but the first issue is back.

I'll be looking for a whole solution, maybe the best to fill the map directly with the possible values.

Greetz Chill.

I can give a work around for the getting each value of the subsubBean :

public SubBean() {
    strings = new ArrayList<String>() {
        private static final long serialVersionUID = 1L;

        {
            add("One");
            add("Two");
            add("Three");
            add("Four");
            add("Five");
            add("Six");
            add("Seven");
            add("Eight");
            add("Nine");
            add("Ten");
        }
    };
    subSubBeans = new HashMap<String, SubSubBean>() {
        @Override
        public SubSubBean get(Object key) {
            SubSubBean subSubBean = super.get(key);
            if (subSubBean == null) {
                subSubBean = new SubSubBean();
                put((String)key, subSubBean);
            }
            return subSubBean;
        }
    };
}

So actually, I'm overriding the get of the HashMap and put your initializing code there.

Like this you could use the EL expressions in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" hflex="1" />

For the formStatus, I inspected a little deeper.
First of all, I added a command with the onChange and passed the form status to the viewmodel.
Like this I could inspect if the form status was updated correctly or not.
I know it looks strange but take in mind that if the binder don't get notified, your status is also never updated.
The result is that the dirty status is correct. => so the binder isn't notified.

So a temp workaround :

@Command
public void change(@BindingParam("proxy")Form form) {
    System.out.println(form.getFormStatus().isDirty());
    BindUtils.postNotifyChange(null, null, form.getFormStatus(), ".");
}

and in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" onChange="@command('change', proxy = fx)" hflex="1" />

I hope this can help you, I know it's pitty you have to send the fx to your viewmodel.

Update:

Looks like I was a little to fast.
The first problem is resolved, but only when you mark the method getSubSubBeans @Immutable, otherwise you will never get in your get method.

Now the second problem can't(yet) be fixed when the @Immutable is on the getter.
If you go back to the previous with getSubSubBean(each) and remove the @Immutable => the solution will work perfect, but the first issue is back.

I'll be looking for a whole solution, maybe the best to fill the map directly with the possible values.

Greetz Chill.

I can give a work around for the getting each value of the subsubBean :

public SubBean() {
    strings = new ArrayList<String>() {
        private static final long serialVersionUID = 1L;

        {
            add("One");
            add("Two");
            add("Three");
            add("Four");
            add("Five");
            add("Six");
            add("Seven");
            add("Eight");
            add("Nine");
            add("Ten");
        }
    };
    subSubBeans = new HashMap<String, SubSubBean>() {
        @Override
        public SubSubBean get(Object key) {
            SubSubBean subSubBean = super.get(key);
            if (subSubBean == null) {
                subSubBean = new SubSubBean();
                put((String)key, subSubBean);
            }
            return subSubBean;
        }
    };
}

So actually, I'm overriding the get of the HashMap and put your initializing code there.

Like this you could use the EL expressions in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" hflex="1" />

For the formStatus, I inspected a little deeper.
First of all, I added a command with the onChange and passed the form status to the viewmodel.
Like this I could inspect if the form status was updated correctly or not.
I know it looks strange but take in mind that if the binder don't get notified, your status is also never updated.
The result is that the dirty status is correct. => so the binder isn't notified.

So a temp workaround :

@Command
public void change(@BindingParam("proxy")Form form) {
    System.out.println(form.getFormStatus().isDirty());
    BindUtils.postNotifyChange(null, null, form.getFormStatus(), ".");
}

and in the zul :

<textbox value="@bind(bean.subSubBeans[each].value)" onChange="@command('change', proxy = fx)" hflex="1" />

I hope this can help you, I know it's pitty you have to send the fx to your viewmodel.

Update:

Looks like I was a little to fast.
The first problem is resolved, but only when you mark the method getSubSubBeans @Immutable, otherwise you will never get in your get method.

Now the second problem can't(yet) be fixed when the @Immutable is on the getter.
If you go back to the previous with getSubSubBean(each) and remove the @Immutable => the solution will work perfect, but the first issue is back.

I'll be looking for a whole solution, maybe the best to fill the map directly with the possible values.

Solution :

Oke, after a good night sleep, I had new idea's to try.
First of all, I need to add some kind of warning :
You proxy the map so the get method is also proxied.
By this, it means that the get method actually will never trigger the real get method so putting the code in the Map is a bad idea, and will give problems later on.
Besides that, initializing a bean when the form object is already created => this means that your form object is directly dirty.
In our solution, we don't see it by the problem of notifying the dirty status on deeper objects.
But remember, when a fix for this will come => save button is enabled when you load the page(at least when 1 SubSubBean needed to be created).

Let's go further with the solution :
So somewhere I was thinking the problem could be that the binder see's bean.getSubSubBean(each) as always the same call, therefore calling it just once.
So I did go back to normal Map and moved the getSubSubBean method to the vm.

public SubSubBean getBean(SubBean bean, String key) {
    System.out.println("getting bean");
    SubSubBean subSubBean = bean.getSubSubBeans().get(key);
    if (subSubBean == null) {
        subSubBean = new SubSubBean();
        bean.getSubSubBeans().put((String) key, subSubBean);
    }
    return subSubBean;
}

Oke, this works in combination with the dirty status fix.
Now I'm thinking that this code doesn't belong in the VM, so I need to move it.
As you can see, it's a kind of helper method we created.
So next thing I did is making a helper class.

public final class HelperClass {
    public static Object getBean(SubBean bean, String key) {
        SubSubBean subSubBean = bean.getSubSubBeans().get(key);
        if (subSubBean == null) {
            subSubBean = new SubSubBean();
            bean.getSubSubBeans().put((String) key, subSubBean);
        }
        return subSubBean;
    }
}

Now, the code is a little more separated.
How do we use this in code, well we have 2 options.
Prior ZK 8 we needed a taglib to call this method from a zul.
So start with creating a tld file (WEB-INF/tld):

<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.1" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd">
    <tlib-version>1.0</tlib-version>
    <short-name>helper</short-name>
    <uri>/tld/helper</uri>
    <function>
        <name>getBean</name>
        <function-class>zk.method.template.ref.form.binding.HelperClass</function-class>
        <function-signature>
            java.lang.Object getBean(zk.method.template.ref.form.binding.SubBean bean, java.lang.String key)
        </function-signature>
        <description>
            Return the bean from a proxy object or create a new one.
        </description>
    </function>
</taglib>

and in the zul :

<?taglib uri="/WEB-INF/tld/helper.tld" prefix="help"?>
<textbox value="@bind(help:getBean(bean,each).value)" onChange="@command('change', proxy=fx)" hflex="1" />

Works like a charm.

With ZK8 we have now acces to static method's in the zul, so we don't need the TLD file but we can do this :

<?import class="zk.method.template.ref.form.binding.HelperClass" ?>
<textbox value="@bind(HelperClass.getBean(bean,each).value)" onChange="@command('change', proxy=fx)" hflex="1" />

Remember to set the import, that's really important.

So the both solutions works as you desired.
Hope this work around could fit in your design.

Greetz Chill.

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