0

@DependsOn requires to keep listbox selection twice

asked 2014-11-18 15:07:02 +0800

Matze2 gravatar image Matze2
773 7

updated 2014-11-18 15:17:02 +0800

Consider a typical page with toolbarbuttons and a listbox. The "disabled" state of the toolbarbuttons depends on listbox selection.

Up to now I always bound selectedItems to a view model property so we have the following ZUL fragment:

<toolbarbutton ... disabled="@load(vm.action1Disabled)" onClick="@command('action1')"/>
...
<listbox ... model="@load(vm.listModel)" selectedItems="@bind(vm.selectedEntries)">
    ...
</listbox>

The "disabled" state was recalculated when the selection changes using @DependsOn annotation on the property:

@DependsOn("selectedEntries")
public boolean isAction1Disabled() {
    // Compute state from selectedEntries and other data
}

This is how we did it up to now. On the other hand we use ListModelList as listbox model and this also keeps the selection state. So I wonder why I should maintain this state twice: once in ViewModel and once in listbox model. Just to be able to create property dependency on selectedEntries?

Does anybody know an elegant (MVVM) way to notify the change of selection-dependent properties just with the ListModelList selection and without having an explicit selection binding?

E.g. if the ListModelList selection change would be notified to the binder the following annotation could work:

@DependsOn("listModel.selection")
public boolean isAction1Disabled() {
    // Compute state from selectedEntries and other data
}
delete flag offensive retag edit

1 Answer

Sort by ยป oldest newest most voted
1

answered 2014-11-19 16:02:44 +0800

cyiannoulis gravatar image cyiannoulis
1201 10

The problem is that the toolbarbutton has to be notified either with a @DependsOn or with a @NotifyChange trigger. If you want to eliminate the second list (vm.selectedEntries) from your view model you may use a workaround like the following one:

<window title="Listbox with multiple selections" 
        apply="org.zkoss.bind.BindComposer"
        viewModel="@id('vm') @init('snippets.listboxSelections.LboxVM')" 
        border="none">

    <toolbar>
        <toolbarbutton label="@load(vm.hasSelections ? 'OK' : 'Nothing selected')" 
                   disabled="@load(!vm.hasSelections)" />
    </toolbar>

    <listbox model="@load(vm.listData)" 
             multiple="true" checkmark="true"
             onSelect="@command('items-selected')">

        <listhead>
            <listheader label="Star Wars" />
        </listhead>
        <template name="model" var="person">
            <listitem label="@load(person)" />  
        </template>
    </listbox>

</window>

And the VM:

public class LboxVM {

    private ListModelList<String> listData;

    @Init
    public void init() {

      String[] data = {"Luke Skywalker ", "Darth Vader", "Obi-Wan Kenobi", "Joda"};
      listData = new ListModelList<String>( Arrays.asList(data) );
    }

    @Command("items-selected")
    @NotifyChange("hasSelections")
    public void onItemsSelected() {};

    public boolean getHasSelections() {
        return !listData.getSelection().isEmpty();
    }

    public ListModelList<String> getListData() {
        return listData;
    }

    public void setListData(ListModelList<String> listData) {
        this.listData = listData;
    }
}

As you see the Command("items-selected") is implemented only because we need to make a @NotifyChange back to the status of the toolbarbutton.

Hope that helps

Costas

link publish delete flag offensive edit

Comments

Thanks, Costas. This is one of the possibilities I also had in mind. The other one is to add a ListDataListener on the ListModelList and react on ListDataEvent.SELECTION_CHANGED by calling notifyChange similar to your solution. Both variants do not seem to me really "elegant" :).

Matze2 ( 2014-11-19 16:06:21 +0800 )edit

To make it even more dirty. I wonder if the getHasSelections method is really needed because there would be only the @DependsOn referencing it.

Matze2 ( 2014-11-19 16:11:42 +0800 )edit

Anyway. Thanks for the answer. It is no what I was expecting but definitely a worth a "thumbs up".

Matze2 ( 2014-11-19 16:12:49 +0800 )edit

Thanks mate. I wish i had a more elegant solution.

cyiannoulis ( 2014-11-19 16:17:02 +0800 )edit

Just FYI: I just tried to make a @NotifyChange on a non-existing property just to "fire" a corresponding @DependsOn. It does not work: org.zkoss.zel.PropertyNotFoundException: Property 'notExist' not found on type com.camline.webui.general.custfield.CustFieldValuesVM

Matze2 ( 2014-11-25 16:35:40 +0800 )edit
Your answer
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
1 follower

RSS

Stats

Asked: 2014-11-18 15:07:02 +0800

Seen: 11 times

Last updated: Nov 19 '14

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