smartstore / Smartstore

A modular, scalable and ultra-fast open-source all-in-one eCommerce platform built on ASP.NET Core 7
http://www.smartstore.com/
GNU Affero General Public License v3.0
1.2k stars 447 forks source link

Postback happens when using RuleFor with When in FluentValidation #1144

Closed suatsuphi closed 3 months ago

suatsuphi commented 3 months ago

Hi,

Postback happens when using RuleFor with When in FluentValidation... Is it normal ?

RuleFor(x => x.Delay).NotNull().WithMessage(T("Plugins.Smartstore.BT.PageBuilder.NotEmptyValidator"))
     .When(x => x.Zone != null);
muratcakir commented 3 months ago

Postback happens when using RuleFor with When in FluentValidation... Is it normal ?

Yes, it is. Because When() can contain complex expressions that may not be processable on the client-side.

suatsuphi commented 3 months ago

There are two problems when I use "when" for postback.

1- html b tag is not processed 2- is-invalid class is not added to input. Instead input-validation-error is added.

image

muratcakir commented 3 months ago

1- html b tag is not processed

Where does the b tag come from? We don't render HTML tags in standard validation messages. Maybe a custom message? You have to call Html.Raw(...) in the template that renders the validation messages in order to output the message as is.

2- is-invalid class is not added to input. Instead input-validation-error is added.

Is fixed by 2d2b15f

suatsuphi commented 3 months ago

1- html b tag is not processed

public class PageObjectModelValidator : SmartValidator<PageObjectModel> or public class PageObjectModelValidator : AbstractValidator<PageObjectModel>

When(x => (x.Zone?.Contains("PopupWindow")).GetValueOrDefault(false), () =>
 {
     RuleFor(x => x.Delay).NotEmpty();
 });

or

 When(x => (x.Zone?.Contains("PopupWindow")).GetValueOrDefault(false), () =>
 {
     RuleFor(x => x.Delay).NotEmpty().WithMessage(T("Plugins.Smartstore.BT.NotEmptyValidator"));
 });

I use model's validator and get the same result

image

suatsuphi commented 2 months ago

for testing purposes @Html.ValidationMessageFor(m => m.Delay).ToHtmlString().Value

 <div class="adminRow">
     <div class="adminTitle">
         <smart-label asp-for="Delay" />
     </div>
     <div class="adminData">
         <editor asp-for="Delay" />
         <span asp-validation-for="Delay"></span>
         @Html.ValidationMessageFor(m => m.Delay).ToHtmlString().Value
     </div>
 </div>

result : &lt;b&gt;Delay&lt;/b&gt; cannot be empty

<b>Delay</b> cannot be empty
<span class="field-validation-error" data-valmsg-for="Delay" data-valmsg-replace="true">&lt;b&gt;Delay&lt;/b&gt; cannot be empty</span>
muratcakir commented 2 months ago

Just @Html.ValidationMessageFor(m => m.Delay) is sufficient. You could also try @Html.Raw(@Html.ValidationMessageFor(m => m.Delay))

suatsuphi commented 2 months ago

<span>@Html.Raw(ViewData.ModelState["Delay"]?.Errors.FirstOrDefault()?.ErrorMessage)</span>

If I use it this way, my question is solved.

Source of the problem asp-validation-for="Delay"

<span asp-validation-for="Delay"></span>

suatsuphi commented 2 months ago

the same problem in <div asp-validation-summary="All"></div>

This problem occurs when postback.

suatsuphi commented 1 month ago

<div class="mt-4" asp-validation-summary="All"></div>

<span asp-validation-for="PropertyName"></span>

solution to the problem

$(document).ready(function () {
 $('.field-validation-error').each(function () {
    $(this).html($(this).text());
 });

 $('.validation-summary-errors').each(function () {
     $(this).html($(this).text());
 });
});
suatsuphi commented 1 month ago

chatgpt suggested something like this... replaces the message that comes with ajaxComplete.

    $(document).ajaxComplete(function () {
        $('.field-validation-error').each(function () {
            var rawHtml = $(this).html();
            $(this).html(rawHtml.replace(/&lt;/g, '<').replace(/&gt;/g, '>'));
        });
        $('.validation-summary-errors').each(function () {
            var rawHtml = $(this).html();
            $(this).html(rawHtml.replace(/&lt;/g, '<').replace(/&gt;/g, '>'));
        });
    });