Keep Filter from HttpPost on next page of PaginatedList in ASP.NET Core MVC - asp.net

I am creating a program in which I have a Database with records I want to filter.
The filter has 4 input type="text" and returns the right records based on the filters I typed.
The problem is, when I click Next Page link (of PaginatedList), the second page has no filters adapted.
It lose the filters I gave. I know I must give asp-route on Next Page link some variable with the data given in filter like Microsoft Tutorial gives currentFilter, but I have 4 filters like this :
Name=x&Phone=y&...
Here is my Controller Code simplyfied :
public async Task<IActionResult> Index( some variables ){
var appusers = from a in _context.AppUsers
select a;
return(return View(await app.PaginatedList<AppUser>.CreateAsync(appusers.AsNoTracking(), pageNumber ?? 1, pageSize));)
}
AND
[HttpPost]
public async Task<IActionResult> Index(string Name, string Phone, string Calls, string Date){
var ap = from c in _context.AppUsers
select c;
Filter The database based on variable values Name,Phone,Calls,Date
return View(await PushNotificationApp.PaginatedList<AppUser>.CreateAsync(ap.AsNoTracking(),
pageNumber?? 1, pageSize));}
Here is the part of Index :
#using (Html.BeginForm("Index", "AppUsers", new { id = "filterForm" }))
{
name="SearchTrips" value="#ViewData["CurrentTrips"]" />
<input id="NameFilterField" type="text" name="Name" />
<input id="PhoneFilterField" type="text" name="Phone" />
<input id="CallsFilterField" type="text" name="Calls" />
<input id="DateFilterField" type="text" pattern="\d{1,2}/\d{1,2}/\d{4}" name="Date" />
<button class="m-3" type="submit" value="submit">Search</button>
}
AND PAGELIST LINK PART :
<div class="p-2 bd-highlight">
<nav aria-label="Page navigation example">
<ul class="pagination">
<li class="page-item">
<a class="page-link MainButton" asp-action="Index"
asp-route-pageNumber="#(Model.PageIndex - 1)"
asp-route-currentFilter="#ViewData["CurrentFilter"]"
class="page-link #prevDisabled">
Previous
</a>
</li>
<li class="page-item">
<a class="page-link MainButton" asp-action="Index"
asp-route-pageNumber="#(Model.PageIndex + 1)"
asp-route-currentFilter="#ViewData["CurrentFilter"]"
Next
</a>
</li>
</ul>
</nav>
</div>

The problem is, when I click Next Page link (of PaginatedList), the second page has no filters adapted. It lose the filters I gave.
You are doing the filter in the Post action, but when you click the Next link, it will go to the Get action which not filter. So, I think you can make the form do a get request and just do the filter in the Get method.
I know I must give asp-route on Next Page link some variable with the data given in filter like Microsoft Tutorial gives currentFilter, but I have 4 filters like this : Name=x&Phone=y&...
4 filters is the same, just give the other filter parameters to the Next link
<a class="page-link MainButton" asp-action="Index"
asp-route-pageNumber="#(Model.PageIndex + 1)"
asp-route-Name="#ViewData["Name"]"
asp-route-Phone="#ViewData["Phone"]"
asp-route-Calls="#ViewData["Calls"]"
asp-route-Date="#ViewData["Date"]"
Next
</a>

why not use a single box to search everything or four search boxes using the method below in the tutorial?
if (!String.IsNullOrEmpty(searchString))
{
students = students.Where(s => s.LastName.Contains(searchString)
|| s.FirstMidName.Contains(searchString));
}

Related

ASP.NET how to pass value from form to another page

i have page with the url that show my list of items:
https://localhost:123/AllSystems/List?systemTypeID=1
and inside this page i have search (i pass SearchTerm to list.cshtml.cs file ):
<form method="get">
<div class="form-group">
<div class="input-group">
<input type="search" class="form-control" asp-for="SearchTerm" />
<button type="button" class="btn btn-danger">
<span class="glyphicon glyphicon-search"></span> **Search**
</button>
</div>
</div>
</form>
when i click on Search button (inside the search form) i go to url:
https://localhost:123/AllSystems/List?SearchTerm=nba
that fine but i want to pass the systemTypeID=1 to from last url
(https://localhost:123/AllSystems/List?systemTypeID=1).
how i do it?
i want the result be something like that:
https://localhost:123/AllSystems/List?systemTypeID=1&SearchTerm=nba
thank's
you can pass multiple dynamic values to QueryString as below
you can set Value1 and Value2 and pass that values to your query string as below
string value1="1";
string value2="nba";
Response.Redirect("https://localhost:123/AllSystems/List?systemTypeID"+value1+"&SearchTerm="+value2);
in second page you can access the value like
string typeid= Request.QueryString["systemTypeID"];
string searchvalue = Request.QueryString["SearchTerm"];

data-reveal loading partial view MVC

I have the following code on my cshtml page:
<div class="large reveal" id="draftProductModal" data-reveal>
<button class="close-button" data-close aria-label="Close modal" type="button">
<span aria-hidden="true"><i class="fa fa-times-circle-o"></i></span>
</button>
</div>
<div class="input-group">
<input type="text" class="input-group-field" id="draftSearchProducts" name="draftSearchProducts" placeholder="SearchProducts" />
<div class="input-group-button">
<!--Add product to order lines button-->
<a id="draftAddProduct" class="hollow button secondary" data-open="draftProductModal"><i class="fa fa-plus"></i> Search Products</a>
</div>
</div>
I need to take the value in the draftSearchProducts text field, pass it to a controller that returns a partialview:
public ActionResult SearchResults(string keywords, int queryLimit = 20, int offset = 0)
{
try
{
//connect to db, grab data return results
searchResults.ProductDetails = products.ToList();
return PartialView("_SearchResults", searchResults);
}
catch (Exception ex)
{
throw ex;
}
}
I need to send in the keyword to the controller, return the partial view and load it into the draftProductModal div and display the div. How is this done? I am new to front end development.
Tried this code:
var url = '/ProductsController/SearchResults';
$('#draftAddProduct').click(function () {
var keyWord = $('draftSearchProducts').val();
$('#draftProductModal').load(url, { keywords: keyWord });
});
And all I get is a 404 error, so it appears I am not hitting my controller. I think I am getting close, I just need to find out how to access the controller ActionResult. Still accepting help.

Issue with pagination in PagedList MVC

I am using MVC PagedList to handle pagination in my project. Everything works fine except that in my controller I have to initialize pageNumber parameter with "1" (Default page number). The problem is the blue activated button on page 1 that remains there no matter which page button link you click. Moreover this button is also missing the actionLink.
One last thing I am integrating my search with pagination as you can see in the controller code.
public PartialViewResult List_Items(string keyword, int? page)
{
var newlists = from s in db.TrMs
orderby s.S1
select s;
int pageNumber = (page ?? 1);
int pageSize = 10;
var data = newlists.Where(f => f.S1.ToString().Contains(keyword) && f.S100 == vt).ToPagedList(pageNumber, pageSize);
return PartialView(data);
}
Here is the generated Html for PagedList in my view
<div class="pagination-container">
<ul class="pagination">
<li class="active">
<a>1</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=2">2</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=3">3</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=4">4</a>
</li>
<li class="PagedList-skipToNext">
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=2" rel="next">»</a>
</li>
</ul>
</div>
Here is how I am using the pagination helper.
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("List_Items", "TrM", new {keyword="", page }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "searchResult" }))
Your paging controls are most likely outside of the searchResult container. When you click on a page you're replacing the table but not the paging controls. Move your paging controls inside of your searchResult container!
Hope this helps.

How can I elegantly preserve filter parameters when paginating with Thymeleaf?

On many of my pages, I have several options to sort or filter a long listing of results.
I'd like to have those selections preserved properly when someone pages through the data. For example:
Start looking at the list of all tickets. (/tickets)
Search for all tickets like "foo." (/tickets?query=foo)
Go to the next page. (/tickets?query=foo&page=2)
See the next page of tickets like "foo", not the 2nd page of "all tickets." (e.g. not /tickets?page=2)
In JSP, I came up with a solution like this:
<c:if test="${page.hasNext()}">
<spring:url value="" var="nextLink">
<c:forEach items="${param}" var="curParam">
<c:if test="${curParam.key != 'page'}">
<spring:param name="${curParam.key}" value="${curParam.value}"/>
</c:if>
</c:forEach>
<spring:param name="page" value="${page.nextPageable().pageNumber}"/>
</spring:url>
<li>
<a href="${nextLink}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
</c:if>
That basically constructs a new URL pointing to the same path as the current page, but adds/replaces the "path" parameter to it's query parameters.
It's pretty ugly in JSP, but I don't see a way to really do this at all in Thymeleaf?
Or, perhaps there's some better way to do this using some Spring or Thymeleaf feature I haven't encountered yet?
My hope is to have a concise Thymeleaf fragment I can reuse everywhere I need pagination. So far, this is all I have, but it ends up missing missing the "query" parameter, etc. (I don't want to hard-code the query parameter here, because that would limit the reusability of this pagination code)
<li th:if="${page.hasNext()}">
<a href="pagination.html" th:href="#{''(page=${page.nextPageable().pageNumber})}" aria-label="next">
<span aria-hidden="true">»</span>
</a>
</li>
Maybe this will be usefull for someone using HTML and Spring with Thymeleaf.
In my case I use thymeleaf with spring. I have a DTO as a filter that is used in the controller to do the filtering.
public class Controller {
private final int BUTTONS_TO_SHOW = 5;
public String home(FilterDTO filterDTO #PageableDefault(size = 50) Pageable pageable, Model model){
List<YourEntity> rows = YourEntityService.findAll();
Pager pager = new Pager(rows.getTotalPages(), rows.getNumber(), BUTTONS_TO_SHOW);
model.addAttribute("rows", rows);
model.addAttribute("pager", pager);
model.addAttribute("filterDTO", filterDTO);
return "your-template";
}
}
and the paginator like this:
<nav style="display: inline-block">
<ul class="pagination">
<li th:class="page-item" th:classappend="${rows.number == 0} ? ''">
<a class="page-link" th:href="#{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=0)}">«</a>
</li>
<li th:class="page-item" th:classappend="${rows.number == 0} ? ''">
<a class="page-link" th:href="#{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${rows.number - 1})}">←</a>
</li>
<li th:class="page-item" th:classappend="${rows.number == (page - 1)} ? 'active pointer-disabled'"
th:each="page : ${#numbers.sequence(pager.startPage, pager.endPage)}">
<a class="page-link" th:href="#{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${page - 1})}" th:if="${page != 0}"
th:text="${page}"></a>
</li>
<li th:class="page-item" th:classappend="${rows.number + 1 == rows.totalPages or pager.endPage == 0} ? ''">
<a class="page-link"
th:href="#{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${rows.number + 1})}">→</a>
</li>
<li th:class="page-item" th:classappend="${rows.number + 1 == rows.totalPages or pager.endPage == 0} ? ''">
<a class="page-link"
th:href="#{${#httpServletRequest.requestURI+'?'+filterDTO.toQueryString()}(page=${rows.totalPages - 1})}">»</a>
</li>
</ul>
</nav>
and in the FilterDTO class I implemented the method: toQueryString() that returns the query string with your applied filters.
Dandelion Datatables is project that can help you not reinvent the wheel.
http://dandelion.github.io/components/datatables/

How to read checkbox/radio value in freemarker?

I'm working with share forms in alfresco and trying to read the values of ticked checkboxes and checked radio buttons form a form. I extended both the user creation and userprofile form with these input controls and so far I have been unsuccessful at reading the textual values of said controls. Below is a snippet of code:
<div class="row">
<span class="label"><input id="${el}-input-spokenEnglish" type="checkbox" name="spokenLanguages" value="${msg("label.anglais"!"")?html}" /> ${msg("label.anglais")}</span>
<span class="label"><input id="${el}-input-spokenSpanish" type="checkbox" name="spokenLanguages" value="${msg("label.espagnol"!"")?html}" /> ${msg("label.espagnol")}</span>
<span class="label"><input id="${el}-input-spokenGerman" type="checkbox" name="spokenLanguages" value="${msg("label.allemand"!"")?html}" /> ${msg("label.allemand")}</span>
<span class="label"><input id="${el}-input-spokenChinese" type="checkbox" name="spokenLanguages" value="${msg("label.chinois"!"")?html}" /> ${msg("label.chinois")}</span>
<br/>
<span class="label">${msg("label.otherLanguages")} : </span>
<span class="input"><input id="${el}-input-spokenLanguages" type="text" size="30" maxlength="256" value="" <#immutablefield field="spokenLanugages" /> /> </span>
</div>
unfortunately I get nothing so far from whatever is returned and would gladly appreciate some insight into this.fre
If you look at userprofile.get.html.ftl, you'll see the following snippet:
<script type="text/javascript">//<![CDATA[
var userProfile = new Alfresco.UserProfile("${args.htmlid}").setOptions(
{
This means it's triggering a client-side JS file from Alfresco, in this case profile.js (see the head file). So just adding some input fields isn't enough.
You need to extend the client-side JS file.
In the function onEditProfile it gets the Dom elements.
But that's just for showing the actual fiels 'after' it's saved.
In profile.js you'll see: form.setSubmitAsJSON(true); that you have a json object from which you can get your fields.
And in userprofile.post.json.ftl it does a loop on the user.properties:
for (var i=0; i<names.length(); i++)
{
var field = names.get(i);
// look and set simple text input values
var index = field.indexOf("-input-");
if (index != -1)
{
user.properties[field.substring(index + 7)] = json.get(field);
}
// apply person description content field
else if (field.indexOf("-text-biography") != -1)
{
user.properties["persondescription"] = json.get(field);
}
}
user.save();
This probably means that you haven't extended the contentmodel of the cm:person object with your new properties.

Resources