0% found this document useful (0 votes)
41 views71 pages

Chapter 15 Slides

Uploaded by

aisha.adediran0
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
41 views71 pages

Chapter 15 Slides

Uploaded by

aisha.adediran0
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 71

Chapter 15

How to work
with tag helpers,
partial views,
and view components

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 1
Objectives (part 1)
Applied
1. Reduce code duplication in the views of a web app by creating
custom tag helpers, partial views, and view components.

Knowledge
2. Distinguish between tag helper attributes and elements.
3. Explain how to register tag helpers.
4. Explain how to create custom tag helpers for standard and non-
standard HTML elements.
5. Describe the use of the HtmlTarget attribute to control the scope of
a tag helper.
6. Describe the use of the TagHelperOutput class and the TagBuilder
class to add an HTML element before or after the tag helper
element.

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 2
Objectives (part 2)
6. Describe the use of properties within a tag helper class.
7. Describe the use of dependency injection with a tag helper.
8. Describe the use of the SuppressOutput() method of the
TagHelperOutput class to create tag helpers that send an element
to the browser only under certain conditions.
9. Describe the use of the GetPathByAction() method of the
LinkGenerator class to generate a route-based URL.
10. Describe what a partial view typically contains.
11. List and describe the paths that MVC searches for a partial view.
12. Describe how to use the partial tag helper to include a partial
view and pass a model to it.
13. Distinguish between a partial view and a view component.
14. Describe how a view component works and how data can be
passed to it.

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 3
Common built-in tag helpers
asp-action
asp-controller
asp-area
asp-for
asp-validation-summary
asp-validation-for
environment
partial

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 4
A tag helper that generates attributes
for an <input> tag
<input asp-for="FirstName" class="form-control" />

The HTML that’s sent to the browser


<input class="form-control" type="text" data-val="true"
data-val-maxlength="The field FirstName must be a string
or array type with a maximum length of &#x27;200&#x27;."
data-val-maxlength-max="200" data-val-required="Please
enter a first name." id="FirstName" maxlength="200"
name="FirstName" value="" />

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 5
A tag helper that generates a route-based URL
in a <form> tag
<form asp-action="Edit" method="post"></form>

The HTML that’s sent to the browser


<form action="/Home/Edit" method="post"></form>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 6
Tag helpers that output a different CSS link
based on hosting environment
<environment include="Development">
<link rel="stylesheet"
href="~/lib/bootstrap/css/bootstrap.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet"
href="~/lib/bootstrap/css/bootstrap.min.css" />
</environment>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 7
A _ViewImports.cshtml file that registers
all built-in and custom tag helpers
...
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Bookstore

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 8
Razor code that uses HTML helpers (old way)
@{ Html.BeginForm("Edit", "Home", FormMethod.Post,
new { @class = "form-inline" }); }
@Html.LabelFor(m => m.Title)
@Html.TextBoxFor(m => m.Title,
new { @class = "form-control m-2" })
@Html.LabelFor(m => m.Price)
@Html.TextBoxFor(m => m.Price,
new { @class = "form-control m-2",
placeholder = "e.g., $14.99" })
@{ Html.EndForm(); }

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 9
HTML that uses tag helpers (new way)
<form asp-action="Edit" method="post"
class="form-inline">
<label asp-for="Title">Title</label>
<input asp-for="Title" class="form-control m-2" />
<label asp-for="Price">Price</label>
<input asp-for="Price" class="form-control m-2"
placeholder="e.g., $14.99" />
</form>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 10
The HTML that both examples send
to the browser
<form action="/Home/Edit" method="post"
class="form-inline">
<label for="Title">Title</label>
<input type="text" id="Title" name="Title" value=""
class="form-control m-2" />
<label for="Price">Price</label>
<input type="text" id="Price" name="Price" value=""
class="form-control m-2"
placeholder="e.g., $14.99" />
</form>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 11
The using directive for the TagHelpers namespace
using Microsoft.AspNetCore.Razor.TagHelpers;

One virtual method of the TagHelper class


Process(ctx, out)

One property of the TagHelperOutput class


Attributes

One method of the TagHelperAttributeList class


SetAttribute(name, val)

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 12
A tag helper that applies to any standard
HTML <button> element
public class ButtonTagHelper : TagHelper
{
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
output.Attributes.SetAttribute(
"class", "btn btn-primary");
}
}

Two button elements in a view


<button type="submit">Submit</button>
<button type="reset">Reset Form</button>

The HTML that MVC sends to the browser


<button type="submit" class="btn btn-primary">Submit</button>
<button type="reset" class="btn btn-primary">Reset Form</button>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 13
More properties of the TagHelperOutput class
TagName
TagMode

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 14
A tag helper that applies to any non-standard
<submit-button> element
public class SubmitButtonTagHelper : TagHelper
{
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
// make it a button element with start and end tags
output.TagName = "button";
output.TagMode = TagMode.StartTagAndEndTag;

// make it a submit button


output.Attributes.SetAttribute("type", "submit");

// append bootstrap button classes


string newClasses = "btn btn-primary";
string oldClasses =
output.Attributes["class"]?.Value?.ToString();
string classes = (string.IsNullOrEmpty(oldClasses)) ?
newClasses : $"{oldClasses} {newClasses}";
output.Attributes.SetAttribute("class", classes);
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 15
A submit-button element in a view
<submit-button class="mr-2">Submit</submit-button>

The HTML that MVC sends to the browser


<button type="submit" class="mr-2 btn btn-primary">
Submit</button>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 16
Three extension methods for tag helpers (part 1)
using Microsoft.AspNetCore.Razor.TagHelpers;
...
public static class TagHelperExtensions
{
public static void AppendCssClass(
this TagHelperAttributeList list, string newCssClasses)
{
string oldCssClasses = list["class"]?.Value?.ToString();
string cssClasses = (string.IsNullOrEmpty(oldCssClasses)) ?
newCssClasses : $"{oldCssClasses} {newCssClasses}";
list.SetAttribute("class", cssClasses);
}

public static void BuildTag(this TagHelperOutput output,


string tagName, string classNames)
{
output.TagName = tagName;
output.TagMode = TagMode.StartTagAndEndTag;
output.Attributes.AppendCssClass(classNames);
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 17
Three extension methods for tag helpers (part 2)
public static void BuildLink(this TagHelperOutput output,
string url, string className)
{
output.BuildTag("a", className);
output.Attributes.SetAttribute("href", url);
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 18
Two tag helpers that use the extension methods
public class ButtonTagHelper : TagHelper
{
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
output.Attributes.AppendCssClass("btn btn-primary");
}
}

public class SubmitButtonTagHelper : TagHelper


{
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
output.BuildTag("button", "btn btn-primary");
output.Attributes.SetAttribute("type", "submit");
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 19
Two properties of the HtmlTargetElement attribute
Attributes
ParentTag

Use the HTMLTargetElement attribute to…


 Allow a tag helper class to have a different name than the HTML
element it targets.
 Narrow the scope of a tag helper so it only targets an element
under certain conditions.
 Widen the scope of a tag helper so it targets multiple elements.

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 20
A tag helper for any <label> element
public class LabelTagHelper : TagHelper {...}

Another tag helper for any <label> element


[HtmlTargetElement("label")]
public class MyLabelTagHelper : TagHelper {...}

A tag helper for bound <label> elements in a form


[HtmlTargetElement("label", Attributes = "asp-for",
ParentTag = "form")]
public class FormLabelTagHelper : TagHelper {...}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 21
A tag helper for <input> or <select> elements
in a form
[HtmlTargetElement("input", ParentTag = "form")]
[HtmlTargetElement("select", ParentTag = "form")]
public class FormTagHelper : TagHelper {...}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 22
A tag helper for any element of the submit type
or any <a> element with a my-button attribute
[HtmlTargetElement(Attributes = "[type=submit]")]
[HtmlTargetElement("a", Attributes = "my-button")]
public class MyButtonTagHelper : TagHelper {...}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 23
Three properties of the TagHelperOutput class
PreElement
Content
PostElement

Two properties of the TagBuilder class


Attributes
InnerHtml

The using directive for the Rendering namespace


using Microsoft.AspNetCore.Mvc.Rendering;
// for TagBuilder

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 24
A tag helper that adds a <span> element
after the targeted element
[HtmlTargetElement("input", Attributes = "my-required")]
public class RequiredInputTagHelper : TagHelper
{
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
// add CSS class to input element
output.Attributes.AppendCssClass("form-control");

// create a <span> element


TagBuilder span = new TagBuilder("span");
span.Attributes.Add("class","text-danger mr-2");
span.InnerHtml.Append("*");

// add span element after input element


output.PostElement.AppendHtml(span);
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 25
An <input> element that uses the tag helper
<input asp-for="Title" my-required />

The HTML that’s sent to the browser


<input my-required type="text" id="Title" name="Title"
value="" class="form-control" />
<span class="text-danger mr-2">*</span>

The elements displayed in a browser

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 26
A tag helper that generates numeric options
for a <select> element
[HtmlTargetElement("select",
Attributes = "my-min-number, my-max-number")]
public class NumberDropDownTagHelper : TagHelper
{
[HtmlAttributeName("my-min-number")]
public int Min { get; set; }

[HtmlAttributeName("my-max-number")]
public int Max { get; set; }

public override void Process(TagHelperContext context,


TagHelperOutput output)
{
for (int i = Min; i <= Max; i++)
{
TagBuilder option = new TagBuilder("option");
option.InnerHtml.Append(i.ToString());
output.Content.AppendHtml(option);
}
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 27
A view that uses the NumberDropDown tag helper
@model CartItem
...
<select asp-for="Quantity" class="form-control"
my-min-number="1" my-max-number="10"></select>

The HTML that’s sent to the browser


<select class="form-control" id="Quantity"
name="Quantity">
<option>1</option>
<option>2</option>
...
<option>10</option>
</select>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 28
The <select> element displayed in a browser

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 29
One property of the TagHelperContext class
AllAttributes

Three properties of the ModelExpression class


Name
Model
Metadata

The using statement for the ViewFeatures


namespace
using Microsoft.AspNetCore.Mvc.ViewFeatures;
// for ModelExpression

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 30
The updated NumberDropDownTagHelper class
[HtmlTargetElement("select", Attributes = "my-min-number, my-max-number")]
public class NumberDropDownTagHelper : TagHelper
{
// Min and Max properties same as before

public override void Process(TagHelperContext context,


TagHelperOutput output)
{
// get selected value from view's model
ModelExpression aspfor =
(ModelExpression) context.AllAttributes["asp-for"].Value;
int modelValue = (int)aspfor?.Model;

for (int i = Min; i <= Max; i++)


{
TagBuilder option = new TagBuilder("option");
option.InnerHtml.Append(i.ToString());

// mark option as selected if matches model's value


if (modelValue == i)
option.Attributes["selected"] = "selected";

output.Content.AppendHtml(option);
}
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 31
A tag helper that gets a ViewContext value
via dependency injection (part 1)
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.Rendering;
...
[HtmlTargetElement("a", Attributes = "[class=nav-link]",
ParentTag = "li")]
public class ActiveNavbarTagHelper : TagHelper
{
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewCtx { get; set; }

public override void Process(TagHelperContext context,


TagHelperOutput output)
{
string area =
ViewCtx.RouteData.Values["area"]?.ToString() ?? "";
string ctlr =
ViewCtx.RouteData.Values["controller"].ToString();

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 32
A tag helper that gets a ViewContext value
via dependency injection (part 2)
string aspArea = context.AllAttributes["asp-area"]?.Value?
.ToString() ?? "";
string aspCtlr =
context.AllAttributes["asp-controller"].Value
.ToString();

if (area == aspArea && ctlr == aspCtlr)


output.Attributes.AppendCssClass("active");
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 33
A tag helper that gets a Cart object
via dependency injection
[HtmlTargetElement("span", Attributes = "my-cart-badge")]
public class CartBadgeTagHelper : TagHelper
{
private ICart cart;
public CartBadgeTagHelper(ICart c) => cart = c;

public bool MyCartBadge { get; set; }

public override void Process(TagHelperContext context,


TagHelperOutput output)
{
output.Content.SetContent(cart.Count?.ToString());
}
}

The tag helper in a layout


<span class="fas fa-shopping-cart"></span>&nbsp;Cart
<span class="badge badge-light" my-cart-badge></span>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 34
A layout that only displays an element
if there’s a value in TempData
<main>
@if (TempData.Keys.Contains("message"))
{
<h4 class="bg-info text-center text-white p-2">
@TempData["message"]
</h4>
}
@RenderBody()
</main>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 35
A method of the TagHelperOutput class
SuppressOutput()

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 36
A tag helper that only outputs HTML
if there’s a value in TempData
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.Rendering;
...
[HtmlTargetElement("my-temp-message")]
public class TempMessageTagHelper : TagHelper
{
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewCtx { get; set; }

public override void Process(TagHelperContext context,


TagHelperOutput output)
{
var td = ViewCtx.TempData;
if (td.Keys.Contains("message"))
{
output.BuildTag("h4", "bg-info text-center text-white p-2");
output.Content.SetContent(td["message"].ToString());
}
else
{
output.SuppressOutput();
}
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 37
A layout that uses the conditional tag helper
<main>
<my-temp-message />
@RenderBody()
</main>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 38
A tag helper that generates a paging link (part 1)
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Routing;
using Bookstore.Models;
...
[HtmlTargetElement("my-paging-link")]
public class PagingLinkTagHelper : TagHelper
{
private LinkGenerator linkBuilder;
public PagingLinkTagHelper(LinkGenerator lg) => linkBuilder = lg;

[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewCtx { get; set; }

public int Number { get; set; }


public RouteDictionary Current { get; set; }

public override void Process(TagHelperContext context,


TagHelperOutput output) {
// update routes for this paging link
var routes = Current.Clone();
routes.PageNumber = Number;

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 39
A tag helper that generates a paging link (part 2)
// get controller and action method, create paging link URL
string ctlr =
ViewCtx.RouteData.Values["controller"].ToString();
string action =
ViewCtx.RouteData.Values["action"].ToString();
string url =
linkBuilder.GetPathByAction(action, ctlr, routes);

// build up CSS string


string linkClasses = "btn btn-outline-primary";
if (Number == Current.PageNumber)
linkClasses += " active";

// create link
output.BuildLink(url, linkClasses);
output.Content.SetContent(Number.ToString());
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 40
A view that uses the PagingLink tag helper
@{
for (int i = 1; i <= Model.TotalPages; i++)
{
<my-paging-link number="@i"
current="@Model.CurrentRoute" />
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 41
The Add MVC View dialog

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 42
The paths that MVC searches for a partial view
/Views/ControllerName/PartialViewName
/Views/Shared/PartialViewName

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 43
A partial view that loads the jQuery validation
libraries
<script
src="~/lib/jquery-validation/dist/jquery.validate.min.js">
</script>
<script
src="~/lib/jquery-validation-unobtrusive/
jquery.validate.unobtrusive.min.js">
</script>

A tag helper that includes the partial view


in a view
<partial name="_ValidationScriptsPartial" />

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 44
A partial view that contains the HTML
for a Bootstrap navbar menu button
<button class="navbar-toggler" type="button"
data-toggle="collapse"
data-target="#menu" aria-controls="menu"
aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>

A layout that uses the partial view


in a Bootstrap navbar
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<partial name="_NavbarMenuButtonPartial" />
<div class="collapse navbar-collapse" id="menu">
<ul class="navbar-nav mr-auto">...</ul>
</div>
</nav>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 45
Four attributes of the partial tag helper
name
model
for
viewData

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 46
The _BookLinkPartial partial view
@model Book

<a asp-action="Details" asp-controller="Book"


asp-route-id="@Model.BookId"
asp-route-slug="@Model.Title.Slug()">
@Model.Title
</a>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 47
The partial view in a view with the same
model object (Home/Index)
@model Book
...
<h5>
<partial name="_BookLinkPartial" />
</h5>
...

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 48
The partial view in a view with a different
model object (Book/List)
@model BookListViewModel
...
@foreach (Book book in Model.Items) {
<tr>
<td>
<partial name="_BookLinkPartial" model="@book" />
</td>
...

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 49
A method in a ViewComponent class
Invoke([params])

The folder for the view component classes


/Components

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 50
A view component that passes the Cart count
to a partial view
using Microsoft.AspNetCore.Mvc;
...
public class CartBadge : ViewComponent
{
private ICart cart { get; set; }
public CartBadge(ICart c) => cart = c;

public IViewComponentResult Invoke() =>


View(cart.Count);
}

The Default.cshtml partial view


@model int?
<span class="badge badge-light">@Model</span>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 51
The paths that MVC searches
for a view component’s partial view
/Views/ControllerName/Components/ViewComponentName/ViewName
/Views/Shared/Components/ViewComponentName/ViewName

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 52
A layout that uses tag helper syntax
to call the view component
<span class="fas fa-shopping-cart"></span>&nbsp;Cart
<vc:cart-badge></vc:cart-badge>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 53
The DropDownViewModel class
public class DropDownViewModel
{
public Dictionary<string, string> Items { get; set; }
public string SelectedValue { get; set; }
public string DefaultValue { get; set; }
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 54
A view component with an Invoke() method
that has a parameter
public class AuthorDropDown : ViewComponent
{
private IRepository<Author> data { get; set; }
public AuthorDropDown(IRepository<Author> rep) => data = rep;

public IViewComponentResult Invoke(string selectedValue)


{
var authors = data.List(new QueryOptions<Author> {
OrderBy = a => a.FirstName
});

var vm = new DropDownViewModel {


SelectedValue = selectedValue,
DefaultValue = "All",
Items = authors.ToDictionary(
a => a.AuthorId.ToString(), a => a.FullName)
};
return View(
"~/Views/Shared/Components/Common/DropDown.cshtml", vm);
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 55
The DropDown partial view
@model DropDownViewModel

<select name="filter" class="form-control m-2"


asp-items="@(new SelectList(
Model.Items, "Key", "Value", Model.SelectedValue))">
<option value="@Model.DefaultValue">All</option>
</select>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 56
A view that uses the view component
<label>Author: </label>
<vc:author-drop-down
selected-value="@Model.CurrentRoute.AuthorFilter">
</vc:author-drop-down>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 57
The generic GridViewModel class
public class GridViewModel<T>
{
public IEnumerable<T> Items { get; set; }
public RouteDictionary CurrentRoute { get; set; }
public int TotalPages { get; set; }
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 58
The List() action method of the Book controller
public ViewResult List(BooksGridDTO values)
{
/* code that creates GridBuilder and QueryOptions objects to
retrieve a list of paged, sorted, and filtered books */

var vm = new GridViewModel<Book> {


Items = data.List(options),
CurrentRoute = builder.CurrentRoute,
TotalPages = builder.GetTotalPages(data.Count)
};

return View(vm);
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 59
The List() action method of the Author controller
public ViewResult List(GridDTO vals)
{
/* code that creates GridBuilder and QueryOptions objects to
retrieve a list of paged and sorted authors */

var vm = new GridViewModel<Author> {


Items = data.List(options),
CurrentRoute = builder.CurrentRoute,
TotalPages = builder.GetTotalPages(data.Count)
};

return View(vm);
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 60
The Book Catalog page

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 61
The custom tag helpers, partial views,
and view components in this page
1. The ActiveNavbar tag helper.
2. The CartBadge view component.
3. The TempMessage tag helper.
4. The AuthorDropDown view component. The other drop-down
lists are view components that work similarly.
5. The SortingLink tag helper.
6. The _BookLink partial view.
7. The _AuthorLink partial view.
8. The Button tag helper.
9. The paging-links partial view, containing the paging-link tag
helper.

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 62
The updated ActiveNavbar tag helper
that accounts for the Admin area (part 1)
[HtmlTargetElement("a", Attributes = "[class=nav-link]",
ParentTag = "li")]
public class ActiveNavbarTagHelper : TagHelper
{
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewCtx { get; set; }

[HtmlAttributeName("my-mark-area-active")]
public bool IsAreaOnly { get; set; }

public override void Process(TagHelperContext context,


TagHelperOutput output)
{
string area = ViewCtx.RouteData.Values["area"]?
.ToString() ?? "";
string ctlr = ViewCtx.RouteData.Values["controller"]
.ToString();

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 63
The updated ActiveNavbar tag helper (part 2)
string aspArea = context.AllAttributes["asp-area"]?.Value?
.ToString() ?? "";
string aspCtlr = context.AllAttributes["asp-controller"]
.Value.ToString();

if (area == aspArea && ctlr == aspCtlr)


output.Attributes.AppendCssClass("active");
else if (IsAreaOnly && area == aspArea)
output.Attributes.AppendCssClass("active");
}
}

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 64
The two active navbar links
on the Manage Authors page of the Admin area

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 65
The layout of the Bookstore app (part 1)
<!DOCTYPE html>
<html lang="en">
<head>...</head>
<body>
<div class="container">
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<partial name="_NavbarMenuButtonPartial" />
<div class="collapse navbar-collapse" id="menu">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" asp-action="Index"
asp-controller="Home" asp-area="">
<span class="fas fa-home"></span>
&nbsp;Home
</a>
</li>
@* nav item links for Books and Authors *@
</ul>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 66
The layout of the Bookstore app (part 2)
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" asp-action="Index"
asp-controller="Cart" asp-area="">
<span class="fas fa-shopping-cart">
</span>&nbsp;Cart
<vc:cart-badge></vc:cart-badge>
</a>
</li>
@* nav item link for Registration goes here *@
<li class="nav-item">
<a class="nav-link" asp-action="Index"
asp-controller="Book" asp-area="Admin"
my-mark-area-active>
<span class="fas fa-cog"></span>
&nbsp;Admin
</a>
</li>
</ul>
</div>
</nav>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 67
The layout of the Bookstore app (part 3)
<header class="jumbotron text-center">
<a asp-action="Index" asp-controller="Home">
<img src="~/images/logo.png"
class="img-fluid center-block" />
</a>
</header>

<main>
<my-temp-message />
@RenderBody()
</main>
</div>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js">
</script>
<script src="~/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
</body>
</html>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 68
The Book/List view (part 1)
@model GridViewModel<Book>
...
<form asp-action="Filter" method="post" class="form-inline">
<label>Author: </label>
<vc:author-drop-down
selected-value="@Model.CurrentRoute.AuthorFilter">
</vc:author-drop-down>

<label>Genre: </label>
<vc:genre-drop-down
selected-value="@Model.CurrentRoute.GenreFilter">
</vc:genre-drop-down>

<label>Price: </label>
<vc:price-drop-down
selected-value="@Model.CurrentRoute.PriceFilter">
</vc:price-drop-down>

<button type="submit" class="mr-2">Filter</button>


<button type="submit" name="clear" value="true">Clear</button>
</form>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 69
The Book/List view (part 2)
<form asp-action="Add" asp-controller="Cart" method="post">
<table class="table table-bordered table-striped table-sm">
<thead class="thead-dark">
<tr>
<th>
<my-sorting-link sort-field="Title"
current="@Model.CurrentRoute">Title
</my-sorting-link></th>
<th>Author(s)</th>
<th>
<my-sorting-link sort-field="Genre"
current="@Model.CurrentRoute">Genre
</my-sorting-link></th>
<th>
<my-sorting-link sort-field="Price"
current="@Model.CurrentRoute">Price
</my-sorting-link></th>
<th></th>
</tr>
</thead>

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 70
The Book/List view (part 3)
<tbody>
@foreach (Book book in Model.Items) {
<tr>
<td><partial name="_BookLinkPartial" model="@book" />
</td>
<td>
@foreach (var ba in book.BookAuthors) {
<p><partial name="_AuthorLinkPartial"
model="@ba.Author" /></p>
}
</td>
<td>@book.Genre?.Name</td>
<td>@book.Price.ToString("c")</td>
<td><button type="submit" name="id"
value="@book.BookId">Add To Cart
</button>
</td>
</tr>
}
</tbody>
</table>
</form>
<partial name="_PagingLinksPartial" />

© 2020, Mike Murach & Associates, Inc.


Murach's ASP.NET Core MVC C15, Slide 71

You might also like