I have the following composition in my application:
Here, a document version (DocumentVersion) is composed of many document items (DocItem). There are more relations that are omitted for clarity here.
On the UI side, I have an editor for DocumentVersion hosting a fragment which is a browser for it´s items, as shown below:
The fragment is implemented as an ancestor browser fragment class and a more specialized document item browser which inherits from the previous and is parameterized by the class that is being browsed. The ancestor contains a generic TreeDataGrid component which is then complemented by the appropriate datasource on the descendant class. The data source loader is on the descendant class and it just returns the List contained within the DocumentVersion being edited by the host screen.
CRUD operations with the items are done by actions inside the TreeDataGrid associated with the buttons on its header.
The removal of items is implemented initially by the ancestor browser fragment, which after doing some initial checking, calls the overridden descendant fragment method to do the removal. If the removal is successfully done by the descendant fragment, then the ancestor fragment calls the “refresh” method of the TreeDataGrid to update the UI and the removed item disappears. The descendant fragment performs the removal by calling dataContext.remove(docItem), as show in code below:
@Override
protected boolean removeItem(DocItem item) {
// Removes a document item from the document version being edited
List<DocItem>dois = this.getItems(false);
if (dois.contains(item)) {
this.dataContext.remove(item);
return true;
}
return false;
}
The item removal handler on the ancestor fragment code is shown below (please notice the call to MainTree.refresh after item removal)
@Subscribe("mainTree.remove")
public void onMainTreeRemove(Action.ActionPerformedEvent event) {
// Handle the "remove' command for a document item
E item = this.getCurrentlySelectedItem();
if (item == null){
return;
}
dialogs.createOptionDialog()
.withCaption(messages.getMessage("com.calidus.pdcs.screen.generic/browserMultiEditorFragment.confirmRemove.caption"))
.withMessage(messages.getMessage("com.calidus.pdcs.screen.generic/browserMultiEditorFragment.remove.message"))
.withActions(
new DialogAction(DialogAction.Type.YES)
.withHandler(e -> this.handleRemoveItem(item)), // execute action
new DialogAction(DialogAction.Type.NO)
)
.show();
}
protected void handleRemoveItem(E item){
// Handle the removal of an item
List<E>items = this.getItems(false); // Get items from doc version being edited on host screen
// First, check if there are sub-items
.
.
.
.
// Execute item removal
final E parent = item.getParent();
if (this.removeItem(item)){
.
.
.
// Refresh the document tree
refresh();
}
}
The refresh method is on the ancestor fragment class:
@Named("mainTree.refresh")
protected RefreshAction refresh;
.
.
.
public void refresh(){
// Refresh the tree of document items
this.refresh.execute();
}
Problem: Finally, the problem is that when I call the refresh method for the TreeDataGrid, the item removals inside the dataContext in the host editor screen appear to be reset, as shown below in the “before commit” event handler for the host screen:
As a result of that, the item is not deleted from the data store. If I don´t call the refresh method on the TreeDataGrid, the UI is not updated but the data context stays coherent and the item is removed from data store.
Does the refresh method interact with the data context somehow? Any ideas on that?
The xml for host screen and ancestor and descendant fragments are below:
Host screen:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://jmix.io/schema/ui/window"
caption="msg://docVersionEdit.caption"
focusComponent="form">
<data>
<instance id="docVersionDc"
class="com.calidus.pdcs.entity.documents.DocVersion">
<fetchPlan extends="_base">
<property name="dovDoc" fetchPlan="_base"/>
<property name="dovDois" fetchPlan="_base">
<property name="doiDti" fetchPlan="_base"/>
<property name="doiTkd" fetchPlan="_base"/>
</property>
</fetchPlan>
<loader id="docVersionDl"/>
</instance>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
<screenSettings id="settingsFacet" auto="true"/>
</facets>
<actions>
<action id="windowCommitAndClose" caption="msg:///actions.Ok"
icon="EDITOR_OK"
primary="true"
shortcut="${COMMIT_SHORTCUT}"/>
<action id="windowClose"
caption="msg:///actions.Close"
icon="EDITOR_CANCEL"/>
</actions>
<dialogMode height="600"
width="800"/>
<layout spacing="true" expand="gbDoiBrowserEditor">
<groupBox id="gbDovDetails" outerMargin="false" width="100%">
<form id="form" dataContainer="docVersionDc" width="100%" stylename="small">
<column width="100%">
<textField id="docCodeField" property="dovDoc.docCode" editable="false"/>
<textField id="dovIdField" property="dovId" editable="false"/>
<dateField id="dovCreationDateField" property="dovCreationDate" editable="false"/>
</column>
<column width="100%">
<textField id="docTitleField" property="dovDoc.docTitle" editable="false"/>
<comboBox id="dovLcsField" property="dovLcs" editable="false"/>
<dateField id="dovLastChangeDateField" property="dovLastChangeDate" editable="false"/>
</column>
</form>
</groupBox>
<groupBox id="gbDoiBrowserEditor" outerMargin="false" width="100%" expand="doiBrowserEditor">
<fragment id="doiBrowserEditor" screen="DocItemBrowserEditorFragment" width="100%" responsive="true"/>
</groupBox>
<hbox id="editActions" spacing="true" align="BOTTOM_RIGHT">
<button id="closeBtn" action="windowClose" stylename="small"/>
<button id="commitAndCloseBtn" action="windowCommitAndClose" stylename="small"/>
</hbox>
</layout>
</window>
Ancestor fragment:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<fragment xmlns="http://jmix.io/schema/ui/fragment">
<data>
</data>
<layout width="100%" spacing="false" expand="split">
<split id="split"
orientation="horizontal"
reversePosition="true"
width="100%"
dockable="true"
dockMode="LEFT">
<treeDataGrid id="mainTree"
width="AUTO"
height="100%"
headerVisible="true"
responsive="true">
<actions>
<action id="refresh"
type="refresh"/>
<action id="noCaptionRefresh"
icon="font-icon:REFRESH"/>
<action id="promote"
icon="font-icon:TOGGLE_LEFT"/>
<action id="demote"
icon="font-icon:TOGGLE_RIGHT"/>
<action id="remove"
icon="font-icon:TRASH_O"/>
<action id="moveUp"
icon="font-icon:CHEVRON_UP"/>
<action id="moveDn"
icon="font-icon:CHEVRON_DOWN"/>
</actions>
<columns>
</columns>
<!-- <simplePagination/>-->
<buttonsPanel id="buttonsPanel"
alwaysVisible="true" spacing="false" stylename="small">
<popupButton id="createBtn"
icon="font-icon:PLUS"
stylename="small">
<actions>
</actions>
</popupButton>
<!-- <button id="refreshBtn" action="doiTree.refresh" stylename="small"/>-->
<button id="removeBtn" action="mainTree.remove" stylename="small"/>
<button id="moveUpBtn" action="mainTree.moveUp" stylename="small"/>
<button id="moveDnBtn" action="mainTree.moveDn" stylename="small"/>
<button id="refreshBtn" action="mainTree.noCaptionRefresh" stylename="small"/>
<button id="promoteBtn" action="mainTree.promote" stylename="small"/>
<button id="demoteBtn" action="mainTree.demote" stylename="small"/>
</buttonsPanel>
</treeDataGrid>
<scrollBox id="editSb"
width="100%"
height="100%"
spacing="false"
responsive="true"/>
</split>
</layout>
</fragment>
Descendant fragment:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<fragment xmlns="http://jmix.io/schema/ui/fragment"
caption=""
extends="com/calidus/pdcs/screen/browsermultieditorfragment/browser-multi-editor-fragment.xml">
<data>
<collection id="docItemsDc"
class="com.calidus.pdcs.entity.documents.DocItem">
<fetchPlan extends="_base">
<property name="doiPath"/>
<property name="doiTitle"/>
<property name="doiParent" fetchPlan="_base"/>
<property name="doiDti" fetchPlan="_base"/>
<property name="doiTkd" fetchPlan="_base"/>
</fetchPlan>
<loader id="docItemsDl"/>
</collection>
</data>
<layout>
<split id="split">
<treeDataGrid id="mainTree"
dataContainer="docItemsDc"
hierarchyProperty="doiParent">
<actions>
<action id="createDti"
caption="msg://com.calidus.pdcs.screen.docitem/docItemBrowserEditorFragment.createDti.caption"/>
<action id="createTkd"
caption="msg://com.calidus.pdcs.screen.docitem/docItemBrowserEditorFragment.createTkd.caption"/>
<action id="copyStdTkd"
caption="msg://com.calidus.pdcs.screen.docitem/docItemBrowserEditorFragment.copyStdTkd.caption"/>
</actions>
<columns>
<column id="doiPath" property="doiPath" sort="ASCENDING"/>
<column id="doiTitle" property="doiTitle" sortable="false"/>
</columns>
<buttonsPanel id="buttonsPanel">
<popupButton id="createBtn">
<actions>
<action id="mainTree.createDti"
icon="font-icon:FILE_TEXT"/>
<action id="mainTree.copyStdTkd"
icon="font-icon:CERTIFICATE"/>
<action id="mainTree.createTkd"
icon="font-icon:STICKY_NOTE_O"/>
</actions>
</popupButton>
</buttonsPanel>
</treeDataGrid>
</split>
</layout>
</fragment>
Thanks in advance.