Добавим в наше приложение фильтрацию и поиск (попытаемся повторить функционал WPFприложения).
Поля ввода на странице обычно заворачиваются в форму (тег <form>) и передаются в контроллер при клике на кнопку с типом submit. Можно сделать и автоматическую отправку формы при изменении данных в полях ввода ("живой" ввод), но такой вариант не рекомендую использовать, так как получается повышенная нагрузка на сервер (ведь каждый раз запрашивается страница целиком).
Итак, добавим на страницу со списком продуктов форму с полями:
<h1 class="display-4">Список продуктов</h1>
<div class="row">
<form method="get">
<input type="text" name="search" value="@Context.Request.Query["search"]"/>
<select name="productType">
@foreach (ProductType pt in @ViewBag.productTypes)
{
<option
value="@pt.ID"
selected="@(pt.ID.ToString() == Context.Request.Query["productType"])"
>
@pt.TitleType
</option>
}
</select>
<button type="submit">Применить</button>
</form>
</div>
...
Должно получиться примерно такое окно:
Что тут происходит?
Добавляем форму и задаем метод GET
<form method="get">
...
</form>
По умолчанию для отправки форм используется метод POST, в таком варианте данные формы передаются в теле запроса. Для формирования представления это не принципиально, но если перезагрузить получившееся окно в браузере, то мы потеряем контекст (введенные ранее данные для фильтрации). Используя метод GET мы передаем данные в queryString и страница открывается с использованием этой строки и сохранением контекста (я подчеркнул эту строку на скриншоте).
Еще в форме можно задать атрибут action, который задает альтернативный URL для отправки формы, по умолчанию форма отправляется на URL текущей страницы.
Добавляем на форму поле ввода для фильтрации по названию
<input
type="text"
name="search"
value="@Context.Request.Query["search"]"/>
name - название переменной (ключа в queryString)value - содержимое поля ввода (при первом запуске оно пустое, но если мы применим фильтрацию, то в содержимое запишется текущее значение фильтра, полученное из queryString)Добавляем выпадающий список с типами продукции
<select name="productType">
@foreach (ProductType pt in @ViewBag.productTypes)
{
<option
value="@pt.ID"
selected="@(pt.ID.ToString() == Context.Request.Query["productType"])"
>
@pt.TitleType
</option>
}
</select>
<select> как раз объявляет выпадающий список, внутри него мы в цикле добавляем <option> - элементы выпадающего спискаselected устанавливаем true для выбранного элементаViewBag.productTypes - типы продукции из БД, заполняем их в контроллере (покажу ниже)Нам нужно добавить в модель список типов продукции (я делаю пустой проект - у вас, если вы делали все лабы, такая модель уже должна быть) и предусмотреть фильтрацию при получении списка продукции.
public interface IDataProvider
{
// В метод получения списка продукции добавил номер страницы для пагинатора
IEnumerable<Product> getProduct(int pageNum = 1);
// Объявляем метод получения списка типов продукции
IEnumerable<ProductType> getProductTypes();
// Объявляем методы для задания фильтрации
void setSearchFilter(string? searchString);
void setProductTypeFilter(string? productTypeFilter);
}
Объявляем приватные переменные для хранения значений фильтров и методы для их инициализации:
private string? searchFilter;
private string? productTypeFilter;
public void setSearchFilter(string? searchString)
{
this.searchFilter = searchString;
}
public void setProductTypeFilter(string? productTypeFilter)
{
this.productTypeFilter = productTypeFilter;
}
Реализуем метод для получения списка типов продукции:
public IEnumerable<ProductType> getProductTypes()
{
using (MySqlConnection db = new MySqlConnection(connectionString))
{
return db.Query<ProductType>("SELECT * FROM ProductType").ToList();
}
}
Переписываем метод получения списка продукции с учетом фильтрации и пагинации:
Для формирования условий используется пакет
Dapper.SqlBuilder
public IEnumerable<Product> getProduct(int pageNum = 1)
{
using (MySqlConnection db = new MySqlConnection(connectionString))
{
var builder = new SqlBuilder();
// если задан фильтр по названию
if (!String.IsNullOrEmpty(this.searchFilter))
// то добавляем условие с LIKE
builder.Where(
"Title LIKE @tt",
// обратите внимание как задается шаблон поиска
new { tt = '%' + this.searchFilter + '%' });
// если задан фильтр по типу продукции
if (!String.IsNullOrEmpty(this.productTypeFilter))
builder.Where(
"ProductTypeID = @id",
new { id = this.productTypeFilter });
// шаблон запроса с пагинацией
// (запрос не полный)
var template = builder.AddTemplate(
"SELECT p.ID, p.Title, p.ProductTypeID, p.ArticleNumber, p.Image, pt.TitleType AS ProductTypeTitle " +
"FROM Product p " +
"JOIN ProductType pt ON p.ProductTypeID=pt.ID " +
"/**where**/ " +
"LIMIT @pageLen OFFSET @offset",
new
{
pageLen = 20,
offset = (pageNum - 1) * 20
}
);
return db.Query<Product>(
template.RawSql,
template.Parameters).ToList();
}
}
На этом знакомство с разработкой веб-приложений на C# мы закончим. Для дальнейшей работы с классическими веб-приложениями нужно копать JavaScript и AJAX-запросы, но мне лень с этим разбираться.
На демо-экзамене вам веб-разработка вообще не понадобится, но если будете учавствовать в чемпионате, то этих основ должно хватить.
Самостоятельно реализовать сортировку
в методе формирования списка продукции в builder добавить сортировку
Пример был в лекции про пагинацию в WPF
builder.OrderBy(orderCondition);