Drag & Drop with Code-behind

After the last video with the Javascript and Code-behind, I got (as to be expected) several questions if it was possible to do it also with a drag & drop interface. And since drag & drop is something you can do with Javascript, the answer is yes. So here's an example of an interface doing just that. You can see the example in action on our website. You can also download the source code there as well.

The inspiration and the basic Javascript in this example comes from a video I found on Youtube from Brad Traversy. If you are interested in more great videos on all kinds of programming languages and frameworks I highly recommend to subscribe to his channel!

Plain vanilla Javascript

Now to begin with, there are several Javascript frameworks out there that can help you to create a drag & drop interface. But my rule of thumb is, as long as you can just as easily do things with plain vanilla Javascript, stick to that and don't use a framework. Adding a framework will add an additional load to your page, sometimes a quite significant one. So to keep your pages fast, try to avoid it if you can. Also, you have to rely on the code of others and the options the framework gives you. So if you want to expand the functionality later on, you might get into trouble because the framework does not support what you want to do. 

As tempting as it might be to use a framework, try to up your Javascript skills and stay in control. You'll be surprised with what you can do with just Javascript. Also, the better you understand what you can do yourself, the better you can decide whether to stick to your own Javascript or switch to a framework.

The Drag & Drop Example

For this example I used a business case where the user can enter notes and assign them to a person. Now you could use a selection list from a drop-down for that. But for this example I decided it would be more intuitive to drag & drop the note on the person you want to assign it to. 

Also, I added a counter so the user can see how many notes a person already has. So with a bit of imagination you can think of other use cases as well. For example, assigning tasks to the person who currently has the least assignments in his/her workload. And then instead of the counter, add and display the hours required to complete those tasks.

Here's the example in action:

Adding Drag & Drop through Javascript

Making an element dragable is easy. Simply add the dragable attribute to that element. So in this example, the DIV containing the text-box has:

<div id="content" class="content" draggable="true">

Once the element is dragable, you need to add some event listeners so you can catch them with a function when the event is fired:

content.addEventListener('dragstart', dragStart);
content.addEventListener('dragend', dragEnd);

Now if you use an ASP:Repeater to generate the options where that can be dropped, you need to find all the elements that are dropable. This can be done through Javascript:

const containers = document.querySelectorAll('.container');

This will get all elements using their ClassName. Once you have all those elements, loop through them and add the event listeners that will fire when the dragable element is dragged on and over it, moves out of it or dropped onto it:

for (const container of containers) {
  container.addEventListener('dragover', dragOver);
  container.addEventListener('dragenter', dragEnter);
  container.addEventListener('dragleave', dragLeave);
  container.addEventListener('drop', dragDrop);
}

So now you have the event listeners, let's add the functions that should be executed when the event is fired:

The first one for the drag start is simple. It just adds another class to the already assigned class, making it clear for the user that the element is ready to be moved. You could also make that change after a few seconds using setTimeout. I did not use that for this example but you can find out how to do that from the line that is added as a comment:

function dragStart() {
  this.className += ' hold';
  //setTimeout(() => (this.className = 'invisible'), 0);
}

Once the user release it outside of a drop zone, the element should look like it was before. So when dropped, the ClassName should be reset to its original value:

function dragEnd() {
  this.className = 'content';
}

Now when we move the element over a drop zone, we don't want anything to happen that we don't control. So we add:

function dragOver(e) {
  e.preventDefault();
}

What we would like to happen is that the appearance of the drop zone changes. So we change the ClassName:

function dragEnter(e) {
  e.preventDefault();
  this.className += ' hovered';
}

And when we move out of the drop zone, it should go back to its initial appearance:

function dragLeave() {
this.className = 'container';
}

Now once we drop the element onto the drop zone, we also revert back to the original appearance. Next we put the ID of the drop zone in an ASP:HiddenField that can be accessed from code-behind. Last thing is to find the button that fires the postback action and simulate a click on it.

function dragDrop() {
  this.className = 'container';
  document.getElementById('hfSelectedID').value = this.id;

  var clickButton = document.getElementById('btnAddNote');
  clickButton.click();
}

What happens in the background?

When the page is loaded for the first time, the values for the ASP:Labels in the drop zones are set. Of course, when you generate the drop zones using an ASP:Repeater, you would fill those labels during the ItemDatabound. 

if (!IsPostBack)
{
  lblA.Text = "0";
  lblB.Text = "0";
  lblC.Text = "0";
  lblD.Text = "0";
  lblE.Text = "0";
  lblF.Text = "0";
  lblG.Text = "0";
  lblH.Text = "0";
}

Be sure to set them only on the initial page load and not on postback since the value will be updated from the AddNote later on. Otherwise the values will be reset and you wouldn't see the updated value. 

Here's what happens when the element is dropped and the AddNote button is clicked through Javascript:

protected void btnAddNote_Click(object sender, EventArgs e)
{
  DropNote(hfSelectedID.Value);

  tbNote.Text = "";
  tbNote.Attributes.Add("placeholder",
     "The Note was added to the list of Person " +
     hfSelectedID.Value +
     ". Type and assign your next Note.");
}

As you can see, after the DropNote is done, the text box is set to empy and the placeholder is used to let the user know that the action has taken place.

Now for the DropNote:

protected void DropNote(string person)
{
  string selectedLabel = "lbl" + person;
  Label lbl = (Label)Page.Form.FindControl(selectedLabel);

  int counter = int.Parse(lbl.Text);
  counter = counter + 1;

  lbl.Text = counter.ToString();
}

First we find the ASP:Label using Page.Form.FindControl. Next we get the text of that label and convert it to an integer. Then do the +1 and update the text with that.

Let's wrap it all up

Creating a drag & drop layout is easy to do with just simple Javascript, without the need of a framework. The different events from the drag & drop action can be used to execute some easy Javascript functions. And with the drop event you can then execute the server side code.

That's it for this post. Feel free to leave a comment or send a question to andre@silveressence.net. Let me know if you got inspired and may the source be with you!