Custom command Duplicate Row

24 posts, 0 answers
  1. Shahar
    Shahar avatar
    12 posts
    Member since:
    Jul 2010

    Posted 04 Jul 2013 Link to this post

    I have a grid with edit : popup.
    I want to add a custom command that will open the popup editor in adding new row  mode
    but will have the values of the current record (like duplicate row).
  2. Dimiter Madjarov
    Admin
    Dimiter Madjarov avatar
    2304 posts

    Posted 05 Jul 2013 Link to this post

    Hello Shachar,


    A custom approach to achieve this would be the following - use a boolean flag value which will indicate whether the currently added row is added by the standard "Add new item" button or by the custom command. In the custom command event handler you should retrieve the dataItem for the current row, set the flag to true and manually call the addRow method of the Grid to add the new row. Finally in the edit event handler (which is fired each time a record is added or edited) you should check the flag and if it's true, manually set the values of the editor fields with the ones from the current row. Here is a short example, which demonstrates the approach.

    E.g.
    { command: { text: "Add New Custom Row", click: addNewCustomRow}, width: "140px" }

    var isCustomAdd = false;
    var customRowDataItem;
     
    function addNewCustomRow(e) {
        e.preventDefault();
     
        customRowDataItem = this.dataItem($(e.currentTarget).closest("tr"));
        isCustomAdd = true;
        this.addRow();
    }

    function edit(e) {
        if (isCustomAdd && e.model.isNew()) {
            isCustomAdd = false;
     
            //set the values of the pop up editor fields
            $(e.container).find("[name='ProductName']").val(customRowDataItem.ProductName);
            ...
        }
    }

    I hope that this information was helpful for you. I wish you a great day!

     

    Regards,
    Dimiter Madjarov
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  3. Shahar
    Shahar avatar
    12 posts
    Member since:
    Jul 2010

    Posted 16 Jul 2013 Link to this post

    Hi Dimiter,
    I tried the solution you provided.
    It worked fine and I populated all the items in the popup window.

    The problem is when I click the update button
    only items that were changed are submited.

    Thanks

  4. Dimiter Madjarov
    Admin
    Dimiter Madjarov avatar
    2304 posts

    Posted 17 Jul 2013 Link to this post

    Hello Shachar,


    Sorry for the inconvenience. I missed a small aspect of the approach in my previous answer. The change event of the edit fields should be triggered in order to notify the model binding.
    E.g.
    function edit(e) {
        if (isCustomAdd && e.model.isNew()) {
            isCustomAdd = false;
            $(e.container).find("[name='ProductName']").val(customRowDataItem.ProductName).change();
        }
    }

     

    Regards,
    Dimiter Madjarov
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  5. Aaron
    Aaron avatar
    3 posts
    Member since:
    Sep 2013

    Posted 30 Oct 2013 Link to this post

    I am wanting to accomplish the same thing as Shachar, the only difference is that two of the fields that I want to populate, or "duplicate" are cascading drop down items.  For example, I have a grid with three columns: Category, Subcategory, Content.  Category and Subcategory are cascading dropdown list that retrieve data via JSON.  I want to have these automatically set to the same as the row I want to duplicate.  I tried to see if this works with the code you have provided here but the drop down list are not set appropriately.  I am thinking that maybe the edit event is being called before the Category dropdown list is populated.  Also, the Subcategory is usually not populated until there has been an item selected in the Category drop down.
  6. Dimiter Madjarov
    Admin
    Dimiter Madjarov avatar
    2304 posts

    Posted 31 Oct 2013 Link to this post

    Hi Aaron,


    You are correct, when the edit event of the Grid is triggered, the DropDownLists are not populated yet, which means that their value cannot be set yet. In general this is a custom scenario, but a sample approach that you could try would be to use a separate object to store the values in the edit event.
    E.g.
    var ddlValues = [];
     
    function edit(e) {
        ...
        ddlValues[0] = ...;
        ddlValues[1] = ...;
        ddlValues[2] = ...;
    }

    Then you could bind to the dataBound events of the three DropDownLists and manually set the values there after the data is populated.
    E.g.
    function dataBound1(e) {
        this.value(ddlValues[0]);
    }
     
    function dataBound2(e) {
        this.value(ddlValues[1]);
    }
     
    function dataBound3(e) {
        this.value(ddlValues[2]);
    }

    This custom approach may cause another issue i.e. the dataBound event of the first DropDownList may be triggered before the ddlValues array is populated. If that is the cause, you could set it's AutoBind option to false and manually trigger the loading of the data at the end of the edit event.

    I wish you a great day!

    Regards,
    Dimiter Madjarov
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  7. Aaron
    Aaron avatar
    3 posts
    Member since:
    Sep 2013

    Posted 31 Oct 2013 Link to this post

    I took you approach here and it definitely is populating the drop down list how I would like for it to.  However, it is not updating the record when I select update because the Category and Subcategory properties of the object being passed back are not set.
  8. Dimiter Madjarov
    Admin
    Dimiter Madjarov avatar
    2304 posts

    Posted 01 Nov 2013 Link to this post

    Hello Aaron,

    As stated in the previous post, the change event should also be triggered, so the model is aware that the value has been changed. After further testing I stated that a timeout would be required too. 

    To demonstrate the complete approach I prepared a sample solution for you. You could find it attached to my post.

    Regards,
    Dimiter Madjarov
    Telerik
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
  9. Aaron
    Aaron avatar
    3 posts
    Member since:
    Sep 2013

    Posted 01 Nov 2013 Link to this post

    Dimiter,
    This got me to where I needed to be.  Thank you.
  10. Paige
    Paige avatar
    1 posts
    Member since:
    Feb 2014

    Posted 02 Dec 2015 Link to this post

    I'm having an issue with this solution.   

    Once I append the .Name parameter to the textbox control on the popup template in order to be referenced for the copy function to work, that same textbox it is blank when I try to do a normal edit in the popup template. 

  11. Dimiter Madjarov
    Admin
    Dimiter Madjarov avatar
    2304 posts

    Posted 03 Dec 2015 Link to this post

    Hello Paige,

    Using the Name() method in the editor should not be needed in this case. The name attribute will be automatically generated to be the same as the name of the edited property. Let me know if that is the case on your end too?

    Regards,
    Dimiter Madjarov
    Telerik
     
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
     
  12. Mark
    Mark avatar
    4 posts
    Member since:
    Oct 2016

    Posted 22 Sep 2017 in reply to Dimiter Madjarov Link to this post

    Hi Dimiter,

    I am trying to implement this technique (you'd think that duplicate row would be a standard grid function as it's a common data entry need) and am stuck.

    The popup gets executed but with no data.  My troubleshooting shows that the edit(e) function is not getting executed.  

    My question is: what triggers the edit(e) function?

    Also, what uses the customRowDataItem object?  

    Thanks

  13. Mark
    Mark avatar
    4 posts
    Member since:
    Oct 2016

    Posted 25 Sep 2017 in reply to Mark Link to this post

    OK, to answer my noob questions: 

    You have to add the event to the grid's event array for edit(e) to fire.

    The edit(e) function is consuming customRowDataItem in the val() extension.  

    This technique does work.

  14. Insad
    Insad avatar
    41 posts
    Member since:
    Jan 2010

    Posted 26 Sep 2017 Link to this post

    Hi,

    It looks like the solution above works but I have found some issues with it;

    1 - the $(e.container).find("[name='ProductName']").val(customRowDataItem.ProductName); only works on text fields, not on special widgets like numericaltextbox, calender etc.

    It would be nicer to take a more MVVM approach, so I use

    e.model.set('ProductName', self.customRowDataItem.ProductName);

    Which works for the numericals and dates as well.

    2 - After pressing my Copy and Edit button (in the edit event function) I change the ProductName and to my surprise I can see it changing in the grid as well?? After pressing the Update button I see the changed ProductName 2 times in the grid!

    3 - Pressing Edit on the second one with the duplicate name, followed by pressing Cancel changes the name in the grid back?

    4 - Pressing Edit on the first one, followed by pressing Cancel removes the entire (new) record??

    5 - I have added the ID to the grid and this also has strange values during the above points 3 and 4

     

    To give a visual example look at this DoJo Sample: Copy and Edit record

     

    Can u advise on what I am doing wrong here?

     

    Regards,

    Insad

  15. Stefan
    Admin
    Stefan avatar
    2473 posts

    Posted 28 Sep 2017 Link to this post

    Hello, Insad,

    Thank you for the provided suggestions and the example.

    I made a modification to the example in order to only shown the copy items as a copy instead of both items. This will keep the name of the original item. This will also resolve the issue listed in point 4.

    As for point 3 ("Pressing Edit on the second one with the duplicate name, followed by pressing Cancel changes the name in the grid back"), this is expected and can be observed in all of our demos. This occurs because the item is not saved in the database and is without an ID. Then when the cancel button is clicked, this is calling cancel changes and it is reverting all unsaved changes for the dataItem.

    Please inspect the modified example and advise if additional issues are observed:

    http://dojo.telerik.com/AkanIR

    Regards,
    Stefan
    Progress Telerik
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  16. Insad
    Insad avatar
    41 posts
    Member since:
    Jan 2010

    Posted 28 Sep 2017 in reply to Stefan Link to this post

    Hello Stefan,

    Thanks for your answer, I saw what I did wrong.

    I noticed that the data only is created and is not updated to the server, so I assume that is because the server is for demo purposes only and will not handle the updates to it.

    But how I can project this to my real life app is not clear to me.

    To make you understand what I am facing I will make it a bit clear what the idea is;

    I have an app that has an RFQ system in it.

    When the user comes to the RFQ page a grid is shown with the current RFQs. For this there is a service that provides only the information for the grid and the ID in the database.

    The user can Add/Edit and Delete RFQs.

    When adding a new RFQ a window pops up with a tabstrip and several pages with the RFQ information that can be entered. When the user presses Save the data is stored via a service in the database and the RFQ grid is refreshed. For this I do a dataSource.add({}) to add a new datarecord, init some values and copy it into the viewModel and show the window. In the onSave the data is copied from the viewModel into the dataSource vars and a dataSource.sync() is called. Note that it is not possible to bind the datasource to the window due to incompatible fields (don't ask ;)).

    When the user presses edit on a RFQ the same window pops up with the data of the selected RFQ in it and the user can change the data and press Update to store the RFQ. For this I do a dataSource.read() to get the data from the server, copy it into the viewModel and show the window. In the onUpdate the data is copied from the viewModel into the dataSource vars and a dataSource.sync() is called.

    The delete just calls a delete service that takes the ID and the RFQ is dropped in the back-end.

    What I need to do next is adding the Copy and Edit functionality that creates a new RFQ and takes the data from the selected RFQ, changing some values and present it in the window as if it was an existing record, with the difference that there is a Save button that stores the new data and the Cancel button forgets the info.

    What I came up with so far is that when the user presses the Copy and Edit button, a flag is set, the window pops up as if it was a new record, only with a difference: I read the data from the RFQ selected (dataSource.fetch()), change some values and call the dataSource.add(sourceRFQ). From here I continue with copying the (new) data to the viewModel and when the user presses Save the data is sync'd.

    Is this something (in simple words) that should work or do I need to take a different path for this?

    Any thoughts are welcomed.

     

    Best regards,

     

    Insad

     

  17. Insad
    Insad avatar
    41 posts
    Member since:
    Jan 2010

    Posted 28 Sep 2017 in reply to Insad Link to this post

    I forgot to mention the problem I encounter with my described solution.

    When I do the sync(), after the Copy and Edit -> enter data -> press Save, the UPDATE of the dataSource is fired, but there is no CREATE done, so the server responds that you cannot update data that is not there (in simple words, the data is not created, so why is the update called?)

     

    Best regards,

    Insad

  18. Konstantin Dikov
    Admin
    Konstantin Dikov avatar
    2466 posts

    Posted 02 Oct 2017 Link to this post

    Hi Insad,

    The suggested approach by my colleague Stefan calls the Create correctly in the dojo examlpe. Could you please try to modify the example to replicate the issue and to better match your scenario? 

    Meanwhile, please ensure that the "id" field is set in the dataSource`s schema.


    Regards,
    Konstantin Dikov
    Progress Telerik
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  19. Mark
    Mark avatar
    4 posts
    Member since:
    Oct 2016

    Posted 03 Oct 2017 in reply to Dimiter Madjarov Link to this post

    I have found one small logic issue with this code; it happens with the definition of the isCustomAdd variable. 

    In the case where you are not duplicating a row, the conditional:

    if (isCustomAdd && e.model.isNew()) {..} will throw an exception, until isCustomAdd is defined.  

    This will keep the Cancel and Update popup buttons from working properly.  My workaround is to capture the error, that fixes it, but if someone has a better idea for defining that variable, that would be great. 

    try {
        if (isCustomAdd && e.model.isNew()) {
            isCustomAdd = false;
            e.model.set("Performance_ID", customRowDataItem.Performance_ID);
            e.model.set("Type", customRowDataItem.Type);
            e.model.set("Text", customRowDataItem.Text);
        }
    } catch (err) { }

     

  20. Stefan
    Admin
    Stefan avatar
    2473 posts

    Posted 04 Oct 2017 Link to this post

    Hello, Mark,

    Thank you for sharing this with the Kendo UI community. It is highly appreciated.

    In general, the "isCustomAdd" property should be declared inside the ViewModel and this should not create a scenario where the isCustomAdd is undefined.

    Regards,
    Stefan
    Progress Telerik
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  21. Insad
    Insad avatar
    41 posts
    Member since:
    Jan 2010

    Posted 15 Nov 2017 Link to this post

    Hi again,

     

    sorry for the delay but I was put on a high prio project for a short moment.

     

    I've been playing around and my problem comes down to a really elementary problem.

    Look at the following an please tell me how I can get it to work:

    var myViewModel = kendo.observable({
        className: 'myViewModel'
        , myDs: rfqsDataSource      // rfqsDataSource implements all CRUD operations
         
        ...
         
        //
        // Read and copy data
        //
        , doMyCopy: function (sourceId)
        {
            var self = this;
             
            self.myDs.read(sourceId)
                    .then(function () {
                        // Copy dataSet
                        var dataSet = self.myDs.at(0);
     
                        // Cancel read flags?
                        self.myDs.cancelChanges();
     
                        // Invalidate the ID field
                        dataSet.set('ID', null);
                         
                        // Add new dataset, copying data from the saved dataset
                        var newDataSet = self.myDs.add(dataSet);
     
                        // Alter the other fields
                        newDataSet.set('Description', 'Brand new day!');
                         
                        // Sync (CREATEing) the new record
                        self.myDs.sync();
                    });
        }
     
        ...
    });

     

    However, instead of calling the CREATE method of the datasource, the UPDATE method is called??

    To me this indicates that it appears that the read flags are still active, disregarding the cancelChanges() and therefor the UPDATE method is called instead of the CREATE method?

    Best regards,

     

    Insad

  22. Stefan
    Admin
    Stefan avatar
    2473 posts

    Posted 17 Nov 2017 Link to this post

    Hello, Insad,

    Could you please integrate this scenario in one of the Dojo, so we can inspect it?

    I implemented a similar approach in one of the Dojos, but the Create was called as expected:

    http://dojo.telerik.com/AkanIR/2

    Please ensure that the null ID is set to the id property on the dataItem.

    Regards,
    Stefan
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  23. Insad
    Insad avatar
    41 posts
    Member since:
    Jan 2010

    Posted 17 Nov 2017 in reply to Stefan Link to this post

    I found that initializing the new dataset with the seperate entities, excluding the ID field, works okay in my situation.

    Initializing with the entire dataset triggers the update to happen instead of the create.

     

    My data model is somewhat more complex than the demo in the DoJo; I heve several nested items an  an array of nested items.

    Possibly this, somehow, triggers the flag to call the update instead of the create.

     

    For now I have fixed it by calling the add() something like

    01.// Copy data read
    02.var dataSet = self.dataSource.at(0);
    03.// Clear read flags
    04.self.dataSource.cancelChanges();
    05. 
    06.// Invalidate the ID field
    07.dataSet.set('ID', null);
    08. 
    09.// Create new record with data in it
    10.self.lastDataItem = self.dataSource.add({
    11.                                    Description: 'Kopie van ' + dataSet.Description
    12.                                    , FinishingTypeIds: dataSet.FinishingTypeIds
    13.                                    , FinishingTypes: dataSet.FinishingTypes
    14.                                    , DeliveryTypeID: dataSet.DeliveryTypeID
    15.                                    , PackagingTypeID: dataSet.PackagingTypeID
    16.                                    , PaperDeliveryTypeID: dataSet.PaperDeliveryTypeID
    17.                                    , PrepackTypeID: dataSet.PrepackTypeID
    18.                                    , ProductSizeID: dataSet.ProductSizeID
    19.                                    , ProductTypeCategoryID: dataSet.ProductTypeCategoryID
    20.                                    , ProductTypeID: dataSet.ProductTypeID
    21.                                    , Quantity: dataSet.Quantity
    22.                                    , Version: 0
    23.                                    , Entrys: dataSet.Entrys
    24.                                });                                             // Add new record
  24. Stefan
    Admin
    Stefan avatar
    2473 posts

    Posted 20 Nov 2017 Link to this post

    Hello,

    I'm glad to hear that the desired result is achieved.

    Please let a know if additional assistance is needed on this matter.

    Regards,
    Stefan
    Progress Telerik
    Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Back to Top