I'm working on an ASP.Net Core 6 project and I am trying to add a selection function to the rows of my table. My problem is that my selection function requires me to have access to the index of the selected object and I can't do that with IEnumerable. So, I'm wondering how I can change my code to bind my view to a list instead. I currently have a viewModel that contains properties that are populated from two different tables in the database that I need for my list.
EventListViewModel.cs
public class EventListViewModel
{
//from Events table
public int EventId { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string Type { get; set; }
//from Clients table
public int ClientId {get ; set; }
public string ContactName { get; set; }
public string Phone { get; set; }
}
EventController.cs (index action)
public IActionResult Index()
{
var result = from e in _db.Events
join c in _db.Clients on e.ClientId equals c.Id
select new EventListViewModel
{
EventId = e.Id,
StartDate = e.EventStart,
EndDate = e.EventEnd,
Type = e.Type,
ClientId = c.Id;
ContactName = c.Name,
Phone = c.Phone
}; //.ToList();
//.ToList() doesn't work here
return View(result);
}
In my Event/Index.cshtml I am binding the model as an IEnumerable, but I need it to be a list, so I can iterate through it.
@model IEnumerable<MyProject.ViewModels.EventListViewModel>
Event/Index.cshtml table looks like this
<tbody>
@foreach (var item in Model)
{
int index = Model.IndexOf(item);
//above line gives error IEnumerable does not contain a definition for IndexOf
<tr class="table-light selectable" controller="Event" Action="Selection" data-
id="@item.Id" data-index="@index">
<td>@item.Type </td>
<td>@item.StartDate.ToShortDateString()</td>
<td>@item.StartDate.TimeOfDay</td>
<td>@item.EndDate.TimeOfDay</td>
<td>@item.ContactName</td>
<td>@item.Phone</td>
</tr>
</tbody>
And here is the .js function for class selectable that needs to be able to get the item index
$((function () {
$(".selectable").on('click', (e) => {
e.preventDefault
var selectedRow = e.target.parentElement;
var id = $(selectedRow).data('id');
var index = $(selectedRow).data('index');
var controller = selectedRow.getAttribute("controller");
var action = selectedRow.getAttribute("action");
var url = "/" + controller + "/" + action + "/" + id;
var trArray = selectedRow.parentElement.getElementsByTagName('tr');
for (var row = 0; row < trArray.length; row++) {
if (row == index)
{
tdArray = selectedRow.getElementsByTagName('td');
for (var cell = 0; cell < tdArray.length; cell++)
{
tdArray[cell].style.backgroundColor = "yellow";
//need to remove hover for these cells
}
}
else
{
tdArray = trArray[row].getElementsByTagName('td');
for (var cell = 0; cell < tdArray.length; cell++)
{
tdArray[cell].style.backgroundColor = "#f8f9fa";
//need to add hover back into these cells
}
}
}
$.ajax({
url: url,
type: "POST",
success: function (response) {
$(".selectionResult").val(response);
$(".selectedId").val(id);
}
})
});
}()));
I'm pretty sure I can accomplish this by creating another ViewModel that contains just the list, and bind the cshtml file to that, but I'm wondering if there is a more elegant way of doing this, or if there is possibly some other way to write my selectable function to not require the index. Any help would be much appreciated.