I'm trying to make a UI component that allows for easy sorting by drag-drop. I used a library to get started: https://github.com/Postlagerkarte/blazor-dragdrop
Here is my setup:
Components/ApproverPriorityList.razor
@using Project.ViewModels.PrimaryDb
@using Project.ViewModels.PrimaryDb.Datasets
<div id="main" class="container-fluid">
<DxComboBox Data="@AllResources" TextFieldName="@nameof(ResourceViewModel.Text)" @bind-Value="@_newApprover" />
<DxButton Text="Add" @onclick="AddApprover" />
<hr />
<Dropzone Items="LoadedApprovers">
<ApproverItem OnRemoveClick="(item) => LoadedApprovers.Remove(item)" Item="@context"></ApproverItem>
</Dropzone>
</div>
@code{
[Parameter]
public IList<ApproverTemplateDetailViewModel> LoadedApprovers { get; set; }
[Parameter]
public IList<ResourceViewModel> AllResources { get; set; }
private string _newApprover;
private void AddApprover()
{
if (string.IsNullOrWhiteSpace(_newApprover)) return;
LoadedApprovers.Add(new ApproverTemplateDetailViewModel
{
ApproverResourceId = _newApprover,
ApprovalLevel = byte.Parse((LoadedApprovers.Count + 1).ToString()),
});
_newApprover = string.Empty;
}
}
Components/ApproverItem.razor
@using Project.ViewModels.PrimaryDb
<div class="approverItemStyle">
<DxButton Text="" @onclick="@(() => OnRemoveClick.InvokeAsync(Item))" />
<i class="fad fa-user fa-fw theme-da"></i>
@Item.ApproverResourceId
</div>
@code {
[Parameter]
public ApproverTemplateDetailViewModel Item { get; set; }
[Parameter]
public EventCallback<ApproverTemplateDetailViewModel> OnRemoveClick { get; set; }
}
Models
namespace Project.ViewModels.PrimaryDb
{
public class ApproverTemplateDetailViewModel
{
public ApproverTemplateDetailViewModel() { }
public ApproverTemplateDetailViewModel(ApproverTemplateDetail model)
{
Id = model.Id;
ApproverResourceId = model.ApproverResourceId;
ApprovalLevel = model.ApprovalLevel;
}
public int Id { get; set; }
public string ApproverResourceId { get; set; }
public byte ApprovalLevel { get; set; }
}
public class ResourceViewModel
{
public ResourceViewModel() { }
public ResourceViewModel(DataResource model)
{
Email = model.Email;
Name = model.FullName;
}
public string Email { get; set; }
public string Text => $"{Name} ({Email})";
}
}
Pages/Request-New.razor
@page "/request-new"
@using ProjectWeb.Services.Interfaces
@using Project.PrimaryDb
@using Project.PrimaryDb.Datasets
@using Project.PrimaryDb.Lookups
@inject IResourceService ResourceProviderService
@inject IApproverTemplateService ApproverTemplateProviderService
<EditForm Model="@_model" CaptionPosition="CaptionPosition.Vertical" Context="editFormContext" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<DxFormLayout CssClass="dxFormLayoutHeaderStyle">
<DxFormLayoutGroup Caption="Approvers" ColSpanMd="12">
<DxFormLayoutItem Caption="List:" ColSpanMd="6">
<Template>
<ApproverPriorityList LoadedApprovers="@_approverListData"></ApproverPriorityList>
</Template>
</DxFormLayoutItem >
</DxFormLayoutGroup>
</DxFormLayout>
</EditForm>
@code {
private BudgetReleaseRequestViewModel _model = new BudgetReleaseRequestViewModel();
private ApproverTemplateViewModel _selectedTemplate;
private IList<ResourceViewModel> _localResources;
private IList<ApproverTemplateViewModel> _approverHeadData;
private IList<ApproverTemplateDetailViewModel> _approverListData = new List<ApproverTemplateDetailViewModel>();
protected override async Task OnInitializedAsync()
{
@ = (await ResourceProviderService.GetAllResources()).ToList();
_approverListData = (await ApproverTemplateProviderService.GetAllApproverTemplateDetails()).ToList();
_approverListData = _approverListData.Where(w => w.TemplateId == 1).ToList();
}
private void HandleValidSubmit(EditContext editContext)
{
}
}
CSS
/*add this to avoid flickering*/
.plk-dd-inprogess > * {
pointer-events: none;
}
/*dropzone style style*/
.plk-dd-dropzone {
min-height: 50px;
}
/*drag drop styles*/
.plk-dd-spacing {
height: 10px;
}
.plk-dd-spacing-dragged-over {
padding: 25px;
}
.plk-dd-dragged-over {
background-color: lightgray;
opacity: 0.6;
animation: blinker 1s linear infinite;
}
.plk-dd-dragged-over > div {
background-color: lightgray;
opacity: 0.6;
animation: blinker 1s linear infinite;
}
.plk-dd-dragged-over-denied {
background-color: red;
opacity: 0.6;
animation: blinker 1s linear infinite;
}
.plk-dd-in-transit {
opacity: 0;
}
.plk-dd-in-transit > div {
opacity: 0;
}
@keyframes blinker {
50% {
opacity: 0;
}
}
.blink_me {
animation: blinker 1s linear infinite;
}
/*for flex demo*/
.plk-flex .plk-dd-spacing {
width: 20px;
height: auto;
}
.plk-flex .plk-dd-dragged-over {
background-color: lightgray;
opacity: 0.6;
animation: blinker 1s linear infinite;
}
.plk-flex .plk-dd-dragged-over > div {
background-color: lightgray;
opacity: 0.9;
animation: blinker 1s linear infinite;
}
.plk-flex .plk-dd-in-transit {
background-color: orangered;
}
.plk-flex .plk-dd-in-transit > div {
background-color: orangered;
}
.plk-dd-noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
Now, I have the UI working visually: I can drag & drop row to sort out. I need to add mechanism to hold sort order somehow in code. I have no idea where to begin on that? In my class ApproverTemplateDetailViewModel
, there is a property ApprovalLevel
that I want to hold the sort order
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…