parse all html helper extensions on page before load mvc3
I have written some extension methods that extend the html helper class for client side form validation. What I'd like to be able to do is have the page loaded with an array (javascript) of all of my开发者_开发技巧 elements that are part of my validation "library".
example:
@Html.VTextBox("blah)
@Html.VDropDownList("bling")
@Html.VTextBox("bloo")
when the page is loaded, I'd like a javascript array placed at the top filled with something like this:
errorListArr = new Array("blah","bling","bloo");
Currently what I'm doing is using errorListArr.push() for each element and writing out script tags each time ... clearly not the most elegant way to do this. I'd also like to figure out how I can parse the whole page ahead of time so that I can put together my list of elements that I'm going to need to validate server side.
Please let me know if this can be done and any code snippet/samples would be appreciated.
I'm not entirely clear on what you're trying to do, but I think I understand enough to point you in the right direction.
First of all, server-side validation in MVC 3 is typically done as a postback to an action that takes a model and validates it. If the model isn't valid, you return the view with the (now-validated) model, and the view will render the appropriate error messages for the properties that were wrong.
By default, you can define what validation to perform by adding certain attributes to the properties on the model that you're rendering inputs for.
What's more, MVC is smart enough to output client-side javascript to perform many of these validations when the user tries to submit the form, without actually requiring a post-back at all!
See this post for a walk-through of how to use model validation.
In MVC 3, you also have the option to enable "unobtrusive javascript" validation, which basically does the same client-side validation as usual, but instead of generating a bunch of inline javascript, it simply flags the input elements with certain "data-" attributes. A couple of jquery-based libraries then scan the page for elements with these flags, and add the appropriate validation handlers to them.
If you have validation needs that go beyond what MVC offers out of the box, it is easy to add your own validation attributes, or even make your model perform custom logic to validate itself.
Generally speaking, if you find that you're rendering a lot of little javascript snippets client-side, you may want to follow the "unobtrusive javascript" pattern yourself:
- Put code in a static javascript file that knows how to scan the DOM for specific flags that it's interested in.
- Render your HTML elements with these flags added, using "data-" attributes to add specifics where necessary.
Your "validation library" probably doesn't contain so much extension methods. So it would not be so inelegant to place in each of them the same line of code to add the processed element's name into your array.
Another way would be indeed to artificially make something common to all the elements validated thanks to your "validation library" : a common marker interface. The idea is : don't use the elements as instances of their real types. Make instead subtypes of these types which also implement the interface IValidated
with only one string ID
member (I suppose here that all the elements you're interested in already have such a property thanks to the original class they're instances of).
Then, once you've done all you need, you build your array just once as an ending action before sending the page to the client. Now that all your custom-validated elements are recognizable thanks to IValidated
, that's pretty easy with a one-liner like this :
errorListArr = new Array(this.Page.SubControls().OfType<IValidated>().Select(elt => elt.ID));
SubControls
being a very handy extension method to get all the subcontrols whatever their depth in the controls tree :
public static IEnumerable<Control> Subcontrols<T>(this T parentControl) where T : Control
{
//Recursively returns all the parentContol's descendant controls
foreach (Control ctrl in parentControl.Controls)
{
yield return ctrl;
foreach (Control childCtrl in ctrl.Subcontrols())
{
yield return childCtrl;
}
}
}
Sure you may have to make a few adaptations to reach your exact needs, but that's essentialy the idea.
This second option has the main advantage to give "something common" to all your elements, despite they're all instances of various classes which otherwise have maybe really few in common. You create a new functional abstraction which is specific to your project and later you'll be able to extend IValidated
with specific extension methods if you need to, for instance...
精彩评论