Radzen Professional is now 20% off until January 4th 2019! Learn more

Blazor Drag and Drop

This blog post shows how to implement drag and drop in server-side Blazor applications. We will use the HTML 5 Drag and Drop API which is built-in in every modern browser.

Hey, we have announced Blazor support in Radzen! Check how you can create a complete Blazor CRUD application in minutes.

Sample project

Start from the default Blazor project template. Pick BlazorDragAndDrop as the project name.

DragAndDropService

This is a service which the draggable components will use to communicate with the drop targets.

Add a new file called DragAndDropService.cs in the BlazorDragAndDrop.App\Services directory:

using System;

namespace BlazorDragAndDrop.App.Services
{
    public class DragAndDropService
    {
        public object Data { get; set; }
        public string Zone { get; set; }

        public void StartDrag(object data, string zone)
        {
            this.Data = data;
            this.Zone = zone;
        }

        public bool Accepts(string zone)
        {
            return this.Zone == zone;
        }
    }
}

Then register the DragAndDropService in Startup.cs:

using Microsoft.AspNetCore.Blazor.Builder;
using Microsoft.Extensions.DependencyInjection;
using BlazorDragAndDrop.App.Services;

namespace BlazorDragAndDrop.App
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            // Since Blazor is running on the server, we can use an application service
            // to read the forecast data.
            services.AddSingleton<WeatherForecastService>();

            // Register the DragAndDropService
            services.AddSingleton<DragAndDropService>();
        }

        public void Configure(IBlazorApplicationBuilder app)
        {
            app.AddComponent<App>("app");
        }
    }
}

Draggable component

The next step is to create the component which the users will drag.

Add a new file Draggable.cshtml in the BlazorDragAndDrop.App\Shared directory:

@typeparam T
@using BlazorDragAndDrop.App.Services
@inject DragAndDropService DragAndDropService
<div draggable="true" ondragstart="@OnDragStart">
    @ChildContent
</div>
@functions {
    [Parameter]
    RenderFragment ChildContent { get; set; }

    [Parameter]
    string Zone { get; set; }

    [Parameter]
    T Data { get; set;}

    void OnDragStart()
    {
        // Notify the DragAndDropService what the current Data and Zone are.
        DragAndDropService.StartDrag(Data, Zone);
    }
}

The Draggable component has three properties.

  1. ChildContent is the user defined draggable content. We simply render it via @ChildContent.
  2. Zone is restricts (optinally) where this draggable can be dropped. A draggable can be dropped in a drop target only if their zones have the same value.
  3. Data is the user specified data associated with the draggable. Can be anything.

DropTarget component

The DropTarget accepts Draggable components and triggers an event when the user drops one.

Add a new file DropTarget.cshtml in the BlazorDragAndDrop.App\Shared directory:

@using BlazorDragAndDrop.App.Services
@inject DragAndDropService DragAndDropService
@typeparam T
<div ondragover="event.preventDefault()" ondrop="@OnDrop">
    @ChildContent
</div>
@functions {
    [Parameter]
    RenderFragment ChildContent { get; set; }

    [Parameter]
    string Zone { get; set; }

    [Parameter]
    Action<T> Drop { get; set; }

    void OnDrop()
    {
        if (Drop != null && DragAndDropService.Accepts(Zone))
        {
            Drop((T)DragAndDropService.Data);
        }
    }
}

The component has three properties.

  1. ChildContent is the user defined drop target content.
  2. Zone is specifies (optinally) what draggable components are accepted. A draggable can be dropped in a drop target only if their zones have the same value.
  3. Drop is the event handler that the DropTarget will trigger when the user drops an accepted draggable. The Data assocated with the dropped component is provided as argument.

Usage

Here is how to use the Draggable and DropTarget components in the Index.cshtml page:

<style>
    .draggable {
      border: 1px solid #ccc;
      border-radius: 5px;
      margin: 1rem;
      padding: 1rem;
      display: inline-block;
      cursor: move;
    }

    .drop-target {
      border: 1px dashed #ebebeb;
      margin: 1rem;
      padding: 1rem;
      display: inline-block;
    }
</style>

<Draggable Data="@draggableDataA">
    <div class="draggable">
        Draggable A
    </div>
</Draggable>

<Draggable Data="@draggableDataB">
    <div class="draggable">
        Draggable B
    </div>
</Draggable>

<DropTarget T="String" Drop="@OnDrop">
    <div class="drop-target">
        Accepts Draggable A or B
    </div>
</DropTarget>

@if (dropMessage != null) {
    @dropMessage
}

<DropTarget T="String" Zone="DropZone">
    <div class="drop-target">
        Can't drop here
    </div>
</DropTarget>

@functions {
    string draggableDataA = "Draggable Data A";
    string draggableDataB = "Draggable Data B";

    string dropMessage = null;

    void OnDrop(string data)
    {
        dropMessage = $"Dropped: {data}";

        // Important: Invoke StateHasChanged() to update the page
        StateHasChanged();
    }
}

The complete sample project is available in the Radzen Github repository.

Cheers!

by Atanas Korchev

Designing custom forms with Radzen

Radzen has supported forms since its very first release. The faithful Form component also got some improvements such as multi-column support and popup lookups. Still in some cases it wasn’t enough as Radzen users needed full control over the form layout in ...
Read more