I figure choices are usually a good thing. For instance, I recently fleshed out my Blazor form generation library with some nice, added features. The goal, in making those changes, was to give developers more ways to do the same things. More choices are almost always a good thing.
What do I mean by “more choices”? Let’s go look at an example.
Suppose we needed to generate a simple form with a tab control, and two tabs, where each tab contains dynamically generated form content. Everything in the tab control should be inside the form tag, and therefore, all validated and submitted as a single transaction. The end result should look something like this:
Now granted, this is a hypothetical example. Still, I did need to do something like this, for one of my Blazor plugins, so, it’s not altogether theoretical.
So, how would we do this?
Well, the first way is to use the DynamicForm
component, and have it generate everything for us. Here us what the markup would look like:
@page "/example1" <DynamicForm Model="@Model" OnValidSubmit="OnValidSubmit" /> @code { private MyVM Model { get; set; } = new MyVM(); private void OnValidSubmit(EditContext editContext) { // TODO : do something with the submit. } [RenderMudTabs] public class MyVM { [RenderMudTabPanel(Text = "Panel A")] public ModelA A { get; set; } = new ModelA(); [RenderMudTabPanel(Text = "Panel B")] public ModelB B { get; set; } = new ModelB(); } public class ModelA { [RenderMudTextField] public string A1 { get; set; } = "A1 value"; } public class ModelB { [RenderMudTextField] public string B1 { get; set; } = "B1 value"; } }
The markup couldn’t be simpler, just the single call to DynamicForm
. The Model
attribute is pointed at our Model
property. The callback for the OnValidSubmit
handler is pointed to our OnValidSubmit
method. So far, so good.
The MyVM
model has a few attributes applied to it that we need to go over. The first is the RenderMudTabs
attribute. That attribute instructs the form generator to wrap the content, for the MyVM
model, inside a MudTabs
control.
Since we’ve started by rendering a MudTabs
control, it stands to reason that our next step should be to render a couple of MudTabPanel
controls. right? The RenderMudTabPanel
attributes, on the A
and B
properties of the MyVM
class, take care of that. Each RenderMudTabPanel
attribute instructs the form generator to render that property inside a MudTabPanel
control.
For my example, I chose to give each tab a single text box field. Just so the tab would have something to display. So, as we can see, the ModelA
and ModelB
classes each have a single string property, decorated with a corresponding RenderMudTextField
attribute. The RenderMudTextField
attribute instructs the form generator to render the string property using a MudTextField
control, that is then bound to the property, on the model.
That constitutes one way of generating dynamic content inside a tab control. Let’s go look at another way now.
Suppose, for the sake of argument, that we needed to manually generate parts of a form, and dynamically generate other parts. Further, let’s say that we need to end result to look exactly the same as the first example:
How might we do that?
One way is to drop the use of the DynamicForm
, which generates the actual form, as well as any dynamic content for the form. Instead, let’s use the DynamicContent
component, which only generates the dynamic content and leaves everything else up to us. Let’s see what that might look like:
@page "/example2" <EditForm Model="@Model" OnValidSubmit="OnValidSubmit"> <MudTabs> <MudTabPanel Text="Panel A"> <DynamicContent Model="@Model.A"/> </MudTabPanel> <MudTabPanel Text="Panel B"> <DynamicContent Model="@Model.B"/> </MudTabPanel> </MudTabs> <button type="submit">Submit</button> </EditForm> @code { private MyVM Model { get; set; } = new MyVM(); private void OnValidSubmit(EditContext editContext) { // TODO : do something with the submit. } public class MyVM { [RenderObject] public ModelA A { get; set; } = new ModelA(); [RenderObject] public ModelB B { get; set; } = new ModelB(); } public class ModelA { [RenderMudTextField] public string A1 { get; set; } = "A1 value"; } public class ModelB { [RenderMudTextField] public string B1 { get; set; } = "B1 value"; } }
In this second example, we’re now handling the EditForm
tag ourselves. We still point the Model
attribute at our Model
property. We still wire up a handler for the OnValidSubmit
callback. The difference is, this time, we have absolute control over our form, and, we STILL get to dynamically generate our form content, using the DynamicContent
components.
We’ve manually built up the MudTabs
control, with the two MudTabPanel
controls. Each MudTabPanel
then contains a single DynamicContent
component whose Model
attribute is pointed to a particular part of the parent model.
The attributes we’ve used are a little different, for the MyVM
class. Since we aren’t asking the form generator to create the tabs, there isn’t a RenderMudTabs
attribute on the MyVM
class definition. Also, since we aren’t asking the form generator to create the tab panels, we’ve swapped out the RenderMudTabPanel
attributes for RenderObject
attributes. The RenderObject
attribute instructs the form generator to simply render the content for an object property.
So, why manually build up the form and the tabs when we can get the form generator to handle all that for us?? Well, think about it, we might need to integrate with a library that I haven’t, as yet, created support for. Or, we might need to add additional content to the HTML – perhaps an additional icon in the tabs, for instance.
Also, we might need to add a validator to the form that I haven’t, as yet, added support for. That’s another perfectly valid reason to render the form manually.
The other way we could have handled our hypothetical example, is to go create our own version of RenderMudTabs
and RenderMudTabPanel
attributes. I’ll write about that at some point, but not today. for now, just know that writing your own attributes is another way to get things done.
I hope I’ve demonstrated that my Blazor form generation library is flexible, and extensible, and easily capable of handling both simple form generation scenarios, as well as not so simple.
As always, all of my source code is available, for free, HERE.
All of my NUGET packages are available, for free. HERE.
Photo by Beth Macdonald on Unsplash