Drag & Drop en Blazor
04/08/2022 02:47:35


En este articulo veremos cómo realizar una drag and drop básico en blazor webassembly, utilizando Net 6.

Creamos un proyecto del tipo blazor webassembly

Dentro del proyecto de blazor webassembly creamos una carpeta llamada Models y creamos una clase llamada DragDropModel.cs y sustituimos su contenido con el siguiente código.

namespace DragAndDrop.Models
{
	public class DragDropModel<T>
	{
		public int Index { get; set; }
		
		public T? Item { get; set; }
		
		public int NewIndex { get; set; }
		
		public bool IsActive { get; set; }
		
		public override string ToString()
		{
			return $"Index: {Index} IndexNew: {NewIndex}";
		}
	}
}

Crearemos un componente llamado DragDrop en la carpeta share y sustituimos el contenido con el siguiente código.

@typeparam TItem

<div class="row overflow-hidden">
	<div class="col-md-12">
		<div class="overflow-auto">
			<ul class="list-group" ondragstart="event.dataTransfer.setData('text', event.target.id);"
				@ondragover:preventDefault @ondragenter:preventDefault 
				@ondrop:preventDefault @ondrop:stopPropagation 
				@ondragenter:stopPropagation @ondragend:stopPropagation 
				@ondragover:stopPropagation @ondragleave:stopPropagation 
				@ondragstart:stopPropagation >
					
				@foreach (var item in _newPosition)
				{
					<li draggable="true"
						class="list-group-item dd-draggable  @CheckIfDragOperationIsInProgess() @GetClassForEnterDrag(item) @(item.IsActive ? "active" : "")"
						@onclick="()=> OnClick(item)"
						@ondragstart="()=>OnDragStart(item)"
						@ondragenter="()=>OnDragEnter(item)"
						@ondragleave="()=>OnDragLeave(item)"
						@ondragend="()=>OnDragEnd()">
					
						@if ( ItemRender != null  && item.Item != null  )
						{
							@ItemRender(item.Item)
						}
					</li>
				}
					
			</ul>
		</div>
	</div>	
</div>

Creamos una clase llamada DragDrop.razor.cs en la carpeta Share, esto creara el code-behind de nuestro componente y sustituimos la clase que creamos con el siguiente código.

using  DragAndDrop.Models;
using  Microsoft.AspNetCore.Components;

namespace DragAndDrop.Shared
{
	public partial class DragDrop<TItem>
	{
		[Parameter]
		public IEnumerable<TItem>? Items { get; set; }
		
		[Parameter]
		public RenderFragment<TItem>? ItemRender { get; set; }
		
		readonly List<DragDropModel<TItem>> _newPosition = new();		
		DragDropModel<TItem>? _selected;
		
		protected override void OnParametersSet()
		{
			if( Items != null)
			{
				_newPosition.Clear();
				int count = 1;				
				foreach ( var item in Items)
				{
					_newPosition.Add(new DragDropModel<TItem> { Index = count++, Item = item });
				}
			}
		}
		
		void OnClick(DragDropModel<TItem> item )
		{
			_newPosition.FindAll(x => x != item).ForEach(x => x.IsActive = false);
			item.IsActive = !item.IsActive;
		}
		
		void OnDragStart(DragDropModel<TItem> item )
		{
			_newPosition.ForEach(x => x.IsActive = false);
			_selected = item;
		}
		
		void OnDragLeave(DragDropModel<TItem> item )
		{
			
		}
		
		void OnDragEnter(DragDropModel<TItem> item )
		{
			if( _selected != null)
			{
				_selected.NewIndex = item.NewIndex > 0 ? item.NewIndex : item.Index;
				_newPosition.Remove(_selected);
				_newPosition.Insert(_selected.NewIndex - 1, _selected);
			}
			
			int count = 1;
			_newPosition.ForEach(x => x.NewIndex = count++);
		}
		
		void OnDragEnd()
		{
			if( _selected != null)
			{
				_selected.IsActive = true;
				_newPosition.Remove(_selected);
				_newPosition.Insert(_selected.NewIndex - 1, _selected);
				GenerateNewIndex();
				OnClick(_selected);
				_selected.IsActive = true;
				_selected = null;
			}
		}
		
		void GenerateNewIndex()
		{
			int count = 1;
			_newPosition.ForEach(x => { x.Index = count++; x.NewIndex = 0; });
		}
		
		string CheckIfDragOperationIsInProgess()
		{
			return _selected == null ? "" : "dd-inprogess";
		}
		
		string GetClassForEnterDrag(DragDropModel<TItem> item )
		{
			return  _selected != item || _selected == null ? "" : "dd-enter active";
		}
	}
}

Agregamos una hoja de estilos en la carpeta de share llamada DragDrop.razor.css para generar los estilos de la componente una vez agregada sustituimos con el siguiente código.

.dd-inprogess > * {
	pointer-events:none;
}

.dd-draggable {
	cursor:move;
}

.dd-enter {
	opacity:0.01;
}

Hasta este punto ya tenemos el componente para poder usarlo en nuestro sitio, para usarlo tendremos que modificar la página Index de la carpeta Page

Una vez abierta la página sustituir el código con el siguiente.

@page "/"

<PageTitle> Drag & Drop </PageTitle>

<div class="container">
	<h1> Drag & Drop </h1>
	<DragDrop TItem="int" Items="@(new List<int>{ 1,2,3,4,5,6,7,8,9 })">
		<ItemRender Context="item">
			@item
		</ItemRender>
	</DragDrop>	
</div>

Ahora ejecutamos el programa y ya podremos utilizar el drag and drop con cualquier tipo de dato que necesitemos, para comprobar esto sustituimos el código

<DragDrop TItem="int" Items="@(new List<int>{ 1,2,3,4,5,6,7,8,9 })">

por

<DragDrop TItem="string" Items="@(new List<string>{ "Elemento 1","Elemento 2","Elemento 3","Elemento 4","Elemento 5","Elemento 6","Elemento 7","Elemento 8","Elemento 9","Elemento 10" })">

Ejecutamos la aplicación y podremos ver que todo funciona igual mostrando los datos que le pasemos en el parámetro Items.

Te dejo el enlace al proyecto en GitHub.

signing



Commentarios