frappe / datatable

The Missing Javascript Datatable for the Web
https://frappe.io/datatable
MIT License
1.02k stars 164 forks source link

I added an event after field edition, what do you think ? #59

Open melBoh opened 5 years ago

melBoh commented 5 years ago

Hi ! I needed to save data after inline edition. seeing https://github.com/frappe/datatable/issues/46 I thought I should try my hand on it.

It's working for me, but I don't know if it's good enough for community, so, what do you think ?

in apps/frappe/node_modules/frappe-datatable/dist/frappe-datatable.cjs.js from line 2525 class CellManager { constructor(instance) { this.instance = instance; linkProperties(this, this.instance, [ 'wrapper', 'options', 'style', 'header', 'bodyScrollable', 'columnmanager', 'rowmanager', 'datamanager', 'keyboard', 'fireEvent', //<= add this ]); this.bindEvents();

then, from line 3022

` submitEditing() { if (!this.$editingCell) return; const $cell = this.$editingCell; const { rowIndex, colIndex } = $.data($cell); const col = this.datamanager.getColumn(colIndex);

    if ($cell) {
        const editor = this.currentCellEditor;

        if (editor) {
            let valuePromise = editor.getValue();

            // convert to stubbed Promise
            if (!valuePromise.then) {
                valuePromise = Promise.resolve(valuePromise);
            }

            valuePromise.then((value) => {
                const done = editor.setValue(value, rowIndex, col);
                const oldValue = this.getCell(colIndex, rowIndex).content;

                // update cell immediately
                this.updateCell(colIndex, rowIndex, value);
                $cell.focus();

                // =>add this : BEGINNING OF add edit submit event
                let rowData = this.datamanager.getData(rowIndex);
                this.fireEvent('onSubmitEditing', [rowData, this.getCell(colIndex, rowIndex).column.id, value]);
                // END OF add edit submit event

                if (done && done.then) {
                    // revert to oldValue if promise fails
                    done.catch((e) => {
                        console.log(e);
                        this.updateCell(colIndex, rowIndex, oldValue);
                    });
                }
            });
        }
    }

    this.currentCellEditor = null;
}`

Then in custom JS (associated to a report in my case)

` frappe.query_reports["my_report"] = { ... get_datatable_options(options) {

    // loops on each column and make one ore more of them editable
    options.columns.forEach(function(column, i) {
        // column id i want to make editable
        if(column.id == "your_editable_id") {
            column.editable = true
        }
    });

    // change datatable options
    return Object.assign(options, {
        checkboxColumn: true,
        events: {
            onSubmitEditing: function (cell) {
                // rowValues : all cell values from row before edition
                // cellId : key id of cell edited
                // newVal : edited val
                let [rowValues, cellId, newVal] = cell;
                if(cellId == "your_editable_id") {
                    frappe.call({
                        method: "your.method",
                        type: "GET",
                        args: {name: rowValues.id, qty: newVal}, // for example
                        callback: function (r) {
                            if (r.message) {
                                frappe.msgprint(__(r.message));
                            }
                        },
                    });
                }
            },
        }
    });
},

};

`

hetal1110 commented 4 years ago

Is there any way to get selected rows in Datatable?

But how to get row Ids, that is selected?

What is the Event to capture selected rows?

Thanks in Advance…

sanjay-hercules commented 4 years ago

@hetal1110 you can get selected rows of report having checkbox as mentioned below:


        onload: function() {
                       // add a button to report
            frappe.query_report.page.add_inner_button(__("Get Selected"), function() {
                var selected_rows = [];
                $('.dt-scrollable').find(":input[type=checkbox]").each((idx, row) => {
                    if(row.checked){
                        console.log("*** selected row id : " + idx);
                        selected_rows.push(frappe.query_report.data[idx]);
                    }
                });
            });
        },
AndyOverLord commented 3 years ago

Hi @melBoh, thank you very much. I think it's working real well as I have used it to enabled a feature of editing inline and update it in the database. I wonder why it's still not merged to the repository.

If I make the changes on my own, how to prevent the changes be override with next frappe version updates.

kevinpthorne commented 3 years ago

why this is still open? Can a PR be made for this?

kevinpthorne commented 3 years ago

Actually, I found using the setValue function when setting the datatable's getEditor return object provided the same functionality.

For example (using Frappe Controls)


    getEditor: function(colIndex, rowIndex, value, parent, column, row, data) {
            // colIndex, rowIndex of the cell being edited
            // value: value of cell before edit
            // parent: edit container (use this to append your own custom control)
            // column: the column object of editing cell
            // row: the row of editing cell
            // data: array of all rows

            const control = frappe.ui.form.make_control({
                parent: parent,
                df: {
                    label: '',
                    fieldname: doctype,
                    fieldtype: 'Link',
                    options: doctype
                },
                render_input: true,
                only_input: true,
            });

            let oldValue = '';

            return {
                // called when cell is being edited
                initValue(value) {
                    control.input.focus();
                    control.input.value = value;
                    oldValue = value;
                },
                // called when cell value is set
                setValue(newValue) {
                    // ----------- Do whatever is needed here.
                    control.input.value = newValue;
                },
                // value to show in cell
                getValue() {
                    return control.input.value;
                }
            }
        }
azharumar commented 2 years ago

I've hit a strange roadblock.

Inline editing works in Report Builder, but calculated fields are not possible. Calculated fields are possible in script editor, but inline editing is not possible.

kevinpthorne commented 2 years ago

I've hit a strange roadblock.

Inline editing works in Report Builder, but calculated fields are not possible. Calculated fields are possible in script editor, but inline editing is not possible.

Editing a calculated field goes against their purpose. I would make it whatever type it should be and do the calculation manually. Alternatively, you can make a hidden calculation field and copy the value over to the editable field.

azharumar commented 2 years ago

I've hit a strange roadblock. Inline editing works in Report Builder, but calculated fields are not possible. Calculated fields are possible in script editor, but inline editing is not possible.

Editing a calculated field goes against their purpose. I would make it whatever type it should be and do the calculation manually. Alternatively, you can make a hidden calculation field and copy the value over to the editable field.

Obviously! I wouldn't want a calculated field to be editable. Instead, I have a report where both type of columns are needed - one for calculated and another for inline editing.