Trigger sorting after cards have been added

I am automatically distributing cards to columns without the need for a user to drag and drop each one of them based on a predefined logic. 

Problem is I cannot get the columns to be sorted after the cards have been added. The integrated sorting of the kanban sorts them only if they have been manually added. I cannot afford to sort the datasource since it's already been sorted, because of our requirements for the distributing of cards to columns. 

Is there a way for me to loop through each column and change the indexes of cards based on our sorting logic?

<SfKanban @ref="sfKanban" KeyField="ApplicantStatus" DataSource="list" AllowDragAndDrop="true">

    <KanbanEvents TValue="RoomExamApplicantVM" ActionComplete="ActionCompleteHandler"></KanbanEvents>

    <KanbanColumns>

        @foreach (var item in model.RoomExamList)

        {

            <KanbanColumn HeaderText="@item.KeyField" KeyField="@(new List<string>() {@item.KeyField})" Visible="@item.isVisible" AllowToggle="true" MaxCount="item.CapacityAcceptable" AllowDrag="true" AllowDrop="true">

                <Template>

                    @{

                        KanbanColumn column = (KanbanColumn)context;


                        <div class="header-template-wrap">

                            <div class="header-text">@column.HeaderText</div>

                            <span class="d-block">Приоритет: @item.Priority</span>

                            <span class="d-block">Бр. Кандидати: @column.Count</span>

                        </div>

                    }

                </Template>

            </KanbanColumn>

        }


        <KanbanColumn KeyField="@(new List<string>() {"Undistributed"})" AllowDrag="true" AllowDrop="true">

            <Template>

                @{

                    KanbanColumn column = (KanbanColumn)context;

                    <div class="header-template-wrap">

                        <div class="header-text">Неразпределени<br />кандидати</div>

                        <span class="d-block">Бр. Кандидати: @column.Count</span>

                    </div>

                }

            </Template>

        </KanbanColumn>

    </KanbanColumns>


    <KanbanCardSettings HeaderField="IncomingNumber">

        <Template>

            @{

                RoomExamApplicantVM model = (context as RoomExamApplicantVM);

                bool HasEnglishExam = true;


                if (model.Applicant.HasEnglishCertificate == true)

                {

                    HasEnglishExam = false;

                }

                else

                {

                    HasEnglishExam = true;

                }


                <div class="p-0">

                    <div class="d-flex justify-content-between align-items-center">

                        <span class="badge bg-info">Вх. № : @model.Applicant.IncomingNumber</span>

                        @if (HasEnglishExam)

                        {

                            <span class="badge bg-warning text-dark ms-2">EN</span>

                        }

                    </div>

                    <div class="text-start p-2">

                        <div class="text-nowrap fw-bold" style="font-size: 12px;">@(model.Applicant.FullName)</div>

                        <div class="text-nowrap" style="font-size: 10px;">@model.Applicant.Country</div>

                    </div>

                </div>

            }

        </Template>

    </KanbanCardSettings>

</SfKanban>

code

{

public async Task AutoDistribute()

{

    if (model.UndistributedApplicants.Any())

    {

        this.ShowSpinner();


        int priorityCount = 1;

        var englishExamApplicants = model.UndistributedApplicants

            .Where(applicant =>

            {

                // If HasEnglishCertificate is true, they do not need the exam

                if (applicant.Applicant.HasEnglishCertificate == true)

                {

                    return false; // Exclude them

                }


                // If HasEnglishCertificate is false or null, check the citizenship

                return !countryList.Any(country =>

                    country.IdCountry == applicant.Applicant.IdCitizenship && country.isNativeEnglish);

            })

            .ToList();


        while (model.UndistributedApplicants.Count > 0 && model.RoomExamList.Any(room => room.Priority == priorityCount && room.RoomExamApplicantList.Count < room.Capacity))

        {

            var roomsByPriority = model.RoomExamList.Where(x => x.Priority == priorityCount).ToList();


            foreach (var roomExam in roomsByPriority)

            {

                // Skip this room if it's already full

                if (roomExam.RoomExamApplicantList.Count >= roomExam.Capacity)

                {

                    continue;

                }


                // Assign an applicant to this room

                if (englishExamApplicants.Count > 0)

                {

                    await MoveApplicant(roomExam, englishExamApplicants);

                }

                else if (model.UndistributedApplicants.Count > 0)

                {

                    await MoveApplicant(roomExam, model.UndistributedApplicants);

                }

            }


            // Move to the next priority level if all rooms in the current priority are full

            if (roomsByPriority.All(r => r.RoomExamApplicantList.Count >= r.Capacity))

            {

                priorityCount++;

            }

        }


        this.StateHasChanged();

        await sfKanban.RefreshAsync();

        this.HideSpinner();

    }

}


public async Task MoveApplicant(RoomExamVM roomExam, List<RoomExamApplicantVM> applicants)

{

    var applicant = applicants.ElementAt(0);

    applicants.Remove(applicant);

    model.UndistributedApplicants.Remove(applicant);

    applicant.IdRoomExam = roomExam.IdRoomExam; // Set the room ID for the applicant

    var newRoomExamApplicant = await SaveRoomExamApplicant(applicant);

    applicant.IdRoomExamApplicant = newRoomExamApplicant.ResultContextObject.IdRoomExamApplicant; // Set the room applicant ID for the applicant

    applicant.ApplicantStatus = roomExam.Room.RoomName;

    roomExam.RoomExamApplicantList.Add(applicant);

}


public async void ActionCompleteHandler(ActionEventArgs<RoomExamApplicantVM> args)

{

    if (args.ChangedRecords != null)

    {

        foreach (var movedApplicant in args.ChangedRecords)

        {

            RoomExamApplicantVM existingApplicant = new RoomExamApplicantVM();

            RoomExamVM existingRoomExam = new RoomExamVM();

            RoomExamVM destinationRoomExam = new RoomExamVM();


            if (model.RoomExamList.Any(x => x.Room.RoomName == movedApplicant.ApplicantStatus)) //Проверяваме дали преместеният апликант ще бъде

                                                                                                //разпределен или е върнат обратно в неразпределените

            {

                destinationRoomExam = model.RoomExamList.First(x => x.Room.RoomName == movedApplicant.ApplicantStatus);


                if (model.RoomExamList.SelectMany(x => x.RoomExamApplicantList).Any(x => x.IdApplicant == movedApplicant.IdApplicant)) //Проверяваме дали апликанта е разпределен

                {

                    existingApplicant = model.RoomExamList.SelectMany(x => x.RoomExamApplicantList) //Взимаме апликанта с предишен IdRoomExam

                                                          .First(x => x.IdApplicant == movedApplicant.IdApplicant);


                    existingRoomExam = model.RoomExamList.First(x => x.IdRoomExam == existingApplicant.IdRoomExam); //Взимаме стаята, в която се намира апликанта


                    if (existingRoomExam.IdRoomExam != destinationRoomExam.IdRoomExam)

                    {

                        existingRoomExam.RoomExamApplicantList.Remove(existingApplicant); //Премахваме апликанта от стаята, в която се намира


                        existingApplicant.IdRoomExam = destinationRoomExam.IdRoomExam; //Променяме IdRoomExam на апликанта с този на стаята, в която ще се премести


                        var newRoomExamApplicant = await SaveRoomExamApplicant(existingApplicant);


                        existingApplicant.IdRoomExamApplicant = newRoomExamApplicant.ResultContextObject.IdRoomExamApplicant;


                        destinationRoomExam.RoomExamApplicantList.Insert(0, existingApplicant); //Добавяме апликанта в новата стая

                    }

                }

                else

                {

                    existingApplicant = model.UndistributedApplicants.First(x => x.IdApplicant == movedApplicant.IdApplicant); //Взимаме апликанта от неразпределените


                    model.UndistributedApplicants.Remove(existingApplicant); //Премахваме го от неразпределените


                    existingApplicant.IdRoomExam = destinationRoomExam.IdRoomExam; //Слагаме му новия IdRoomExam


                    var newRoomExamApplicant = await SaveRoomExamApplicant(existingApplicant);


                    existingApplicant.IdRoomExamApplicant = newRoomExamApplicant.ResultContextObject.IdRoomExamApplicant; //Променяме IdRoomExamApplicant на апликанта с новия


                    destinationRoomExam.RoomExamApplicantList.Insert(0, existingApplicant); //Добавяме го в новата стая

                }

            }

            else

            {

                if (model.RoomExamList.SelectMany(x => x.RoomExamApplicantList).Any(x => x.IdApplicant == movedApplicant.IdApplicant)) //Проверяваме дали апликантът съществува в някоя от залите

                {

                    existingApplicant = model.RoomExamList.SelectMany(x => x.RoomExamApplicantList) //Взимаме апликанта с предишен IdRoomExam

                                                      .First(x => x.IdApplicant == movedApplicant.IdApplicant);


                    existingRoomExam = model.RoomExamList.First(x => x.IdRoomExam == existingApplicant.IdRoomExam); //Взимаме стаята, в която се намира апликанта


                    await DeleteRoomExamApplicant(existingApplicant);

                    existingRoomExam.RoomExamApplicantList.Remove(existingApplicant); //Премахваме апликанта от стаята, в която се намира


                    existingApplicant.IdRoomExam = 0; //Променяме IdRoomExam на апликанта с този на стаята, в която ще се премести

                    existingApplicant.IdRoomExamApplicant = 0;


                    model.UndistributedApplicants.Insert(0, existingApplicant); //Добавяме апликанта в новата стая

                }

            }

        }

        StateHasChanged();

    }

}

}


5 Replies 1 reply marked as answer

KP Kokila Poovendran Syncfusion Team January 22, 2025 11:03 AM UTC

Hi Lyubo,


We understand that you are distributing cards to columns programmatically based on a predefined logic and need to trigger sorting after the cards have been added. In this scenario, you can utilize the KanbanSortSettings property to apply sorting to the cards in the Kanban board.

This property allows you to specify the sorting logic, ensuring the cards are sorted in each column according to your requirements without affecting the data source.

For detailed information and examples, please refer to the documentation linked below:

Documentation https://blazor.syncfusion.com/documentation/kanban/sort



LY Lyubo January 24, 2025 08:47 AM UTC

Hi,

Problem is that using this method the sorting is kind of random. It's like it isn't sorting by the parameter i have given it. Here is a screenshot demonstrating the issue

Image_9819_1737708372774

The Number on top is the field given in the kanban sorting settings and the SortBy is SortOrderBy.Custom



KP Kokila Poovendran Syncfusion Team January 27, 2025 12:31 PM UTC

Hi Lyubo,


We have reviewed your query, and we would like to clarify that when using SortOrderBy.Custom, the sorting is performed based on string values. This can lead to the cards being sorted in lexicographical order rather than numerically, which might explain the issue you're facing.

If you wish to sort the cards based on integer values, we recommend using SortOrderBy.Index. This ensures that the cards are sorted numerically.

For example, if you are using strings like "Bx. No: 122," we suggest storing the numeric portion in a separate variable for sorting purposes and displaying it within the card as needed.

For more details about the SortOrderBy.Index property, please refer to the following documentation:

https://blazor.syncfusion.com/documentation/kanban/sort#index


Marked as answer

LY Lyubo replied to Kokila Poovendran January 31, 2025 10:29 AM UTC

Turned out the problem was exactly that. The number on top of the card was in a string value, converting it to int fixed the issue. Thank you for the support!



KG Kalpana Ganesan Syncfusion Team January 31, 2025 11:56 AM UTC

Hi Lyubo,


You are welcome. Please reach out to us for further assistance.


Loader.
Up arrow icon