In-line edit in table view

Hi
I am wondering if it is possible to edit inside the table in CUBA? If yes, can I also using other components ?

1 Like

Hello,
I’ve created a simple project with an editable Table. It is not true inline edit because all rows are always editable, but you can use it if you need to edit data in Table without additional windows. Just unzip the archive and import the project to CUBA Studio.

editable-table.zip (81.0 KB)

Thank you. I shall come back to you if I have any question or comments.

Hi
It looks good and works well. I hope you guys are working on to improve it in future.

Thank you so much for taking your time to create this example apps. It really helps.

1 Like

Another option is to unwrap your table to expose it as a Vaadin table. Once the table is unwrapped, you have full functionality of the Vaadin table and make it truly editable.

Hi
I am trying to use the first option in a master-detail screen. In his example, i have master table called BillOfMaterial and detail table called BillOfMaterialLines. I have customized the actions in the controller of BillOfMaterial and the buttons inserts/removes rows but I can’t edit the rows in the detail table. Thanks for any help.

inteaccgms$BillOfMaterial.browse


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://browseCaption"
        class="com.inteacc.gms.gui.billofmaterial.BillOfMaterialBrowse"
        focusComponent="billOfMaterialsTable"
        lookupComponent="billOfMaterialsTable"
        messagesPack="com.inteacc.gms.gui.billofmaterial">
    <dsContext>
        <collectionDatasource id="billOfMaterialsDs"
                              class="com.inteacc.gms.entity.BillOfMaterial"
                              view="billOfMaterial-view">
            <query>
                <![CDATA[select e from inteaccgms$BillOfMaterial e]]>
            </query>
        </collectionDatasource>
    </dsContext>
    <layout expand="billOfMaterialsTable"
            spacing="true">
        <filter id="filter"
                applyTo="billOfMaterialsTable"
                datasource="billOfMaterialsDs">
            <properties include=".*"/>
        </filter>
        <table id="billOfMaterialsTable"
               width="100%">
            <actions>
                <action id="create"/>
                <action id="edit"/>
                <action id="remove"/>
            </actions>
            <columns>
                <column id="bomId"/>
                <column id="name"/>
                <column id="article"/>
                <column id="baseQuantity"/>
                <column id="active"/>
                <column id="rejectPercentage"
                        caption="Reject Percent"/>
            </columns>
            <rows datasource="billOfMaterialsDs"/>
            <rowsCount/>
            <buttonsPanel id="buttonsPanel"
                          alwaysVisible="true">
                <button id="createBtn"
                        action="billOfMaterialsTable.create"/>
                <button id="editBtn"
                        action="billOfMaterialsTable.edit"/>
                <button id="removeBtn"
                        action="billOfMaterialsTable.remove"/>
            </buttonsPanel>
        </table>
    </layout>
</window>

inteaccgms$BillOfMaterial.edit


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://editCaption"
        class="com.inteacc.gms.gui.billofmaterial.BillOfMaterialEdit"
        datasource="billOfMaterialDs"
        messagesPack="com.inteacc.gms.gui.billofmaterial">
    <dsContext>
        <datasource id="billOfMaterialDs"
                    class="com.inteacc.gms.entity.BillOfMaterial"
                    view="billOfMaterial-view">
            <collectionDatasource id="billOfMaterialLinesDs"
                                  property="billOfMaterialLines"/>
        </datasource>
    </dsContext>
    <layout expand="windowActions"
            spacing="true">
        <fieldGroup id="fieldGroup"
                    datasource="billOfMaterialDs">
            <column>
                <field id="bomId"
                       width="250px"/>
                <field id="name"
                       width="400px"/>
                <field id="article"
                       width="400px"/>
                <field id="baseQuantity"
                       width="250px"/>
                <field id="active"
                       width="250px"/>
                <field id="rejectPercentage"
                       caption="Reject Percentage"
                       width="100px"/>
            </column>
        </fieldGroup>
        <groupBox id="billOfMaterialLinesBox"
                  caption="msg://com.inteacc.gms.entity/BillOfMaterial.billOfMaterialLines">
            <table id="billOfMaterialLinesTable"
                   editable="true"
                   height="200px"
                   width="100%">
                <actions>
                    <action id="add"
                            invoke="onAdd"/>
                    <action id="remove"
                            invoke="onRemove"/>
                    <action id="save"
                            invoke="onSave"/>
                </actions>
                <columns>
                    <column id="material"/>
                    <column id="quantity"/>
                    <column id="wastageRate"/>
                </columns>
                <rows datasource="billOfMaterialLinesDs"/>
                <rowsCount/>
                <buttonsPanel>
                    <button id="add"
                            action="billOfMaterialLinesTable.add"
                            caption="Add"
                            invoke="onAddClick"/>
                    <button id="remove"
                            action="billOfMaterialLinesTable.remove"
                            caption="Remove"/>
                    <button id="save"
                            action="billOfMaterialLinesTable.save"
                            caption="Save"/>
                </buttonsPanel>
            </table>
        </groupBox>
        <frame id="windowActions"
               screen="editWindowActions"/>
    </layout>
</window>

Controller of BillOfMaterialEdit


/*
 * Copyright (c) 2016 inteaccgms
 */
package com.inteacc.gms.gui.billofmaterial;

import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.gui.components.AbstractEditor;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.inteacc.gms.entity.BillOfMaterial;
import com.inteacc.gms.entity.BillOfMaterialLines;
import org.apache.commons.lang.StringUtils;

import javax.inject.Inject;
import java.util.UUID;
import com.haulmont.cuba.gui.components.Component;

/**
 * @author Mortoza
 */
public class BillOfMaterialEdit extends AbstractEditor<BillOfMaterial> {


    @Inject 
    private CollectionDatasource<BillOfMaterialLines, UUID> billOfMaterialLinesDs;
 
    @Inject 
    private Metadata metadata; 
    public void onAdd() {
        billOfMaterialLinesDs.addItem(metadata.create(BillOfMaterialLines.class));
    } 
 
    public void onRemove() {
        if (billOfMaterialLinesDs.getItem() != null) {
            billOfMaterialLinesDs.removeItem(billOfMaterialLinesDs.getItem());
        } 
    }

    public void onSave() {
        if (validateAll()) { 
            getDsContext().commit(); 
            showNotification(getMessage("changesSaved"), NotificationType.HUMANIZED); 
        } 
    } 
 
    @Override 
    public boolean validateAll() { 
        for (BillOfMaterialLines task : billOfMaterialLinesDs.getItems()) {
//            if (task.getMaterial() == null
//                    || StringUtils.isEmpty(task.getQuantity())) {
            if (task.getMaterial() == null) {

                showNotification(getMessage("fillRequiredFields"), NotificationType.TRAY); 
 
 
                return false; 
            } 
        } 
        return super.validateAll(); 
    } 
    

}

Hi,
you should set editable to true for columns of billOfMaterialLinesTable. By default columns are non editable.
Please see https://doc.cuba-platform.com/manual-6.0/gui_Table.html#gui_Table_editable.

Hi
Yes, I did that.n But still didn’t work, anything else I should check?


  <groupBox id="billOfMaterialLinesBox" 
                  caption="msg://com.inteacc.gms.entity/BillOfMaterial.billOfMaterialLines"> 
            <table id="billOfMaterialLinesTable" 
                   editable="true" 
                   height="200px" 
                   width="100%"> 

Could you please paste full updated version of XML with billOfMaterialLinesTable? It seems that you’ve pasted only table without columns. You should add editable = “true” for all columns that you want to edit.

Hi
I am append below another set of files since I had to use the BillOfMaterial files for some other testing.

inventoryissueprod-browse


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://browseCaption"
        class="com.inteacc.gms.gui.inventoryissueprod.InventoryIssueProdBrowse"
        focusComponent="inventoryIssueProdsTable"
        lookupComponent="inventoryIssueProdsTable"
        messagesPack="com.inteacc.gms.gui.inventoryissueprod">
    <dsContext>
        <collectionDatasource id="inventoryIssueProdsDs"
                              class="com.inteacc.gms.entity.InventoryIssueProd"
                              view="inventoryIssueProd-view">
            <query>
                <![CDATA[select e from inteaccgms$InventoryIssueProd e]]>
            </query>
        </collectionDatasource>
    </dsContext>
    <layout expand="inventoryIssueProdsTable"
            spacing="true">
        <filter id="filter"
                applyTo="inventoryIssueProdsTable"
                datasource="inventoryIssueProdsDs">
            <properties include=".*"/>
        </filter>
        <table id="inventoryIssueProdsTable"
               width="100%">
            <actions>
                <action id="create"/>
                <action id="edit"/>
                <action id="remove"/>
            </actions>
            <columns>
                <column id="issueDate"/>
                <column id="warehouseFrom"/>
                <column id="factoryTo"/>
                <column id="salesOrderReference"/>
            </columns>
            <rows datasource="inventoryIssueProdsDs"/>
            <rowsCount/>
            <buttonsPanel id="buttonsPanel"
                          alwaysVisible="true">
                <button id="createBtn"
                        action="inventoryIssueProdsTable.create"/>
                <button id="editBtn"
                        action="inventoryIssueProdsTable.edit"/>
                <button id="removeBtn"
                        action="inventoryIssueProdsTable.remove"/>
            </buttonsPanel>
        </table>
    </layout>
</window>

inventoryissueprod-edit


<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
        caption="msg://editCaption"
        class="com.inteacc.gms.gui.inventoryissueprod.InventoryIssueProdEdit"
        datasource="inventoryIssueProdDs"
        focusComponent="fieldGroup"
        messagesPack="com.inteacc.gms.gui.inventoryissueprod">
    <dsContext>
        <datasource id="inventoryIssueProdDs"
                    class="com.inteacc.gms.entity.InventoryIssueProd"
                    view="inventoryIssueProd-view">
            <collectionDatasource id="linesDs"
                                  property="lines"/>
        </datasource>
    </dsContext>
    <layout expand="windowActions"
            spacing="true">
        <fieldGroup id="fieldGroup"
                    datasource="inventoryIssueProdDs">
            <column width="250px">
                <field id="issueDate"/>
                <field id="warehouseFrom"/>
                <field id="factoryTo"/>
                <field id="salesOrderReference"/>
            </column>
        </fieldGroup>
        <groupBox id="linesBox"
                  caption="msg://com.inteacc.gms.entity/InventoryIssueProd.lines">
            <table id="linesTable"
                   height="200px"
                   width="100%">
                <actions>
                    <action id="add"
                            caption="Add"
                            invoke="onAdd"/>
                    <action id="save"
                            caption="Save"
                            invoke="onSave"/>
                    <action id="remove"
                            caption="Remove"
                            invoke="onRemove"/>
                    <action id="edit"
                            caption="Edit"
                            invoke="onEdit"/>
                </actions>
                <columns>
                    <column id="material"
                            editable="true"/>
                    <column id="quantity"
                            editable="true"/>
                </columns>
                <rows datasource="linesDs"/>
                <buttonsPanel>
                    <button id="addbtn"
                            action="linesTable.add"/>
                    <button id="savebtn"
                            action="linesTable.save"/>
                    <button id="removebtn"
                            action="linesTable.remove"/>
                    <button id="editbtn"
                            action="linesTable.edit"/>
                </buttonsPanel>
            </table>
        </groupBox>
        <frame id="windowActions"
               screen="editWindowActions"/>
    </layout>
</window>

controller


/*
 * Copyright (c) 2016 inteaccgms
 */
package com.inteacc.gms.gui.inventoryissueprod;

import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.gui.components.AbstractEditor;
import com.inteacc.gms.entity.InventoryIssueProd;
import java.util.UUID;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.inteacc.gms.entity.InventoryIssueProdLines;

import javax.inject.Inject;

/**
 * @author Mortoza
 */
public class InventoryIssueProdEdit extends AbstractEditor<InventoryIssueProdLines> {
    @Inject
    private CollectionDatasource<InventoryIssueProdLines, UUID> linesDs;

    @Inject
    private Metadata metadata;
    public void onAdd() {
        linesDs.addItem(metadata.create(InventoryIssueProdLines.class));
    }
    public void onRemove() {
        if (linesDs.getItem() != null) {
            linesDs.removeItem(linesDs.getItem());
        }
    }
    public void onEdit() {
        if (linesDs.getItem() != null) {
            linesDs.updateItem(linesDs.getItem());
        }
    }

    public void onSave() {
        if (validateAll()) {
            getDsContext().commit();
            showNotification(getMessage("changesSaved"), NotificationType.HUMANIZED);
        }
    }
    
    
    @Override
    public boolean validateAll() {
        for (InventoryIssueProdLines task : linesDs.getItems()) {
//            if (task.getMaterial() == null
//                    || StringUtils.isEmpty(task.getQuantity())) {
            if (task.getMaterial() == null) {
                showNotification(getMessage("fillRequiredFields"), NotificationType.TRAY);
                return false;
            }
        }
        return super.validateAll();
    }
}

i guess the edit function also needs a fix.

This is behaving the same, i can delete a line but when i want to add, it inserts a row but the row is not editable. Also let me know how can i set a row editable.

Here is the entities


/*
 * Copyright (c) 2016 inteaccgms
 */
package com.inteacc.gms.entity;

import javax.persistence.Entity;
import javax.persistence.Table;
import com.haulmont.chile.core.annotations.Composition;
import com.haulmont.cuba.core.entity.annotation.OnDelete;
import com.haulmont.cuba.core.global.DeletePolicy;
import java.util.Date;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.haulmont.cuba.core.entity.StandardEntity;
import com.haulmont.chile.core.annotations.NamePattern;

/**
 * @author Mortoza
 */
@NamePattern("%s %s|issueDate,warehouseFrom")
@Table(name = "INTEACCGMS_INVENTORY_ISSUE_PROD")
@Entity(name = "inteaccgms$InventoryIssueProd")
public class InventoryIssueProd extends StandardEntity {
    private static final long serialVersionUID = 537703982522792667L;

    @Temporal(TemporalType.DATE)
    @Column(name = "ISSUE_DATE", nullable = false)
    protected Date issueDate;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "WAREHOUSE_FROM_ID")
    protected Warehouse warehouseFrom;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "FACTORY_TO_ID")
    protected Factory factoryTo;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "SALES_ORDER_REFERENCE_ID")
    protected SalesOrder salesOrderReference;

    @Composition
    @OnDelete(DeletePolicy.CASCADE)
    @OneToMany(mappedBy = "inventoryIssueProd")
    protected Set<InventoryIssueProdLines> lines;

    public void setIssueDate(Date issueDate) {
        this.issueDate = issueDate;
    }

    public Date getIssueDate() {
        return issueDate;
    }

    public void setWarehouseFrom(Warehouse warehouseFrom) {
        this.warehouseFrom = warehouseFrom;
    }

    public Warehouse getWarehouseFrom() {
        return warehouseFrom;
    }

    public void setFactoryTo(Factory factoryTo) {
        this.factoryTo = factoryTo;
    }

    public Factory getFactoryTo() {
        return factoryTo;
    }

    public void setSalesOrderReference(SalesOrder salesOrderReference) {
        this.salesOrderReference = salesOrderReference;
    }

    public SalesOrder getSalesOrderReference() {
        return salesOrderReference;
    }

    public void setLines(Set<InventoryIssueProdLines> lines) {
        this.lines = lines;
    }

    public Set<InventoryIssueProdLines> getLines() {
        return lines;
    }


}

/*
 * Copyright (c) 2016 inteaccgms
 */
package com.inteacc.gms.entity;

import javax.persistence.Entity;
import javax.persistence.Table;
import java.math.BigDecimal;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import com.haulmont.cuba.core.entity.StandardEntity;
import com.haulmont.chile.core.annotations.NamePattern;

/**
 * @author Mortoza
 */
@NamePattern("%s|material")
@Table(name = "INTEACCGMS_INVENTORY_ISSUE_PROD_LINES")
@Entity(name = "inteaccgms$InventoryIssueProdLines")
public class InventoryIssueProdLines extends StandardEntity {
    private static final long serialVersionUID = 71825293914329238L;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "MATERIAL_ID")
    protected Material material;

    @Column(name = "QUANTITY", nullable = false)
    protected BigDecimal quantity;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "INVENTORY_ISSUE_PROD_ID")
    protected InventoryIssueProd inventoryIssueProd;

    public void setInventoryIssueProd(InventoryIssueProd inventoryIssueProd) {
        this.inventoryIssueProd = inventoryIssueProd;
    }

    public InventoryIssueProd getInventoryIssueProd() {
        return inventoryIssueProd;
    }


    public void setMaterial(Material material) {
        this.material = material;
    }

    public Material getMaterial() {
        return material;
    }

    public void setQuantity(BigDecimal quantity) {
        this.quantity = quantity;
    }

    public BigDecimal getQuantity() {
        return quantity;
    }

}

Just set editable using Studio UI or from XML:

       
<table id="billOfMaterialLinesTable"        
   editable="true"        
   height="200px"        
   width="100%">        
<actions>        
    <action id="add" invoke="onAdd"/>
    <action id="remove" invoke="onRemove"/>
    <action id="save" invoke="onSave"/>
</actions>        
<columns>        
    <column id="material" editable="true"/>    <!-- editable column -->     
    <column id="quantity"/>        
    <column id="wastageRate"/>        
</columns>

editable

HI, can you post this example with one more Screen ?

Add Entity Project, and Screen Project Edit with table, and add the feature to edit inline in this screen ?

I’m going crazy to make my screen working ;/

Thanks!

1 Like

Hi Ivan,

could you please start a new topic and describe your task in the details?

Thank you for this sample Yuriy.

Is there a way to create all of this editable table functionality using only the Cuba Studio GUI components or does it require copying your code?

Hi,

You can simply set editable = true for Table and for each column you want to edit from Studio Screen Designer. There is additional code in the sample for adding/removing rows and validation in TaskBrowse.java, you need to copy and modify this code for your application.

Wow, that was an amazingly fast reply. Thank you.

Does the save button also require code or is there a way to get that from the GUI?

Yes, currently, Save button requires a few lines of code in the controller. There is no declarative way to do it, but it is really simple code.

Hello,

I needed the same in-line editing. Thank you very much for your example, I can edit and save it inline.
My only problem is that when I want to create a new record, then I need a new row. I tried this:


public void addTask() {
        tasksDs.addItem(metadata.create(Task.class));
    }

But not working =(
Seems nothing happening. What I’ve missed?

Hi
I do like this, it works:

Task task = metadata.create(Task,class);
task.setName("");
task.setParentTask(parentTask);
tasksDs.addItem(task);

You have to include this task as collection of ParentTask

1 Like

What is ParentTask? I have a collectionDatasource for tasksDs.
This is how my code looks like:

	@Inject
	private Metadata metadata;
	
	@Inject
	private CollectionDatasource<Task, Integer> tasksDs;
	
	public void addTask(Component source) {
		//tasksDs.addItem(metadata.create(Task.class));
		Task task = metadata.create(Task.class);

		task.setName("");

		//task.setParentTask(parentTask);

		tasksDs.addItem(task);
    }