Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,23 @@ public class SampleModel

[Display(Name = "Select List Item")]
public SampleEnum? SelectedListItem { get; set; }

[Display(Name = "Set Default Password")]
public bool SetDefaultPassword { get; set; }

[Display(Name = "Agree to Terms (Disabled)")]
public bool AgreeToTerms { get; set; } = true;
Comment on lines +46 to +47
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add Required attribute for terms agreement.

Since this is a terms agreement checkbox, consider making it required and adding a description.

 [Display(Name = "Agree to Terms (Disabled)")]
+[Required(ErrorMessage = "You must agree to the terms to continue.")]
+[Description("By checking this box, you agree to our terms and conditions.")]
 public bool AgreeToTerms { get; set; } = true;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[Display(Name = "Agree to Terms (Disabled)")]
public bool AgreeToTerms { get; set; } = true;
[Display(Name = "Agree to Terms (Disabled)")]
[Required(ErrorMessage = "You must agree to the terms to continue.")]
[Description("By checking this box, you agree to our terms and conditions.")]
public bool AgreeToTerms { get; set; } = true;


[Display(Name = "Item 1")]
public bool Item1 { get; set; }

[Display(Name = "Item 2")]
public bool Item2 { get; set; }

[Display(Name = "Item 3")]
public bool Item3 { get; set; }

[Display(Name = "Item 4")]
public bool Item4 { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@
</form-input>
<form-select asp-for="SelectedListItem" asp-items="Html.GetEnumSelectList<SampleEnum>()">
</form-select>

<form-checkbox asp-for="SetDefaultPassword" is-switch="true"></form-checkbox>
<form-checkbox asp-for="AgreeToTerms" disabled="true"></form-checkbox>
<div class="mb-3">
<label>Select Your Options</label>
<form-checkbox asp-for="Item1" container-class=""></form-checkbox>
<form-checkbox asp-for="Item2" container-class=""></form-checkbox>
<form-checkbox asp-for="Item3" container-class=""></form-checkbox>
<form-checkbox asp-for="Item4" container-class=""></form-checkbox>
</div>

<bs-button type="Submit" value="Click Here To Test Validation">Click Here To Test Validation</bs-button>
</form>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.VisualBasic;
using System;
using System.Text.Encodings.Web;

namespace ICG.AspNetCore.Utilities.Bootstrap5TagHelpers.Form;

/// <summary>
/// TagHelper for rending Bootstrap form compliant checkbox controls with support for ASP.NET Core model Binding. Will
/// include Label, Field, and validation.
/// </summary>
[RestrictChildren("form-checkbox")]
public class FormCheckboxTagHelper : InputTagHelper, IFormElementMixin
{
/// <inheritdoc />
public IHtmlGenerator HtmlGenerator { get; }

/// <summary>
/// The CSS class that should be applied to the containing div, in addition to that of the form-check that is required
/// </summary>
public string ContainerClass { get; set; } = "mb-3";

/// <summary>
/// Indicator if the input should be rendered as disabled
/// </summary>
public bool Disabled { get; set; } = false;

Check notice on line 28 in src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormCheckboxTagHelper.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormCheckboxTagHelper.cs#L28

Remove this initialization to 'Disabled', the compiler will do that for you.

/// <summary>
/// Controls if this should be rendered as a switch
/// </summary>
public bool IsSwitch { get; set; } = false;

Check notice on line 33 in src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormCheckboxTagHelper.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormCheckboxTagHelper.cs#L33

Remove this initialization to 'IsSwitch', the compiler will do that for you.


/// <summary>
/// Public constructor that will receive the incoming generator to leverage existing Microsoft Tag Helpers
/// </summary>
/// <param name="generator"></param>
public FormCheckboxTagHelper(IHtmlGenerator generator) : base(generator)
{
HtmlGenerator = generator;
}

/// <summary>
/// Used to actually process the tag helper
/// </summary>
/// <param name="context"></param>
/// <param name="output"></param>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//Call our base implementation
base.Process(context, output);

//Set our tag name
output.TagName = "input";

//Add the form-control class
if (Disabled)
{
output.Attributes.Add("disabled", "");
}

output.AddClass("form-check-input", HtmlEncoder.Default);

//Add before div
var groupClass = $"form-check {ContainerClass}";
if (IsSwitch)
{
groupClass += " form-switch";
output.Attributes.Add("role", "switch");
}
this.StartFormGroup(output, groupClass);

//Generate our label if not inline
this.AddLabel(output, "form-check-label");

//Now, add validation message AFTER the field if it is not disabled
if (!Disabled)
{
this.AddValidationMessage(output);
}

//Close wrapping div
this.EndFormGroup(output);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,24 @@
public static void EndFormGroup(this IFormElementMixin element, TagHelperOutput output)
=> output.PostElement.AppendHtml("</div>");

public static void AddLabel(this IFormElementMixin element, TagHelperOutput output)
public static void AddLabel(this IFormElementMixin element, TagHelperOutput output, string cssClass = "form-label", bool isPostElement = false)
{
//Find out if required to add special class
var isRequired = element.For.ModelExplorer.Metadata.ValidatorMetadata.Any(o => o is RequiredAttribute);
var targetClass = isRequired ? "form-label required" : "form-label";
var targetClass = isRequired ? $"{cssClass} required" : cssClass;
//Generate our label
var label = element.HtmlGenerator.GenerateLabel(
element.ViewContext,
element.For.ModelExplorer,
element.For.Name, null,
new { @class = targetClass });
output.PreElement.AppendHtml(label);
if (isPostElement)

Check failure on line 48 in src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormElementMixin.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormElementMixin.cs#L48

Add curly braces around the nested statement(s) in this 'if' block.
output.PostElement.AppendHtml(label);
else

Check failure on line 50 in src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormElementMixin.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/AspNetCore.Utilities.Bootstrap5TagHelpers/Form/FormElementMixin.cs#L50

Add curly braces around the nested statement(s) in this 'else' block.
output.PreElement.AppendHtml(label);
}


public static void AddValidationMessage(this IFormElementMixin element, TagHelperOutput output)
{
var validationMsg = element.HtmlGenerator.GenerateValidationMessage(
Expand Down