[Validation.Enabled Property] Not working in Repeater

I have created a custom control that adds a series of buttons as set by the containing page.

The page needs to be able to control if any button in the set disables page validation using the Validation.Enabled property set on the button.

An error occurs when I use this property. See below.

<dot:Repeater ID="PageTabActions" class="nav-item pt-1" DataContext="{value: TabActions}" DataSource="{value: _root.TabActions}">
    <ItemTemplate>
        <%-- Option 1: This way causes error --%>
        <dot:Button Text="{value: _this.Text}" class="{value: _this.CssClass}" Click="{command: _root.PageTabActionButtonClick(_this)}"
                    Validation.Enabled="{resource: !_this.SkipPageValidation}"></dot:Button>

        <%-- Option 2: Having two works but is annoying and extra work --%>
        <dot:Button Text="{value: _this.Text}" class="{value: _this.CssClass}" Click="{command: _root.PageTabActionButtonClick(_this)}"
                    Validation.Enabled="true" IncludeInPage="{value: !_this.SkipPageValidation}"></dot:Button>
        <dot:Button Text="{value: _this.Text}" class="{value: _this.CssClass}" Click="{command: _root.PageTabActionButtonClick(_this)}"
                    Validation.Enabled="false" IncludeInPage="{value: _this.SkipPageValidation}"></dot:Button>

    </ItemTemplate>
</dot:Repeater>

I included a version that works that has two copies of the button, one for enabled and one for disabled. However, that seems like a hack. Surely there is a better way.

Side note: the property does not allow for a value binding, but does allow for a resource binding.

When the page loads with Option 1, the following error is generated:

Commenting Option 1 out causes the page to load and to function correctly.

What is the best way to accomplish this?

Thanks!

So the answer depends on whether you want to allow the user to disable the validation. In your example, all it takes is to click the hidden button and the postback passes without client-side nor server-side validation.

If that’s fine, you can probably just set RenderSettings.Mode=Server on the Repeater. Note that it will make it impossible to add new Tabs to the page during postbacks. Otherwise, you can workaround it by setting Validation.Target={value: TheCondition ? _this : _root.Decoy}, where the decoy is something like:

public object Decoy { get; set; } = new object();

This is will not technically disable validation, but it will validate an empty object, so no new (automatic) errors are added.

Thank you for the reply. Sorry it’s taken me so long to get back to you. I got pulled into other things and am just now able to return to this issue.

I tried implementing the suggested workaround. I am not able to get it to work.
I tried each of the following but they all cause the same result.

Validation.Target="{value: true ? _this : _root.Decoy}"
Validation.Target="{value: true ? _root : _root.Decoy}"
Validation.Target="{value: true ? _page : _root.Decoy}"

In all cases, the validation is skipped and I cannot get it to run.

Perhaps I am going about this all the wrong way.

Here is an example of a page that needs to sometimes disable validation.
image

Before I added the dual buttons, I found that when I clicked the cancel button while the page was in an invalid state (shown), the page validation was running and the Cancel button did not work until the page was valid.

In this example, I need the Submit button to always run validation and the Cancel button never to. Both buttons are only added when the containing page adds them to the TabActions collection of buttons that get created by a repeater control as shown above.

What is the best way to accomplish this?

Looking at this again, I’d suggest finding a way to get custom markup into the PageTabActions element. Do you really need to specify the actions in the view model or is it just a workaround for another issue?

I tested it last week, since I wasn’t sure it would work, but it worked fine for me. If you want to go this route, would you please share a larger piece of code do I’d be able to replicate it?

I will prepare a simplified version of the application that can run outside our environment. Once that is done, I’ll share it. I’m not sure how long it will take me to build that.
Thanks!

The simplified version is available as a standalone project here. I have included enough code and mocked enough objects to allow this part of the application to build/run without the rest of the application.

(Note: the project uses both Bootstrap4 and BusinessPack libraries)

This is part of a project to migrate an ASP.net application over to DotVVM and off of webforms. I have to make the new pages behave the same as and look as similar as possible to the pages they replace.

I recognize there may be a much better way to do this but this is what I currently have.

The basic requirements

  • the page defines which buttons are on the TitleBar on each page (name, order, action, etc)
  • the page handles the click events for each button (only the page knows what to do with them)
  • the field controls (like FieldDate or FieldComboBox) must execute their own Validate method
  • the page must execute its Validate method
  • when the page indicates not to validate for a particular button (like a cancel button) the validation should be skipped (I like the Decoy idea for this but haven’t gotten it to work); validation should run for all buttons unless indicated not to

To answer the previous question about the action handler, yes the page’s view model needs to handle it. The actions will be different on every page.

After running this sample app, click on the Admin/Configuration/TimeSheetPeriod link.

There will be two sets of buttons on the page. The grey buttons are created by the single entry I am trying to get to work. The blue ones are created by the set of duplicated buttons and behave as needed.

With the code as-is

Clear the value in either of the date fields.

When you click the blue or grey Submit button, the page will cause the validation to occur (it will execute the Validate() method in the FieldDateViewModel and then in the page’s view model). The page will correctly tell you the field is required.

Clicking the blue Cancel button in an error state will bypass validation and correctly navigate to another page.

Clicking the grey Cancel button will cause validation and not navigate away. (Cancel needs to be able operate without validation.)

Uncomment any of the Validation.Target lines in TitleBar.dotcontrol

Clear the value in either of the date fields.

Click the grey Submit button. The Validate method in the FieldDateViewModel will not execute (it should) and the Validate method in the TimeSheetPeriodViewModel will also not execute (it also should). An error will then occur in the MapPageToViewModel method as it is not intended to reach there with data in this state.

Hopefully this is sufficient information. Let me know what questions or suggestions you have.

Thank you so much!

Sorry, I don’t have it running, but are you sure that Validation.Enabled is true at that point?


Anyway, I still think we have more of an XY problem. If part of the TitleBar was inlined into the Layout.dotmaster, you could place a <dot:ContentPlaceHolder /> into the div#TitleBarActions. Then, each page can define the actions in dothtml markup, instead of dynamicly defining them in the ViewModel.

I did a text search for “Validation.Enabled” in the entire solution and the only results are from the 3 pairs of buttons that do behave as needed but are not part of the button I’m trying to get to work as a single button.

I am assuming that the default value for Validation.Enabled is true. If that is the case, then, yes, it is true since nothing would be changing it.


This will require some major rewriting and is very different from what the ASP pages currently do. I’ll do a prototype to see if I can get that to work and if it will work within the larger application without disrupting the overall goals of the conversion project or adding too much more time.


However, it does seem like what I am trying to do should work. Not sure why it is not.

Yes, the default is true. Sorry, I was unsure because of the comments above the resource binding.

Yes, it should. It’s just the security implication of dynamic approach that is making me uneasy - this likely works differently in DotVVM than in WebForms. The Validation.Target trick did work for me in a different place, so it must be interacting with something else.

@tomasherceg Could you maybe have a look why doesn’t the validation trigger, if you have some time? It’s a .NET Framework project

Thank you, gentlemen.

I was able to get a working solution that meets all the requirements listed above.

The buttons are still dynamically created by each page as needed. The validation runs by default but can be skipped on a per button basis as defined by the page.

The Solution
I moved all the dothtml markup from the TitleBar custom control directly onto the Layout.dotmaster and removed the TitleBar.dotcontrol. TitleBarViewModel.cs is still being used with very little change. I added the new Decoy object to LayoutViewModel.cs. Note that the object of type TitleBarViewModel was already a member of LayoutViewModel and that is still the case. It is shared by all pages.

Hopefully this helps someone with a similar issue.

I still think it should have worked with the markup in the custom control but I am glad for a solution and I can move on.

1 Like

Ok great! Sorry, it didn’t occur to me that the decoy trick could be affected by the markup control. I’ll try that out, hopefully, I can reproduce the issue and fix the bug.

1 Like