I'm having a problem with ZK binding and drag and drop feature.
I have two listboxes:
<listbox id="left" width="100%" model="#load(vm.contacts)" height="200px" draggable="true" droppable="true" onDrop="#command('move')">
<listhead>
<listheader label="Contatto" align="center" />
</listhead>
<template name="model" var="contact">
<listitem value="#bind(contact)" draggable="true" droppable="true" onDrop="#command('move')">
<listcell src="/img/contact-icon_x32.jpg" label="#load(contact.person.surname.concat(' ').concat(contact.person.name))" />
</listitem>
</template>
</listbox>
...
<listbox width="100%" id="right" model="#load(vm.contactsQuickKey)" height="250px" draggable="true" droppable="true" onDrop="#command('move')" >
<listhead>
<listheader label="Etichetta" align="center" />
<listheader label="Contatto" align="center" />
</listhead>
<template name="model" var="contactQuickKey">
<listitem value="#bind(contactQuickKey)" draggable="true" droppable="true" onDrop="#command('move')">
<listcell>
<textbox width="90%" value="#load(contactQuickKey.label) #save(contactQuickKey.label, before={'move', 'saveData', 'setLeftActivePage'})"/>
</listcell>
<listcell src="/img/contact-icon_x32.jpg" label="#load(contactQuickKey.contact.person.surname.concat(' ').concat(contactQuickKey.contact.person.name))" />
</listitem>
</template>
</listbox>
If I edit the textbox in the right listbox and then immediately, without clicking anywhere, I drag and drop a cell from the left one, the text I added disappears.
The only way I can save the text is to use an onchange event, but it is very heavy.
EDIT:
I created a working demo here http://zkfiddle.org/sample/2t6r27o/24-drag-and-drop-test
Does anyone can give me a better solution?
Thank you very much!
SOLUTION
I added the "instant="true"" to the textbox and this solved my problem!
Thanks to all of you how helped me!
The solution is to put the instant="true" to the textbox. This solved the problem of losing text modification with a drag and drop.
Your problem is, that your text ist not loaded into the serverside Textbox.
You save before drop by before={'move'... but you can't load it into
the Textbox, cos this needs a notifyChange, which is fullfilled before
#command('move') is executed and this is not possible, cos of the zk
execution cycle and the fact that move causes the save
What you could do is, chage the Textbox manually from the data in your
vm class at the move command. But it could maybe a problem to figure out
to which instance of contactQuickKey the dragged Textbox belongs.
By the way, where is the problem with onChanging? The traffic shouldn't be one.
Edit
For some reason the data is not saved before the move command, if
not another user action occurs before the drag.
Maybe a bug?
Related
For the file browser that I'm trying to make I need a navigator with breadcrumb style. I found some example using <forEach> tag that isn't included into the community edition. The Questions are:
Is there a way to render a dynamic text/anchor (link) like bread crumb? Or is there a way to overwrite some <div id="someContainer" /> so the div as placeholder can be write with some children in MVVM way?
So the breadcrumb will have an action when the link is click. When the link is clicked it must update the content of another ListModelList object and update itself if the previous crumb is clicked. How can I do that in MVVM style?
Fiddle example but using shadow component <forEach> https://zkfiddle.org/sample/ha19l0/1-zk-breadcrumbs
Some zul code:
<zk>
<window apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('com.my.zk.mvvm.MyFilesViewModel')">
<hlayout>
<listbox vflex="true" hflex="1" model="#load(vm.files)"
id="fileBrowser" selectedItem="#bind(vm.selectedFile)">
<auxhead>
<auxheader colspan="3">File List</auxheader>
<auxheader colspan="3">
<hlayout>
<!-- breadcrumb, implemented later -->
<div id="placeHolder" />
</hlayout>
</auxheader>
</auxhead>
<listhead>
<listheader label="Name" />
<listheader label="Size" />
<listheader label="Modified" />
</listhead>
<template name="model" var="file">
<!-- This is the model that need to be updated when bredcrumb is clicked -->
<listitem>
<listcell label="#load(file.name)" />
<listcell label="#load(file.length())" />
<listcell label="#load(file.lastModified())" />
</listitem>
</template>
</listbox>
</hlayout>
<separator />
</window>
</zk>
Thanks for the help.
in CE you can use children binding which has a less intuitive syntax, and works less efficient (however not significant in case of breadcrumbs)
Here the updated example.
<hlayout style="border:2px black solid;" children="#load(vm.breadcrumbs)">
<template name="children">
<hlayout>
<nodom if="${each ne vm.currentPage}">
<label style="text-decoration: underline blue; cursor:pointer;" value="${each.label}"
onClick="#command('navigateToPage', page=each)" />
<label value=" > "/>
</nodom>
<label if="${each eq vm.currentPage}" style="font-weight: bold;" value="${each.label}"/>
</hlayout>
</template>
</hlayout>
A children binding is added to the parent and will iterate over the items in the collection using the <template name="children">, <choose>/<when> can be replaced by the static if attribute. Even if static, the expression will evaluate again when the children are re-rendered (so it's kind of dynamic).
In the view model you have to notify change the breadCrumbs property which will then re-render all children. (Since it's only a few elements the impact shouldn't be significant)
Please see my code below. I want to set lbProduct independently when they are not same.
I know that this code
page.setAttribute("snProductList", rmProductList);
can set it, but only when they all same.
How can I set them independently in Java code when they are not same?
<listbox id="lbSnList" rows="10" fixedLayout="false" width="100%" model="#{uploadSnVo}" >
<listitem self="#{each=SN}" style="#{SN.BACKGROUND}">
<listcell label="#{SN.SERIAL_NO}" />
<listcell>
<listbox id = "lbProduct" hflex="1" mold="select" selectedItem="#{SN.PRODUCT}">
<listitem forEach="${snProductList}" label="${each.name}" value="${each.value}" />
</listbox>
</listcell>
<listcell>
<checkbox id="cbCid" checked="#{SN.CH_GFLAG}" disabled="true" />
</listcell>
</listitem>
</listbox>
I am a user of JSF and Richfaces. I will simplify the code about my question to make things easier.
I have a composition named 'mytab.xhtml' defined like following:
<cc:interface>
<cc:attribute name="header" required="true"/>
</cc:interface>
<cc:implementation>
<rich:tab id="my-tab" header="#{cc.attrs.header}" >
<cc:insertChildren />
</rich:tab>
</cc:implementation>
This composition is used in another xhtml file like following:
<rich:tabPanel id="tp" switchType="ajax" headerPosition="top" >
<ic:mytab id="tab1" header="header1">
<h:outputText>content1</h:outputText>
</ic:mytab>
<ic:mytab id="tab2" header="header2">
<h:outputText>content1</h:outputText>
</ic:mytab>
</rich:tabPanel>
But it is very strange that the tab is not rendered at all.
To find the reason, if I add an outputText in the composition definition file like this:
<cc:interface>
<cc:attribute name="header" required="true"/>
</cc:interface>
<cc:implementation>
<h:outputText>#{cc.attrs.header}</h:outputText>
<rich:tab id="my-tab" header="#{cc.attrs.header}" >
<cc:insertChildren />
</rich:tab>
</cc:implementation>
The outputText will be rendered, but tab is not rendered.
Or, if I change one of the tab to richfaces tab directly:
<rich:tabPanel id="tp" switchType="ajax" headerPosition="top" >
<ic:mytab id="tab1" header="header1">
<h:outputText>content1</h:outputText>
</ic:mytab>
<rich:tab id="tab2" header="header2">
<h:outputText>content1</h:outputText>
</rich:tab>
</rich:tabPanel>
The first tab will not be rendered, but the second tab will be rendered.
Thank you if you could give me any help.
Composite components are rendered as own UINamingContainer. So between the UITabPanel and the UITab-component now is a UINamingContainer, UITab might not know what to do with it (same problem with datatable, by the way). What you can do is to use a classic facelet tag instead.
I have created a MyGroupModelList class by extending the AbstractGroupsModel class. I want first group present in MyGroupModelList should be expanded and remaining all other groups should be collapsed.
On the viewModel I have written Below.
private MyGroupModelList <TabData> summaryGroupModel;
#AfterCompose
public void afterCompose(#ContextParam(ContextType.VIEW) Component view){
summaryGroupModel = getSummaryTabData(folderRSN);
if (summaryGroupModel != null && summaryGroupModel.getGroupCount() > 0) {
summaryGroupModel.addOpenGroup(0);
}
On the ZUL have written Below.
<zk>
<window width="100%" height="100%"
apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('com.test.MyGroupModelList ')">
<listbox model="#bind(vm.summaryGroupModel.groupModel)">
<listhead>
<listheader label="Bill Number"></listheader>
<listheader label="Bill Amount"></listheader>
</listhead>
<template name="model" var="Data">
<listitem>
<listcell>
<label value="#load(Data.billNumber)" />
</listcell>
<listcell>
<label value="#load(Data.billAmount)" />
</listcell>
</listitem>
</template>
</listbox>
</window>
</zk>
Above code is not expanding first group present in MyGroupModelList.
Please help
I have created a sample demo example for this expand-first-groupbox-and-collapse
Or you can check this live demo code in Zk fiddle
So, I want to add a specific component (either Checkbox or Textbox) depending on the AttType field of my current node. My zul file looks like this:
<tree id="permissionTree" width="100%"
model="#bind(vm.treeModel)" style="text-align:left;">
<treecols>
<treecol label="Item" width="400px" />
<treecol label="Wert" />
</treecols>
<template name="model" var="node">
<treeitem>
<treerow>
<treecell label="#load(node.data.name)" />
<treecell> HERE COMPONENT DEPENDING ON node.data.AttType </treecell>
</treerow>
</treeitem>
</template>
</tree>
How can I accomplish this? Oh and I want the Textbox/Checkbox value to be bound to my model as a String, that would be pretty nice.
Thanks for any suggestions.
Edit: I made a little "workaround" for myself. Since I have only 3 possible input types, I just defined them hard-coded:
<tree id="permissionTree" width="100%"
model="#bind(vm.treeModel)" style="text-align:left;">
<treecols>
<treecol label="Item" />
<treecol label="Wert" />
</treecols>
<template name="model" var="node">
<treeitem open="#bind(node.open)" onClick="#command('expandNode', item=node)">
<treerow>
<treecell label="#load(node.data.name)" />
<treecell>
<textbox visible="#load(node.data.isTextbox)" value="#bind(node.data.value)" />
<textbox visible="#load(node.data.isTextarea)" rows="6" width="300px" value="#bind(node.data.value)" />
<checkbox visible="#load(node.data.isCheckbox)" checked="#bind(node.data.checkboxValue)" />
</treecell>
</treerow>
</treeitem>
</template>
</tree>
And in the constructor of a TreeNode I set the isTextbox/isTextarea/isCheckbox values according to the type. This way the model binding still works :)
As you asked in your previous question: use treeitem renderer and add items you need there. I don't think binding will work for new components.