Reputation: 49
In a Visual Studio 2019 Web application EF Core, I have a razor page with a list of projects. Each project has several columns with resource names. I would like to be able to filter with multiple drop-downs. I have managed to build the page and the filters, but they only work if I select an entry in both drop-downs. I do not get any error if I use them independently. The two search strings are displayed correctly in the URL /Projects?fosearchString=1&dsmsearchString=0
, but the result does not update if I only use one of the drop-down entries.
I want the drop-down filters to work independently and together (e.g. FO only, DSM only, FO and DSM together). How can I achieve this?
I have the resource model:
public class Resource
{
[Display(Name = "ID")]
public int Id { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Long Name")]
public string LongName { get; set; }
[Display(Name = "Active")]
public bool IsActive { get; set; }
public ICollection<ProjectResource> ProjectResources { get; set; }
}
The project model:
public class Project
{
[Display(Name = "ID")]
public int Id { get; set; }
[Display(Name = "PID")]
public int PID { get; set; }
[Display(Name = "Name")]
public string ProjectName { get; set; }
[Display(Name = "Forecast Owner")]
public int FOId { get; set; }
public Resource Resource { get; set; }
[Display(Name = "DSM")]
public int DSMId { get; set; }
public Resource DSMResource { get; set; }
public ICollection<ProjectResource> ProjectResources { get; set; }
}
The index.cshtml.cs:
public IList<Project> Project { get; set; }
public IList<Resource> Resources { get; set; }
public SelectList FOOptions { get; set; }
public string CurrentFOFilter { get; set; }
public SelectList Options { get; set; }
public string CurrentDSMFilter { get; set; }
public async Task<IActionResult> OnGetAsync(List<int> fosearchString, List<int> dsmsearchString)
{
FOOptions = new SelectList(_context.Resource, nameof(Resource.Id), nameof(Resource.LongName));
List<int> CurrentFOFilter = fosearchString;
Options = new SelectList(_context.Resource, nameof(Resource.Id), nameof(Resource.LongName));
List<int> CurrentDSMFilter = dsmsearchString;
if (fosearchString.Count == 0 || fosearchString[0] == 0 && dsmsearchString.Count == 0 || dsmsearchString[0] == 0)
{
Resources = await _context.Resource.ToListAsync();
Project = await _context.Project
.Include(p => p.Resource).ToListAsync();
}
else
{
Resources = await _context.Resource.ToListAsync();
Project = await _context.Project
.Include(p => p.Resource)
.Where(s => fosearchString.Contains(s.FOId) && dsmsearchString.Contains(s.DSMId))
.ToListAsync();
}
return Page();
}
the index.cshtml:
<form asp-page="./Index" method="get">
<div class="dropdown col-4 no-gutters">
<div class="input-group mb-3">
<select class="custom-select" name="fosearchString" value="@Model.CurrentFOFilter" asp-items="Model.FOOptions" selected="selected"><option value="0">Filter by FO...</option></select><text> </text>
<select class="custom-select" name="dsmsearchString" value="@Model.CurrentDSMFilter" asp-items="Model.Options" selected="selected"><option value="0">Filter by DSM...</option></select><text> </text>
</div>
<input type="submit" value="Filter" class="btn btn-primary" /><text> </text><input type="submit" action="/Projects/Index" value="Back to full List" class="btn btn-primary" />
</div>
</form>
<br />
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Project[0].PID)
</th>
<th>
@Html.DisplayNameFor(model => model.Project[0].ProjectName)
</th>
<th>
@Html.DisplayNameFor(model => model.Project[0].FOId)
</th>
<th>
@Html.DisplayNameFor(model => model.Project[0].DSMId)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model.Project)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.PID)
</td>
<td>
@Html.DisplayFor(modelItem => item.ProjectName)
</td>
<td>
@{
var foresource = Model.Resources.FirstOrDefault(r => r.Id == item.FOId);
}
@foresource.LongName
</td>
<td>
@{
var dsmresource = Model.Resources.FirstOrDefault(r => r.Id == item.DSMId);
}
@dsmresource.LongName
</td>
I use two view models called ProjectVM and ResourceVM to bring the two models together and also have many-to-many relationships between the two models setup via a ProjectResource class.
Upvotes: 0
Views: 1459
Reputation: 20116
The problem lies in your if
and else
conditions, besides, you need to add brackets since &&
is prior to ||
.
You could always add breakpoints to check which condition it comes into when you filter.
A workable solution below is to set the first option value as ""
instead of 0
which will be more convenient to search all:
Index.cshtml:
<div class="input-group mb-3">
<select class="custom-select" name="fosearchString" value="@Model.CurrentFOFilter" asp-items="Model.FOOptions" selected="selected"><option value="">Filter by FO...</option></select><text> </text>
<select class="custom-select" name="dsmsearchString" value="@Model.CurrentDSMFilter" asp-items="Model.Options" selected="selected"><option value="">Filter by DSM...</option></select><text> </text>
</div>
Index.cshtml.cs:
public async Task<IActionResult> OnGetAsync(List<int> fosearchString, List<int> dsmsearchString)
{
FOOptions = new SelectList(_context.Resource, nameof(Resource.ID), nameof(Resource.LongName));
List<int> CurrentFOFilter = fosearchString;
Options = new SelectList(_context.Resource, nameof(Resource.ID), nameof(Resource.LongName));
List<int> CurrentDSMFilter = dsmsearchString;
if (fosearchString.Count == 0 && dsmsearchString.Count == 0)
{
Resources = await _context.Resource.ToListAsync();
Project = await _context.Project.Include(p => p.Resource).ToListAsync();
}
else if(fosearchString.Count != 0 && dsmsearchString.Count == 0)
{
Resources = await _context.Resource.ToListAsync();
Project = await _context.Project
.Include(p => p.Resource)
.Where(s => fosearchString.Contains(s.FOId))
.ToListAsync();
}
else if (fosearchString.Count == 0 && dsmsearchString.Count != 0)
{
Resources = await _context.Resource.ToListAsync();
Project = await _context.Project
.Include(p => p.Resource)
.Where(s => dsmsearchString.Contains(s.DSMId))
.ToListAsync();
}
else
{
Resources = await _context.Resource.ToListAsync();
Project = await _context.Project
.Include(p => p.Resource)
.Where(s => fosearchString.Contains(s.FOId) && dsmsearchString.Contains(s.DSMId))
.ToListAsync();
}
return Page();
}
Upvotes: 1