So I've added sortablejs to my blazor application, and it works - for the first drag n drop.
First, here's what's happening:
Blazor component code:
<ul class="ulManufacturers">
@foreach (var m in manufacturers)
{
var mGrayedOut = m.Visible ? "" : "grayout";
var toggleButtonImg = showManufacturerBikes[m] ? "up" : "down";
var toggleButtonTitle = showManufacturerBikes[m] ? $"Sakrij {m.Nickname} motore" : $"Prikaži {m.Nickname} motore";
<li data-id="@m.Id">
<div class="divManufacturerHeader">
<div class="buttons">
<img class="zoom-on-hover cursor-grab fit-image grayout drag-handle"
src="/lib/bootstrap-icons-1.5.0/list.svg"
data-toggle="tooltip" data-placement="top"
title="Uhvati i premesti"/>
<img class="zoom-on-hover cursor-pointer fit-image grayout"
src="/lib/bootstrap-icons-1.5.0/plus-circle.svg"
data-toggle="tooltip" data-placement="top"
title="Dodaj novi @m.Nickname motor"
@onclick="()=>AddBike(m)" />
<img class="zoom-on-hover cursor-pointer fit-image grayout"
src="/lib/bootstrap-icons-1.5.0/arrow-@(toggleButtonImg)-circle.svg"
data-toggle="tooltip" data-placement="top"
title="@toggleButtonTitle"
@onclick="()=>ToggleBikes(m)" />
</div>
<div class="divLogoOrName">
@if (string.IsNullOrEmpty(m.LogoUrl))
{
<h1 class="zoom-on-hover cursor-pointer @mGrayedOut"
@onclick="()=>SelectManufacturer(m)">
@m.Nickname
</h1>
}
else
{
<img class="zoom-on-hover cursor-pointer fit-image imgManufacturerLogo @mGrayedOut"
src="@m.LogoUrl"
@onclick="()=>SelectManufacturer(m)" />
}
</div>
</div>
<div class="divBikeThumbnailsContainer sortable-list @(showManufacturerBikes[m] ? "" : "hidden")">
@foreach (var b in m.Bikes)
{
var bGrayedOut = b.Visible ? string.Empty : "grayout";
<div class="sortable-list-grid-item drag-handle @bGrayedOut" @onclick="() => SelectBike(b)">
<img class="zoom-on-hover cursor-grab fit-image grayout"
src="/lib/bootstrap-icons-1.5.0/list.svg"
data-toggle="tooltip" data-placement="top"
title="Uhvati i premesti" />
<BikeThumbnailPage Bike="b" />
</div>
}
</div>
</li>
}
@if (showButtonAddManufacturer)
{
<li>
<div class="divManufacturerHeader">
<img class="zoom-on-hover cursor-pointer fit-image grayout"
src="/lib/bootstrap-icons-1.5.0/plus-circle.svg"
data-toggle="tooltip" data-placement="top"
title="Dodaj novog proizvodjača"
@onclick="AddManufacturer" />
</div>
</li>
}
</ul>
@code {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
var objRef = DotNetObjectReference.Create(this);
await jsRuntime.InvokeVoidAsync("EnableManufacturerSorting", objRef);
}
await base.OnAfterRenderAsync(firstRender);
}
[JSInvokable]
public void OnManufacturerDragStart()
{
// hide all manufacturer bikes
foreach (var m in manufacturers)
showManufacturerBikes[m] = false;
showButtonAddManufacturer = false;
StateHasChanged();
}
[JSInvokable]
public async void OnManufacturerDragEnd(int[] ids)
{
showButtonAddManufacturer = true;
// set order numbers for manufacturers
for (int orderNo = 0; orderNo < ids.Length; orderNo++)
manufacturers
.First(m => m.Id == ids[orderNo])
.OrderNumber = orderNo;
_manufacturerService.UpdateAll(manufacturers);
//ReloadManufacturers();
//StateHasChanged();
//var objRef = DotNetObjectReference.Create(this);
//await jsRuntime.InvokeVoidAsync("EnableManufacturerSorting", objRef);
}
}
JavaScript function that's fired on
function EnableManufacturerSorting(dotNetHelper) {
$('.ulManufacturers').each(function() {
new Sortable(this, {
group: 'manufacturers',
handle: '.drag-handle',
direction: 'vertical',
animation: 150,
onStart: function () {
console.log("onStart");
dotNetHelper.invokeMethodAsync('OnManufacturerDragStart');
},
onEnd: function () {
console.log("onEnd");
var orderList = [];
$(this.el).children().each(function (index, element) {
orderList.push($(element).data('id'));
});
var params = JSON.stringify({ 'orderList': orderList });
dotNetHelper.invokeMethodAsync('OnManufacturerDragEnd', orderList);
//dotNetHelper.dispose();
//this.destroy();
},
});
});
}
As you can see from comments in JS function and OnManufacturerDragEnd blazor function, I've tried all combinations with and without commented code, but the result is the same
UPDATE 1
I've found out that if I remove
// set order numbers for manufacturers
for (int orderNo = 0; orderNo < ids.Length; orderNo++)
manufacturers
.First(m => m.Id == ids[orderNo])
.OrderNumber = orderNo;
_manufacturerService.UpdateAll(manufacturers);
from public async void OnManufacturerDragEnd(int[] ids) it works fine -> but I end up not saving the new order of items.
Same if I leave that in but remove
showButtonAddManufacturer = true;
StateHasChanged();
That means will either not save the new order or that I can't hide the button 'add new' (the plus circle at the bottom of the gif, at the bininging), and bring it back.
I suspect there's asynchronicity between sortablejs and blazors rendering, I just can't quite figure it out yet. The 'add new' button might have something to do with it
UPDATE 2
Check my answer, I've found a workaround. The question is now -> what is exactly happening on the second drag? I'll accept your answer if you can just explain to me what is happening.
from sortablejs changes order on second dragStart

No comments:
Post a Comment