Skip to content
This repository was archived by the owner on Dec 14, 2018. It is now read-only.

Add ValidationSummaryTagHelper. #1340

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions samples/TagHelperSample.Web/Views/Home/Create.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
<div class="form-horizontal">
@* validation summary tag helper will target just <div/> elements and append the list of errors *@
@* - i.e. this helper, like <select/> helper has ContentBehavior.Append *@
@* validation-model-errors-only="true" implies validation-summary="true" *@
@* helper does nothing if model is valid and (client-side validation is disabled or validation-model-errors-only="true") *@
@* helper does nothing if model is valid and (client-side validation is disabled or validation-summary="ModelOnly") *@
@* don't need a bound attribute to match Html.ValidationSummary()'s headerTag parameter; users wrap message as they wish *@
@* initially at least, will not remove the <div/> if list isn't generated *@
@* - should helper remove the <div/> if list isn't generated? *@
@* - (Html.ValidationSummary returns empty string despite non-empty message parameter) *@
<div validation-summary="true" validation-model-errors-only="true">
@* Acceptable values are: "None", "ModelOnly" and "All" *@
<div validation-summary="ModelOnly">
<span style="color:red">This is my message</span>
</div>

Expand Down
2 changes: 1 addition & 1 deletion samples/TagHelperSample.Web/Views/Home/Edit.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<form>
<div class="form-horizontal">
<div validation-summary="true"/>
<div validation-summary="All"/>
<input type="hidden" for="Id" />

<div class="form-group">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Microsoft.AspNet.Mvc.TagHelpers.Test")]

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/Microsoft.AspNet.Mvc.TagHelpers/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,7 @@
<data name="FormTagHelper_CannotDetermineAction" xml:space="preserve">
<value>Cannot determine an {1} for {0}. A {0} with a URL-based {1} must not have attributes starting with {3} or a {2} attribute.</value>
</data>
<data name="ValidationSummaryTagHelper_InvalidValidationSummaryValue" xml:space="preserve">
<value>Cannot parse '{1}' value '{2}' for {0}. Acceptable values are '{3}', '{4}' and '{5}'.</value>
</data>
</root>
26 changes: 26 additions & 0 deletions src/Microsoft.AspNet.Mvc.TagHelpers/ValidationSummary.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.AspNet.Mvc.TagHelpers
{
/// <summary>
/// Acceptable validation summary rendering modes.
/// </summary>
public enum ValidationSummary
{
/// <summary>
/// No validation summary.
/// </summary>
None,

/// <summary>
/// Validation summary with model-level errors only (excludes all property errors).
/// </summary>
ModelOnly,

/// <summary>
/// Validation summary with all errors.
/// </summary>
All
}
}
74 changes: 74 additions & 0 deletions src/Microsoft.AspNet.Mvc.TagHelpers/ValidationSummaryTagHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;

namespace Microsoft.AspNet.Mvc.TagHelpers
{
/// <summary>
/// <see cref="ITagHelper"/> implementation targeting &lt;div&gt; elements with a <c>validation-summary</c>
/// attribute.
/// </summary>
[TagName("div")]
[ContentBehavior(ContentBehavior.Append)]
public class ValidationSummaryTagHelper : TagHelper
{
// Protected to ensure subclasses are correctly activated. Internal for ease of use when testing.
[Activate]
protected internal ViewContext ViewContext { get; set; }

// Protected to ensure subclasses are correctly activated. Internal for ease of use when testing.
[Activate]
protected internal IHtmlGenerator Generator { get; set; }

// TODO: Change to ValidationSummary enum once https://github.com/aspnet/Razor/issues/196 has been completed.
/// <summary>
/// If <c>All</c> or <c>ModelOnly</c>, appends a validation summary. Acceptable values are defined by the
/// <see cref="ValidationSummary"/> enum.
/// </summary>
[HtmlAttributeName("validation-summary")]
public string ValidationSummaryValue { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just ValidationSummary

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conflicts with the enum and ends up with ugliness in the Process method wherever we reference the enum.

Ex if we were to have the property be ValidationSummary:

+                if (!Enum.TryParse(ValidationSummary, ignoreCase: true, result: out validationSummary))
+                {
+                    throw new InvalidOperationException(
+                        Resources.FormatValidationSummaryTagHelper_InvalidValidationSummaryValue(
+                            "validation-summary",
+                            TagHelpers.ValidationSummary.All.ToString(),
+                            TagHelpers.ValidationSummary.ModelOnly.ToString(),
+                            TagHelpers.ValidationSummary.None.ToString()));
+                }
+                else if (validationSummary == TagHelpers.ValidationSummary.None)
+                {
+                    return;
+                }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conflicts how? we do this elsewhere and everything Just Works(tm) e.g.

  Html5DateRenderingMode Html5DateRenderingMode { get; set; }

in IHtmlHelper. (yes, the Html5DateRenderingMode type is an enum)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The types are different, otherwise it'd work. If you refactor ValidationSummaryValue => ValidationSummary VS does what I put in the snippet because it can't compile otherwise.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strange that what seems the more complicated case just works. pity.


/// <inheritdoc />
/// Does nothing if <see cref="ValidationSummaryValue"/> is <c>null</c>, empty or "None".
public override void Process(TagHelperContext context, TagHelperOutput output)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add usual <remarks/> about when this no-ops

{
if (!string.IsNullOrEmpty(ValidationSummaryValue))
{
ValidationSummary validationSummaryValue;
if (!Enum.TryParse(ValidationSummaryValue, ignoreCase: true, result: out validationSummaryValue))
{
throw new InvalidOperationException(
Resources.FormatValidationSummaryTagHelper_InvalidValidationSummaryValue(
"<div>",
"validation-summary",
ValidationSummaryValue,
ValidationSummary.All,
ValidationSummary.ModelOnly,
ValidationSummary.None));
}
else if (validationSummaryValue == ValidationSummary.None)
{
return;
}

var validationModelErrorsOnly = validationSummaryValue == ValidationSummary.ModelOnly;
var tagBuilder = Generator.GenerateValidationSummary(
ViewContext,
excludePropertyErrors: validationModelErrorsOnly,
message: null,
headerTag: null,
htmlAttributes: null);

if (tagBuilder != null)
{
output.MergeAttributes(tagBuilder);
output.Content += tagBuilder.InnerHtml;
}
}
}
}
}
Loading