copy&paste buttons problem with multiSet with rowreorder

copy&paste buttons problem with multiSet with rowreorder

milapmilap Posts: 40Questions: 13Answers: 2
edited August 2021 in General

Hello,
I am trying to create set of copy&paste buttons that will allow to copy multiple rows between tables (same structure in db but different table names).
In perfect scenario user will select rows, click "copy" button, switch to another page with similar table and import records pressing "paste" button.
To transfer data between pages I am planing to use Window.sessionStorage or clipboard.

To achieve my goal I have started with paste button.
Since I am also using in my project RowReorder extension I have a problem with proper enumeration of order value.

To create new rows I am using multiSet()
https://editor.datatables.net/reference/api/create()

Here is my button code:

        {
            extend: "create",
            text: 'PASTE',
            action: function ( e, dt, node, config ) {
                if(confirm( 'Are You sure You want to paste rows?' ))
                {
                    var newData = [
                        {
                            txt_1: 'aaa'
                        },
                        {
                            txt_1: 'bbb'
                        },
                    ]
                    var numRows = newData.length;
                    // Create the number of rows but don't show editor form.
                    editor
                        .create( numRows, false );
                    // Loop data to create each new row.
                    for (i=0; i<numRows; i++) {
                        editor.field('txt_1').multiSet(i, newData[i].txt_1);
                    }
                    // Submit data to be saved.
                    editor.submit();
                }
            },
            enabled: true
        }

The problem is that when I am pressing the PASTE button and I am currently having other properly enumerated records in the table, for instance:
1;xxx;
2;yyy;
3;zzz;

I am getting:
4;aaa;
4;bbb;

I was trying to change the approach and I have modified code to:

       {
            extend: "create",
            text: 'PASTE',
            action: function ( e, dt, node, config ) {
                if(confirm( 'Are You sure You want to paste rows?' ))
                {
                    var newData = [
                        {
                            txt_1: 'aaa'
                        },
                        {
                            txt_1: 'bbb'
                        },
                    ]
                    var numRows = newData.length;
                    for (i=0; i<numRows; i++) {
                        editor.create( false ).set( 'txt_1', newData[i].txt_1 ).submit();
                    }
                }
            },
            enabled: true
        }

But then only one row is created (probably there could be only one submit)
How can I control the order column value so I can get:
1;xxx;
2;yyy;
3;zzz;
4;aaa;
5;bbb;

Answers

  • kthorngrenkthorngren Posts: 20,144Questions: 26Answers: 4,736
    edited August 2021

    Since I am also using in my project RowReorder extension I have a problem with proper enumeration of order value.

    Are you copying the index column from the source table? The index changes based on how the rows are reordered. To keep the order you will need this index instead of generating the index.

    Kevin

  • milapmilap Posts: 40Questions: 13Answers: 2
    edited August 2021

    No I am not, but You have directed me what is the actual problem...
    Even if I will preset order column value like this:

    var newData = [
                            {
                                sort: '5',
                                txt_1: 'aaa'
                            },
                            {
                                sort: '6',
                                txt_1: 'bbb'
                            },
                        ]
                        var numRows = newData.length;
                        // Create the number of rows but don't show editor form.
                        editor
                            .create( numRows, false );
                        // Loop data to create each new row.
                        for (i=0; i<numRows; i++) {
                            editor.field('sort').multiSet(i, newData[i].sort);
                            editor.field('txt_1').multiSet(i, newData[i].txt_1);
                        }
                        // Submit data to be saved.
                        editor.submit();
    

    data will be ignored since I am building new order value dynamically during submit (I just forgot about it - I made this at the beginning of the project, sry):

        ->on( 'preCreate', function ( $editor, $values ) {
                $next = $editor->db()->sql('select IFNULL(MAX(sort)+1, 1) as next FROM table')->fetch();
                $editor->field('sort')->setValue($next['next']);
        } )
    

    Why I am doing that is described in my other topic:
    https://datatables.net/forums/discussion/68843/automatic-value-in-order-column-of-new-record#latest

    Since preCreate is called once (even for multiple rows) then I am getting new order value also once...

    So my question is is it possible to have 1 submit for each row? - I have checked that it does not work.
    Other way is to tweak that preCreate db call but how to do that?
    preCreate is called independently for each row so I can make an iterator?
    How to initialize an iterator variable then? Use $GLOBALS?

  • allanallan Posts: 61,446Questions: 1Answers: 10,054 Site admin

    Since preCreate is called once (even for multiple rows) then I am getting new order value also once...

    No, it will [be called once per row](Since preCreate is called once (even for multiple rows) then I am getting new order value also once...)[https://github.com/DataTables/Editor-PHP/blob/7e24a50bb9b0ee278c21ad3016b49b3562be8620/Editor.php#L1004-L1008] - however there is a complication - it gets called for all rows before any get written to the database, and since the field can only store one setValue they all get written to that value...!

    What I think you should do instead is use a setFormatter - as a function it will get called for each field just before it is written. Docs for it here.

    Then you can run your query in the set formatter and return the value you want it to take.

    Regards,
    Allan

  • milapmilap Posts: 40Questions: 13Answers: 2
    edited September 2021

    Thank You Allan for You response.
    I have managed to solve my problem in other way by putting new records (also pasted one) at the beginning of the table.

    In that case I could remove that:

    $next = $editor->db()->sql('select IFNULL(MAX(sort)+1, 1) as next FROM table')->fetch();
    

    In that case passed sort value was not ignored anymore and I was able to easily iterate (since I am starting from 0) and calculate proper values.

    Now my "copy&paste-between-tables-buttons" works like a charm even for multiple rows at once :)

    Here is my solution maybe someone will use it :)

    {
        extend: "selected",
        text: '<span class="glyphicon glyphicon-copy"></span>',
        titleAttr: 'COPY',
        action: function ( e, dt, node, config ) {
            if(confirm( 'Are You sure You want to copy data?' ))
            {
                var copyData = table.rows({selected: true}).data();
                var jsonCopy = [];
                for(let i=0;i<copyData.length;i++)
                    jsonCopy.push(copyData[i]);
                sessionStorage.setItem('key', JSON.stringify(jsonCopy));
            }
        },
        enabled: false
    },
    {
        extend: "create",
        text: '<span class="glyphicon glyphicon-paste"></span>',
        titleAttr: 'PASTE',
        action: function ( e, dt, node, config ) {
            if(confirm( 'Are You sure You want to paste data?' ))
            {
                var pasteData = JSON.parse(sessionStorage.getItem('key'));
    
                if(pasteData != null) {
                    var pasteDataLenght = pasteData.length;
                    editor.create(pasteDataLenght, false);
                    let j = pasteDataLenght-1;
                    for (let i=0; i<pasteDataLenght; i++) {
                        editor.field('sort').multiSet(i, i-j);
                        editor.field('txt_1').multiSet(i, pasteData[i].txt_1);
                        editor.field('activation_time').multiSet(i, pasteData[i].activation_time);
                        editor.field('deactivation_time').multiSet(i, pasteData[i].deactivation_time);
                        j--;
                    }
                    editor.submit();
                }
            }
        },
        enabled: true
    

    It uses sessionStorage so data can be copied only in the same browser tab
    To copy data between tabs You need to use localStorage and delete data while logout/closing browser etc.

    Explanation why this is happening is here

  • colincolin Posts: 15,118Questions: 1Answers: 2,583

    Thanks for posting back!

    Colin

Sign In or Register to comment.