Not even sure this is possible, thought it would be very nice to have though.
I have created a sales page, with a view component of outstanding quote requests.
@{ ViewData["Title"] = "Sales Page"; }<h2>Shenton Application - Sales Team</h2> To start a sale first select Quote Request <h2><a asp-area="" asp-controller="QuoteRequests" asp-action="SalesCreate">Quote Request</a></h2><h4> Quote Requests Not Quoted</h4><div>@await Component.InvokeAsync("QuoteRequests")</div><h4>Quotes To Follow Up</h4>
All fine and dandy.
Then I thought hold on wouldn't it be nice if I can sort the quote requests and maybe there will be more than a few outstanding, I hope not, but should build it in, just in case, and then whilst I am at it lets add search as well. Cant think why, but I guess a contact may call up and we may want to search his request out to update it or something.
The code I added to view component is:
public IViewComponentResult Invoke( string sortOrder, string currentFilter, string searchString, int? page) { ViewData["QRSortParm"] = sortOrder; ViewData["CloseDateSortParm"] = String.IsNullOrEmpty(sortOrder) ? "close_desc" : ""; ViewData["RequestSortParm"] = sortOrder == "Request" ? "request_desc" : "Request"; ViewData["QDSortParm"] = sortOrder == "QD" ? "qd_desc" : "QD"; if (searchString != null) { page = 1; } else { searchString = currentFilter; } ViewData["CurrentFilter"] = searchString; var quoteRequests = from q in _context.QuoteRequest .Where(q=>q.Quoted==false) select q; if (!String.IsNullOrEmpty(searchString)) { quoteRequests = quoteRequests.Where(q => q.Requested.Contains(searchString)); } switch (sortOrder) { case "close_desc": quoteRequests = quoteRequests.OrderByDescending(q => q.CloseDate); break; case "request_desc": quoteRequests = quoteRequests.OrderByDescending(q => q.Requested); break; case "Request": quoteRequests = quoteRequests.OrderBy(q => q.Requested); break; case "qd_desc": quoteRequests = quoteRequests.OrderByDescending(q => q.QDescription); break; case "QD": quoteRequests = quoteRequests.OrderBy(q => q.QDescription); break; default: quoteRequests = quoteRequests.OrderBy(q => q.CloseDate); break; } //return View(quoteRequests); int pageSize = 7; return View(PaginatedList<QuoteRequest>.CreateAsync(page ?? 1, quoteRequests.AsNoTracking(), pageSize)); }
normally I have async PaginatedList, but this didn't like it, so I took the async out.
Then in default view I have:
@model PaginatedList<Eva804.Models.QuoteRequest><form asp-action="Index" method="get"><div class="form-actions no-color"><p> Find by Requested: <input type="text" name="SearchString" value="@ViewData["currentFilter"]" /><input type="submit" value="Search" class="btn btn-default" /><a asp-action="Index">Back to list</a></p></div></form><table class="table"><tr><th><a asp-action="Index" asp-route-sortOrder="@ViewBag.CloseDateSortParm" asp-route-currentFilter="@ViewData["CurrentFilter"]">Closing Date</a></th><th><a asp-action="Index" asp-route-sortOrder="@ViewBag.RequestSortParm" asp-route-currentFilter="@ViewData["CurrentFilter"]">Requested By</a></th><th> Contact Detail</th><th><a asp-action="Index" asp-route-sortOrder="@ViewBag.QDSortParm" asp-route-currentFilter="@ViewData["CurrentFilter"]"> Quote Description</a></th><th></th></tr> @foreach (var q in Model) { <tr><td> @q.CloseDate</td><td> @q.Requested </td><td> @q.ConDetail</td><td> @q.QDescription.Substring(0, Math.Min(q.QDescription.Length, 28))</td><td><a asp-controller="QuoteRequests" asp-action="Details" asp-route-id="@q.QuoteRequestID">Details</a> |<a asp-controller="Quotes" asp-action="Create" asp-route-id="@q.QuoteRequestID">Quote</a></td></tr> } </table> @{ var prevDisabled = !Model.HasPreviousPage ? "disabled" : ""; var nextDisabled = !Model.HasNextPage ? "disabled" : ""; }<a asp-action="Index" asp-route-page="@(Model.PageIndex-1)" class="btn btn-default @prevDisabled btn"> Previous</a><a asp-action="Index" asp-route-page="@(Model.PageIndex+1)" class="btn btn-default @nextDisabled btn"> Next</a>
Nothing wrong in here I can see. Same code I use elsewhere for searching, sorting and paging. All good I thought.
However when I click on the sales index in IE it is creating an error message:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Threading.Tasks.Task`1[Eva804.PaginatedList`1[Eva804.Models.QuoteRequest]]', but this ViewDataDictionary instance requires a model item of type 'Eva804.PaginatedList`1[Eva804.Models.QuoteRequest]'.
Which to me makes no sense.
Why is it telling me about Systems Threading Tasks when neither the ViewComponent or the Default list it as a using item?
Why is it throwing this error at all?
Is this fixable or am I asking too much from the view component?