+ Start a Discussion
Rajasekhar TRajasekhar T 

How to save drag and drop records in lightning component?

In my database contact object having 10records. in list view when i drag the 9th record to 2nd record it will be replaced. But while refreshing the records page or component it will be change existing position. So once i drag and drop the records i need to save automatically in database. 

please check my below drag and drop (sorting) code. can one suggest me how can i achieve my requirement(saving the sorting records automatically).

Controller:
public class ConDragandDropController{


      @AuraEnabled
       public static Contactwrap getContactwrap(String objName, String[] objFields) {

           String query = 'SELECT Id, ';
           for(String s:objFields){
               query += s+' ,';
           }
           query = query.removeEnd(',');
           query += ' FROM ' + objName;
           System.debug('qq  ' + query);

           return new Contactwrap(Database.query(query));
       }


       public class Contactwrap{
           @AuraEnabled
           List<sObject> records {get;set;}

           public Contactwrap(List<sObject> recs){
               this.records = recs;
           }
       }

}


Component:

<aura:component controller="ConDragandDropController" implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction" access="global">
    <aura:attribute name="objName" type="String"/>
    <aura:attribute name="objFields" type="String[]"/>
      <aura:attribute name="dragid" type="Integer" access="private" />
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
    <aura:attribute name="ContactData" type="ConDragandDropController.Contactwrap"/>
    <div class="slds-page-header">
        <div class="slds-media">
            <div class="slds-media__figure">
                <span class="slds-icon_container" title="Description of icon when needed">
                    <lightning:icon iconName="utility:kanban" variant="bare" size="small"/>
                </span>
            </div>
            <div class="slds-media__body">
                <h1 class="slds-page-header__title slds-truncate slds-align-middle" title="Contact Records">Contact Records</h1>
            </div>
        </div>
     </div>
     <div style="padding:0.5rem;">
         <div class="stageContainer" style="width:100%">
            <ul ondrop="{!c.drop}" ondragover="{!c.allowDrop}" class="slds-has-dividers_around-space dropZone" style="height:100%;overflow-y:auto;">
                   <aura:iteration var="objRecord" items="{!v.ContactData.records}"  indexVar="index">
                   
                        <li class="slds-item slds-m-around_small" draggable="true" ondragstart="{!c.drag}" id="{!objRecord.Id}" >
                            <article class="slds-tile slds-tile_board">
                                <h3 class="slds-truncate" title="{!objRecord.Name}">
                                    <a href="javascript:void(0);" onclick="{!c.doView}">
                                        <span class="slds-truncate" id="{!objRecord.Id}">{!objRecord.Name}</span>
                                    </a>
                                </h3>
                                <div class="slds-tile__detail slds-text-body_small">
                                    <p class="slds-text-heading_medium">First Name: ${!objRecord.FirstName} </p>
                                    <p class="slds-truncate" title="{!objRecord.FirstName}">
                                        <a href="javascript:void(0);" onclick="{!c.doView}">
                                            <span class="slds-truncate" id="{!objRecord.LastName}">{!objRecord.LastName}</span>
                                        </a>
                                    </p>
                                    <!-- <p class="slds-truncate" title="{!'Closing ' +objRecord.CloseDate}">Closing {!'Closing ' +objRecord.CloseDate}</p>-->
                                </div> 
                            </article>
                        </li>
                  
                </aura:iteration> 
            </ul>
        </div>    
    </div>   
</aura:component>

Controller.JS:

({
     doInit: function(component, event, helper) {
        
          var action = component.get("c.getContactwrap");
        
          action.setParams({
            "objName":component.get("v.objName"),
            "objFields":component.get("v.objFields")
         });
         
         action.setCallback(this, function(response){
            var state = response.getState();
             
            if (state === "SUCCESS") {
                console.dir(response.getReturnValue());
                component.set("v.ContactData", response.getReturnValue());
            }
        });
        $A.enqueueAction(action);
    },
    
    doView: function(component, event, helper) {
        var editRecordEvent = $A.get("e.force:navigateToSObject");
        editRecordEvent.setParams({
            "recordId": event.target.id
        });
        editRecordEvent.fire();
    },
    allowDrop: function(component, event, helper) {
        event.preventDefault();
    },
    
    drag: function (component, event, helper) {
         
       
        event.dataTransfer.setData("text", event.target.id);
        
    },
    
    drop: function (component, event, helper) {
    var data = event.dataTransfer.getData("text");
         
    // Find the record ID by crawling up the DOM hierarchy
    var tar = event.target.closest('[id]');
        
    var contactData = component.get("v.ContactData"); 
    var index1, index2, temp; 
    // Find the index of each item to move
    contactData.records.forEach((v,i)=>{if(v.Id===data) index1 = i; if(v.Id===tar.id) index2 = i;});
       
    if(index1<index2) {
        // Lower index to higher index; we move the lower index first, then remove it.
        contactData.records.splice(index2+1, 0, contactData.records[index1]);
        contactData.records.splice(index1, 1);
        
       
    } else {
        // Higher index to lower index; we remove the higher index, then add it to the lower index.
        temp = contactData.records.splice(index1, 1)[0];
        contactData.records.splice(index2, 0, temp);
        
    }
    
    // Trigger aura:valueChange, component will rerender
    component.set("v.ContactData", contactData);
        
    event.preventDefault();
}
})
Styles:
.THIS {
    

.THIS .slds-item {
    border: 1px solid #d8dde6;
    border-radius: 0.25rem;
    background-clip: padding-box;
    padding: 0.45rem;
    margin: 0.25rem;
}
.THIS .stageContainer{
 /*   width:320px; */
    float:left;
    border: 2px solid #d8dde6;
    margin: 0.05rem;
    border-radius: .25rem;
}
.THIS .slds-page-header__title {
    padding: 0rem 0.5rem;
    background: #f7f9fb;
}


.THIS .dropZone{
    min-height:25rem;
}
 

Application:

<aura:application extends="force:slds">
     <c:ConDragandDrop objName="contact" objFields="['Name', 'FirstName', 'LastName', 'Email', 'Phone']"/>
</aura:application>
NagendraNagendra (Salesforce Developers) 
Hi Rajasekhar,

In Lightning, we don't manually move elements around (e.g. tar.appendChild(document.getElementById(data))). Instead, we reorder the data, and the platform takes care of it for us.

The design pattern you have isn't optimal, but for sake of keeping it simple, here's the modified drop function you'd use:
({
drop: function (component, event, helper) {
    var data = event.dataTransfer.getData("text");
    // Find the record ID by crawling up the DOM hierarchy
    var tar = event.target.closest('[id]');
    var contactData = component.get("v.ContactData");
    var index1, index2, temp;
    // Find the index of each item to move
    contactData.records.forEach((v,i)=>{if(v.Id===data) index1 = i; if(v.Id===tar.id) index2 = i;});
    if(index1<index2) {
        // Lower index to higher index; we move the lower index first, then remove it.
        contactData.records.splice(index2+1, 0, contactData.records[index1]);
        contactData.records.splice(index1, 1);
    } else {
        // Higher index to lower index; we remove the higher index, then add it to the lower index.
        temp = contactData.records.splice(index1, 1)[0];
        contactData.records.splice(index2, 0, temp);
    }
    // Trigger aura:valueChange, component will rerender
    component.set("v.ContactData", contactData);
    event.preventDefault();
}
})
There's no real error checking here, so you might want to take care of situations like when a user drops on to an area that isn't covered by a DOM element that has an ID.

Hope this helps.

Kindly mark this as solved if the reply was helpful.

Thanks,
Nagendra