Reputation: 33
I created a search bar like this
<form method="post" asp-action="Search">
<input type="text" name="search" placeholder="Enter here the Name " />
<select name="type" id="type" class="form-control">
<option value="Success">Inactive Reservation</option>
<option value="Approved">Active Reservation</option>
<option value="Pending">Pending Reservation</option>
</select>
<input type="submit" value="Search" />
</form>
and the method in controller:
public async Task<IActionResult> Search(string search,string type)
{
var allRsv = from m in _db.Reservation
select m;
var Rsv = allRsv
.Where(x => x.ClientName.ToLower().Contains(search.ToLower()) &&
x.Status.ToLower().Contains(type.ToLower()));
return View(Rsv);
}
What I want: to send in search page something like 'You searched for @search and type: @type.
return View has no option to do this ,neither return to action ..
Can I do it in a simple way ?
My single idea it is to send query string and then request query in search view
Upvotes: 1
Views: 1057
Reputation: 21526
Using ViewData
to pass data between controllers and views is fine as long as there are not many pieces of data in between. If you have lots of going, it will make everybody else harder to understand what's going on with ViewData
because it's a weak-typed and you have no idea what it contains, what's available to get, etc. And then you have to go back to the controller and see what's being passed. What if there are multiple controllers returning this same view...yucky!
In addition, it's not a good practice to display what you have from your database directly from the controller to the view.
Hence you should use one of the alternatives of ViewData
, that is ViewModel
, which is strongly-typed!
Since I don't have your database, for this demo, I am setting up two fake entity models that represent the data from your persistence storage.
namespace DL.NetCore.EmptySolution.Web.UI.Models.Reservation
{
public class FakeReservationStatusEntity
{
public string StatusId { get; set; }
public string Status { get; set; }
}
public class FakeReservationEntity
{
public int ReservationId { get; set; }
public int ClientId { get; set; }
public string ClientName { get; set; }
public DateTime StartTimeUtc { get; set; }
public FakeReservationStatusEntity ReservationStatus { get; set; }
public int CreatedByUserId { get; set; }
}
}
There is one-to-many relationship between reservation and reservation status I assumed. And please notice I purposely made it so that it has more properties than the view model!
They're just POCOs (Plain Old CLR Objects) that serve as data containers to travel between controllers and views.
namespace DL.NetCore.EmptySolution.Web.UI.Models.Reservation
{
public class ReservationFiltersViewModel
{
[Display(Name = "Client name")]
public string ClientNameSearchQuery { get; set; }
[Display(Name = "Reservation type")]
public string ReservationTypeSearchQuery { get; set; }
public IDictionary<string, string> AvailableReservationTypes { get; set; }
}
public class ReservationViewModel
{
public int ReservationId { get; set; }
public string ReservationType { get; set; }
public string ClientName { get; set; }
public DateTime StartTime { get; set; }
}
public class ReservationListViewModel
{
public ReservationFiltersViewModel Filters { get; set; }
public IEnumerable<ReservationViewModel> Reservations { get; set; }
}
}
namespace DL.NetCore.EmptySolution.Web.UI.Controllers
{
public class ReservationController : Controller
{
public IActionResult Index(string c, string t)
{
var vm = new ReservationListViewModel
{
Filters = new ReservationFiltersViewModel
{
ClientNameSearchQuery = c,
ReservationTypeSearchQuery = t,
// You would normally get the list from your database
AvailableReservationTypes = GetFakeReservationStatusesFromDb()
.ToDictionary(x => x.StatusId, x => x.Status)
},
Reservations = Enumerable.Empty<ReservationViewModel>()
};
// You would normally get the list of reservations from your database
var reservationsFromDb = GetFakeReservationsFromDb();
// Filters
if (!String.IsNullOrWhiteSpace(c))
{
reservationsFromDb = reservationsFromDb
.Where(x => x.ClientName.Contains(c, StringComparison.InvariantCultureIgnoreCase));
}
if (!String.IsNullOrWhiteSpace(t))
{
reservationsFromDb = reservationsFromDb
.Where(x => x.ReservationStatus.StatusId.Contains(t, StringComparison.InvariantCultureIgnoreCase));
}
// See you only want to explore what you want on the view
vm.Reservations = reservationsFromDb
.Select(x => new ReservationViewModel
{
ReservationId = x.ReservationId,
ClientName = x.ClientName,
ReservationType = x.ReservationStatus.Status,
StartTime = x.StartTimeUtc.ToLocalTime()
});
return View(vm);
}
[HttpPost]
public IActionResult Search(ReservationFiltersViewModel filters)
{
return RedirectToAction(nameof(Index),
new { c = filters.ClientNameSearchQuery, t = filters.ReservationTypeSearchQuery });
}
...
}
}
@model DL.NetCore.EmptySolution.Web.UI.Models.Reservation.ReservationListViewModel
@{
ViewBag.Title = "Reservations";
var selectList = new SelectList(Model.Filters.AvailableReservationTypes, "Key", "Value");
}
<h2>Reservations</h2>
<p class="text-muted">
List of reservations you can manage
</p>
<div class="row">
<div class="col-lg-4">
<div class="card">
<div class="card-body">
<form method="post" asp-area="" asp-controller="reservation" asp-action="search">
<div class="form-group">
<label asp-for="Filters.ClientNameSearchQuery"></label>
<input asp-for="Filters.ClientNameSearchQuery" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Filters.ReservationTypeSearchQuery"></label>
<select asp-for="Filters.ReservationTypeSearchQuery" class="form-control"
asp-items="selectList">
<option value="">- select -</option>
</select>
</div>
<button type="submit" class="btn btn-success">Search</button>
</form>
</div>
</div>
</div>
<div class="col-lg-8">
<!-- This could be better optimized, i.e., only display non-empty search -->
<div class="alert alert-info">
<i class="fas fa-info-circle"></i>
You searched for <strong>@Model.Filters.ClientNameSearchQuery</strong>
and <strong>@Model.Filters.ReservationTypeSearchQuery</strong>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Client name</th>
<th>Start from</th>
<th>Type</th>
</tr>
</thead>
<tbody>
@foreach (var reservation in Model.Reservations)
{
<tr>
<td>@reservation.ReservationId</td>
<td>@reservation.ClientName</td>
<td>@reservation.StartTime.ToShortDateString()</td>
<td>@reservation.ReservationType</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
With ViewModel
, there is no magic string flowing around like with ViewData
. Everything is strongly typed. And the form only posts back the filter model that contains only what we need to the server.
My demo project's source code is at https://github.com/davidliang2008/DL.NetCore.EmptySolution. The checkin specifically for this demo is at https://github.com/davidliang2008/DL.NetCore.EmptySolution/commit/32087b989de06e316cf747ad49da6ad4b24b61b8
Upvotes: 0
Reputation: 27815
What I want: to send in search page something like 'You searched for @search and type: @type.
You can try to pass data to search page via ViewData etc, like below.
In View Page
<form method="post" asp-action="Search">
<input type="text" name="search" placeholder="Enter here the Name " />
<select name="type" id="type" class="form-control">
<option value="Success">Inactive Reservation</option>
<option value="Approved">Active Reservation</option>
<option value="Pending">Pending Reservation</option>
</select>
<input type="submit" value="Search" />
</form>
<h3>You searched for "@ViewData["search"]" and type: @ViewData["type"].</h3>
In Action Method
public async Task<IActionResult> Search(string search, string type)
{
var allRsv = from m in _db.Reservation
select m;
var Rsv = allRsv
.Where(x => x.ClientName.ToLower().Contains(search.ToLower()) &&
x.Status.ToLower().Contains(type.ToLower()));
ViewData["search"] = search;
ViewData["type"] = type;
return View(Rsv);
}
Test Result
Upvotes: 0