Grid with in-line filter

This examples, differs from, the Grid with query windows example only in the filter form being in-line in the web page instead of opening with a query button. Please, refer to that example for more explanations on how to set-up queries.

This example explains just how to put in-line query windows. Basically, instead of using query TagHelpers in a grid toolbar, we add a query-inline TagHelper in the pace where we would like the query form to appear.

Since in this case information can't be inherited from the grid (since it is not an ancestor TagHelper), we must pass the property containing the QueryDescriprion object in the asp-for TagHelper attribute, and the collection where to apply the query to its collection-for attribute. Query window specific toolbars may be placed inside the TagHelper itself, while the RowType definition must be imported by the grid.

Grid may export all its row definitions, by assigning them a name with the rows-cache-key grid attribute. While, the query-inline TagHelper may import them by accepting the same name in its row-collection-name attribute.

Important: All information contained in the external-key-remote tag helper on how to render external keys, starting from version 2.1.0 may be specified also with data annotations, thus simplifying the markup and increasing reusability of the code

name package type unit price discontinued supplier
Chocolade 10 pkgs. 12.75 Zaanse Snoepfabriek
Côte de Blaye 12 - 75 cl bottles 263.50 Aux joyeux ecclésiastiques
Escargots de Bourgogne 24 pieces 13.25 Escargots Nouveaux
Filo Mix 16 - 2 kg boxes 7.00 G'day, Mate
Flotemysost 10 - 500 g pkgs. 21.50 Norske Meierier
@model LiveExamples.Viemodels.FoodListViewModel
    ViewData["Title"] = "Grid with in-line filter";
    if (Model.Query.AttachedTo == null)
<grid asp-for="Products.Data"
      operations="user => Functionalities.ReadOnly | Functionalities.GroupDetail"
      class="table table-condensed table-bordered">
    <column asp-for="Products.Data.Element().SupplierId">
        <external-key-remote display-property="Products.Data
                           "Food"new { search = "_zzz_" }))"
                             max-results="20" />
    <row-type asp-for="Products.Data.SubInfo<FoodViewModelGrouping>().Model"
        <column asp-for="Products.Data
                .SubElement<FoodViewModelGrouping>().SupplierIdCount" />
            <column asp-for="Products.Data
                    .SubElement<FoodViewModelGrouping>().PackageCount" />
    <toolbar zone-name="@LayoutStandardPlaces.Header">
        <pager class="pagination pagination-sm"
               total-pages="Products.TotalPages" />
        <query type="Sorting" />
        <query type="Grouping" />
<query-inline type="Filtering" asp-for="Query"
              row-collection-name="export-for-query" />
@section Scripts {
<link href="~/lib/awesomplete/awesomplete.css" rel="stylesheet" />
<script src="~/lib/mvcct-controls/mvcct.controls.min.js"></script>
<script src="~/lib/mvcct-controls/modules/mvcct.controls.ajax.min.js"></script>
<script src="~/lib/awesomplete/awesomplete.min.js"></script>
<script src="~/lib/mvcct-controls/modules/mvcct.controls.autocomplete.min.js"></script>
<script src="~/lib/mvcct-controls/modules/mvcct.controls.serverGrid.min.js"></script>
<script src="~/lib/mvcct-odata/dest/global/mvcct.odata.min.js"></script>
<script src="~/lib/mvcct-controls/modules/mvcct.controls.query.min.js"></script>
public class FoodViewModel
    public int? Id { getset; }
    [QueryStringLength(64, MinimumLength = 2) Required, 
        Display(Name ="name")]
    public string ProductName { getset; }
    [QueryStringLength(32, MinimumLength = 2), Required,
        Display(Name = "package type")]
    public string Package { getset; }
    [Range(0, 1000), Query,
        Display(Name = "unit price")]
    public decimal UnitPrice { getset; }
    [Display(Name = "discontinued")]
    public bool IsDiscontinued { getset; }
        Display(Name = "supplier")]
    public int SupplierId { getset; }
        Display(Name = "supplier")]
    public string SupplierCompanyName { getset; }
public class FoodViewModelGroupingFoodViewModel
    public int SupplierIdCount { getset; }
    public int PackageCount { getset; }
public class FoodControllerServerCrudController<FoodViewModelFoodViewModelint?>
    public FoodController(FoodRepository repository, 
            IStringLocalizerFactory factory, IHttpContextAccessor accessor, 
            IWebQueryProvider queryProvider) :
        base(factory, accessor)
        Repository = repository;
        this.queryProvider = queryProvider;
    public IWebQueryProvider queryProvider { getprivate set; }
    public async Task<IActionResult> IndexInLine()
        var query = queryProvider.Parse<FoodViewModel>();
        int pg = (int)query.Page;
        var grouping = query.GetGrouping<FoodViewModelGrouping>();
        var model = new FoodListViewModel
            Query = query,
            Products =
                grouping == null ?
                    await Repository.GetPage(
                        query.GetSorting() ??
                            (q => q.OrderBy(m => m.ProductName)),
                        pg, 5)
                    await Repository.GetPageExtended(
                        query.GetSorting<FoodViewModelGrouping>() ??
                            (q => q.OrderBy(m => m.ProductName)),
                        pg, 5,
        return View(model);
    public async Task<ActionResult> GetSuppliers(string search)
        var res = search == null || search.Length < 3 ?
            new List<AutoCompleteItem>() :
            await (Repository as FoodRepository).GetSuppliers(search, 10);
        return Json(res);
tfoot .paginationthead .pagination 
        displayinline !important;
public class FoodRepository : DefaultCRUDRepository<ApplicationDbContextFood>
    private ApplicationDbContext db;
    public  FoodRepository(ApplicationDbContext db):
        base(db, db.Foods)
        this.db = db;
    public async Task<IEnumerable<AutoCompleteItem>> 
        GetSuppliers(string search, int maxpages)
        return (await DefaultCRUDRepository.Create(db, db.Suppliers)
                .GetPage<AutoCompleteItem>(m => m.Display.StartsWith(search),
                m => m.OrderBy(n => n.Display), 1, maxpages))
    static FoodRepository()
            .DeclareProjection(m => new AutoCompleteItem
                Display = m.CompanyName,
                Value = m.Id

Fork me on GitHub