剃刀页面和引导 - 模态主详细信息

这是一系列帖子中的第一个探索如何使用一些 在数据库驱动的剃刀页面Web中由Bootstrap提供的组件 应用。在本文中,我看看使用Bootstrap模态 主/详细信息方案,显示所选记录的详细信息 master list.

在本系列中,我将使用Northwind示例数据库提供熟悉的 数据访问的数据和实体框架核心。引导标签包含在内 使用标准构建的所有剃刀页面应用程序的默认UI框架 ASP.NET核心Web应用程序项目模板:

项目模板

本文的示例申请将会 显示产品列表,单击一个按钮将调用模态 显示该产品的详细信息:

硕士/细节

初始产品列表的HTML在服务器上生成。什么时候 使用单击“详细信息”按钮,进行AJAX调用以获取产品 细节。 Ajax调用可以返回HTML或JSON。本文涵盖了两者 options.

与数据库的通信分为服务类, ProductService,包含以下代码:

public class ProductService : IProductService
{
    private readonly NorthwindContext context;
    public ProductService(NorthwindContext context) => this.context = context;
 
    public async Task<Dictionary<intstring>> GetProductListAsync() => await context.Products.ToDictionaryAsync(k => k.ProductId, v => v.ProductName);
    public async Task<Product> GetProductAsync(int id) => await context.Products.Include(p => p.Category).Include(p => p.Supplier).FirstOrDefaultAsync(p => p.ProductId == id);
}

它包含两种方法,一个方法将产品ID和名称作为字典返回,返回特定产品的详细信息。该服务已注册 Startup以及我的例子中的上下文使用了orightwind的sqlite版本:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();
    services.AddDbContext<NorthwindContext>(options =>
    {
        options.UseSqlite($"Data Source={Environment.ContentRootPath}/Data/Northwind.db");
    });
    services.AddScoped<IProductServiceProductService>();
}

现在我可以将服务注入PageModel类构造函数以利用 it to populate the ProductList dictionary:

public class MasterDetailsModel : PageModel
{
    private readonly IProductService productService;
    public MasterDetailsModel(IProductService productService) => this.productService = productService;
 
    public Dictionary<intstring> ProductList { getset; } = new Dictionary<intstring>();
    public async Task OnGetAsync()
    {
        ProductList = await productService.GetProductListAsync();
    }
}

字典显示在表中:

<table class="table table-sm table-borderless" style="max-width:50%">
    @foreach (var item in Model.ProductList)
    {
        <tr>
            <td>@item.Value</td>
            <td><button class="btn btn-sm btn-dark details" data-id="@item.Key">Details</button></td>
        </tr>
    }
</table>

到目前为止很好 - 您可以看到该表使用标准引导造型 类,并且每个产品都伴随着Bootstrap样式按钮 has a data attribute set to the value if the product's ID. At the moment, nothing happens if you click the button. This first pass 将展示添加模态并用HTML片段填充它。这 所需的步骤是:

  1. 添加Bootstrap模态
  2. 创建一种生成HTML以显示产品的详细信息的方法
  3. 添加AJAX调用以获取HTML并将其传递给模态
  4. 将模态线连接到按钮

这是模态的HTML。它被添加到包含LSIT的页面 of products:

<div class="modal fade" tabindex="-1" role="dialog" id="details-modal">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Product Details</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body"></div>
        </div>
    </div>
</div>

这是一个或多或少地直接复制的标准模态 引导模态Docs.. It's been given an id attribute so that it can be referenced elsewhere, and it has the fade CSS class applied so that its appearance is animated. The div element with the CSS class of modal-body is empty. This 将通过通过ajax调用获得的HTML填充 命名页面处理程序方法。 HTML将由A生成 剃刀 partial page (_ProductDetails.chtml. ):

@model Product
 
<div>
    <span class="d-inline-block">Product:</span><span>@Model.ProductName</span>
</div>
<div>
    <span class="d-inline-block">Category:</span><span>@Model.Category.CategoryName</span>
</div>
<div>
    <span class="d-inline-block">Quantity Per Unit :</span><span>@Model.QuantityPerUnit</span>
</div>
<div>
    <span class="d-inline-block">Unit Price:</span><span>@Model.UnitPrice</span>
</div>
<div>
    <span class="d-inline-block">Units In Stock:</span><span>@Model.UnitsInStock</span>
</div>
<div>
    <span class="d-inline-block">Units On Order:</span><span>@Model.UnitsOnOrder</span>
</div>
<div>
    <span class="d-inline-block">Discontinued</span><span><input type="checkbox" readonly checked="@Model.Discontinued" /></span>
</div>
<div>
    <span class="d-inline-block">Date Discontinued</span><span>@Model.DiscontinuedDate?.ToShortDateString()</span>
</div>
<div>
    <span class="d-inline-block">Supplier</span><span>@Model.Supplier.CompanyName</span>
</div>

The model for the partial is a Product entity whose details are rendered 在一系列跨度元素中。下一步是添加一个处理程序方法 使用部分并返回HTML:

public async Task<PartialViewResult> OnGetProductAsync(int id)
{
    return Partial("_ProductDetails"await productService.GetProductAsync(id));
}

Then a route template is added to the page directive so that the 处理程序方法名称可以作为段而不是段融合到URL中 query string value:

@page "{handler?}"

下一步是创建一些JavaScript来调用页面模型处理程序方法, 通过所选产品的ID。这是从中获得的 data-id 按钮上的属性:

@section scripts{
    <script>
        $(function () {
            $('button.details').on('click'function () {
                $('.modal-body').load(`/masterdetails/product?id=${$(this).data('id')}`);
            });
        })
    </script>
}

The script makes use of the jQuery load method, which performs a GET 请求并将响应放入匹配元素 the load method is called on, in this case modal-body. 最后,添加到表中的按钮需要修改以触发 modal's visibility by adding data-toggle and data-target attributes, the second of which references the id of the modal:

<button class="btn btn-sm btn-dark details" data-id="@item.Key" data-toggle="modal" data-target="#details-modal">Details</button> 

单击按钮时,对其进行异步呼叫 OnGetProductAsync handler

剃刀页面引导

和调用模态,使用HTML响应加载到身体:

剃刀页面引导

如果您必须与JSON一起使用,则在浏览器中进行数据绑定 而不是在服务器上,所以不需要部分。相反,处理程序方法返回序列化为JSON的数据:

public async Task<JsonResult> OnGetProductAsJsonAsync(int id)
{
    return new JsonResult(await productService.GetProductAsync(id));
}

模态机构设置,以非常相似的HTML到部分

<div class="modal fade" tabindex="-1" role="dialog" id="details-modal">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Product Details (JSON)</h5>
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <div>
                    <span class="d-inline-block">Product:</span><span id="product"></span>
                </div>
                <div>
                    <span class="d-inline-block">Category:</span><span id="category"></span>
                </div>
                <div>
                    <span class="d-inline-block">Quantity Per Unit :</span><span id="quantity"></span>
                </div>
                <div>
                    <span class="d-inline-block">Unit Price:</span><span id="price"></span>
                </div>
                <div>
                    <span class="d-inline-block">Units In Stock:</span><span id="instock"></span>
                </div>
                <div>
                    <span class="d-inline-block">Units On Order:</span><span id="onorder"></span>
                </div>
                <div>
                    <span class="d-inline-block">Discontinued</span><span><input type="checkbox" readonly id="discontinued" /></span>
                </div>
                <div>
                    <span class="d-inline-block">Date Discontinued</span><span id="discontinued-date"></span>
                </div>
                <div>
                    <span class="d-inline-block">Supplier</span><span id="supplier"></span>
                </div>
            </div>
        </div>
    </div>
</div>

The spans that will hold the data values have an id attribute to 在脚本中引用更容易,谈谈哪些脚本是修订的脚本 用于调用新的处理程序方法,并处理响应:

$('button.details').on('click'function () {
    $.getJSON(`/masterdetails/productasjson?id=${$(this).data('id')}`).done(function (product) {
        $('#product').text(product.productName);
        $('#category').text(product.category.categoryName);
        $('#quantity').text(product.quantityPerUnit);   
        $('#price').text(product.unitPrice);
        $('#instock').text(product.unitsInStock);
        $('#onorder').text(product.unitsOnOrder);
        $('#discontinued').text(product.discontinued);
        $('#discontinued-date').text(product.discontinuedDate);
        $('#supplier').text(product.supplier.companyName);
    });
});

This time, the jQuery getJSON method is used, and the individual 数据值已插入DOM。最终结果是相同的。

概括

本文看起来有几种管理硕士/细节方案的方法 使用Bootstrap模块和剃刀页面。第一次使用部分证明 生成要插入模态的HTML,第二个看 返回JSON,并使用jQuery绑定客户端中的数据。使用 HTML更容易,特别是在局部视图中具有IntelliSense支持。 如果您使用JSON工作,jQuery对简单的场景很好,但您也可以 想考虑更正式的模板解决方案,如 Knockout 或者 vuejs. 用于数据库 client.