I have a Copy.cshtml page that copies an existing record and allows the user to create a new record based on the existing record. This works fine by creating the new record and returning to the Index.cshtml. What I need help with is being able to create the record AND return to the Index.cshtml that was filtered by a search (from the Copy.cshtml page).
For example, the user searches for all records for a certain client on the Index.cshtml page. They then want to copy one of those client records by clicking my Copy button next to one of the records, but want to return to the page that is already filtered for that client and see the new record they added along with the other records for that client. I don't know how to accomplish that.
I have 3 links on my Copy.cshml page. One is to Copy the record and return to the UNFILTERED index of all records (which works now), the 2nd is the Copy and return to the FILTERED index (which I need help with), while the 3rd is to just return to the unfiltered index without updating anything (basically a cancel the record copy which also works now).
Here is the code for that:
<div>
<button type="submit" id="CopyRetToIndex" class="btn btn-primary" style="width:150px;">Add Copy</button>
<button type="submit" asp-route-id="searchString" id="CopyRetToFilter" class="btn btn-primary" style="width:300px;">
Add Copy/Return to Filtered Search</button>
<a asp-page="Index" class="btn btn-secondary" style="width: 150px;">Back to List</a>
</div>
On the .cs side of things, I figure I need some type of 'if' statement to differentiate between these buttons, so I have this so far:
public async Task<IActionResult> OnPost()
{
if (ModelState.IsValid)
{
_db.Trip.Add(Trip);
await _db.Trip.AddAsync(Trip);
await _db.SaveChangesAsync();
TempData["success"] = "Trip copied successfully.";
return RedirectToPage("Index");
}
else if (ModelState.IsValid)
{
_db.Trip.Add(Trip);
await _db.Trip.AddAsync(Trip);
await _db.SaveChangesAsync();
TempData["success"] = "Trip copied successfully.";
return RedirectToPage("/Trips?SearchString=");
}
return Page();
}
I have researched on here and only found one question/answer that seems to cover what I need, but I don't fully understand how to implement that with what I already have. The post said to create a session for my search and the code they suggested was:
public ActionResult Search(string searchCriteria)
{
Session["searchCriteria"] = searchCriteria;
// do more stuff
}
Any assistance would be much appreciated. Not sure if I create this session information on the Index.cs or the Copy.cs as the Index.cs is where my search originates and how to work in my own items.
My Index.cs is this:
public async Task OnGetAsync(string sortOrder, string searchString)
{
TripSort = sortOrder == "ClientName_Asc_Sort" ? "ClientName_Desc_Sort" : "ClientName_Asc_Sort";
StatusSort = sortOrder == "Status_Asc_Sort" ? "Status_Desc_Sort" : "Status_Asc_Sort";
CurrentFilter = searchString;
IQueryable<Trip> trip = from s in _db.Trip select s;
if (!string.IsNullOrEmpty(searchString))
trip = (IQueryable<Trip>)trip.Where(s => s.ClientName.Contains(searchString) || s.PickUpDriver.Contains(searchString) || s.ReturnDriver.Contains(searchString) || s.PickUpDateTime.Value.ToString().Contains(searchString));
switch (sortOrder)
{
case "ClientName_Asc_Sort":
trip = trip.OrderBy(s => s.ClientName);
break;
case "ClientName_Desc_Sort":
trip = trip.OrderByDescending(s => s.ClientName);
break;
case "Status_Asc_Sort":
trip = trip.OrderBy(s => s.PickUpStatus);
break;
case "Status_Desc_Sort":
trip = trip.OrderByDescending(s => s.PickUpStatus);
break;
default:
trip = trip.OrderBy(s => s.ClientName);
break;
}
Trip = await trip.AsNoTracking().ToListAsync();
}
Thank you in advance!
Copy button added for comment request below (I don't know what to do with the Copy button specifically to add to the database and return to the filtered search.) This was a guess.
<a asp-page="Copy" asp-route-id="@obj.TripId" class="btn btn-primary mx-2">
<i class="bi bi-clipboard-check"></i>
</a>
I would say, first you need to tell Copy
page what the filter was. For example by using the copy button:
<a asp-page="Copy"
asp-route-id="@obj.TripId"
asp-route-sortOrder="@Model.StatusSort"
asp-route-searchString="@Model.CurrentFilter">
<i class="bi bi-clipboard-check"></i>
</a>
Then in your Copy.cshtml.cs
page, add the filter information to the GET request. It would be something like
public async Task OnGetAsync(int copyItemId, string? sortOrder, string? searchString)
{
this.PreviousSortOrder = sortOrder;
this.PreviousSearchString = searchString;
}
Now you can post this information back to the POST handler via the button in the razor file Copy.cshtml
something like this:
<button type="submit"
asp-page="Copy"
asp-route-sortOrder="@Model.PreviousSortOrder"
asp-route-searchString="@Model.PreviousSearchString"
id="CopyRetToFilter">
Add Copy/Return to Filtered Search
</button>
Again in Copy.cshtml.cs
, the POST handler now also takes the two filter values. Not sure what /Trips
is, but I removed it because the if/else if
had the same condition, so the else if
would never have run anyway:
public async Task<IActionResult> OnPost(string? sortOrder, string? searchString)
{
if (ModelState.IsValid)
{
_db.Trip.Add(Trip);
await _db.Trip.AddAsync(Trip);
await _db.SaveChangesAsync();
TempData["success"] = "Trip copied successfully.";
return RedirectToPage("Index", new { sortOrder, searchString });
}
return Page();
}
In general however, this feels like a very valid use case for some Ajax magic – send the copy request to the server asynchronously, receive back the new row, add it to the existing list without navigating the user away in the first place. This would keep the user’s scroll position and everything. Unless you want to avoid Javascript as much as possible, which would be understandable.