So. You're using AngularJS to build your front end with ASP.Net running on the server side. You're a trustworthy dev - you know that validation on the client will only get you so far. You need to validate on the server.
My particular scenario is where you have a form which you are saving. Angular serves you well when it comes to hooking in your own client side validation. But it doesn't really ship with anything that supports nicely presenting server side validation on the client. Invariably when you look around you find people duplicating their server side validation on the client and presenting all their server side validation in a
<div> at the top of the screen.
This works but it's not as helpful to the user as it might be. It groups together all the validation from the server into one place. What I want is field level validation from the server that's presented on a field level basis on the screen. Like this:
I know. A thing of beauty is a joy forever. Let us travel together to this promised land...
Well, let's start with a directive which I'll call
serverError. This plants a validation message just after the element being validated which is displayed when that element is declared invalid by the server. (That is to say when the
ngModel has a
$error.server set.) When the element is changed then the
$error.server is unset in order that validation can be hidden and the form can be revalidated against the server.
If you look closely at this directive you'll see it is restricted to be used as an attribute and it depends on 2 things:
- The value that the
server-errorattribute is set to should be an object which will contain key / values where the keys represent fields that are being validated.
- The element being validated must have a name property (which will be used to look up the validation message in the
Totally not clear, right? Let's have an example. Here is my "sageEdit" screen which you saw the screenshot of earlier:
If you look closely at where
server-error is used we have a name attribute set (eg "sage.email") and we're passing in something called
<em>vm.</em>errors as the
server-error attribute value. That's because we're using the "controller as" syntax and our controller is called
On that controller we're going to have a dictionary style object called
errors. If you wanted to you could put that object on the scope instead and omit the "vm." prefix. You could call it
barry - whatever floats your boat really. You get my point; it's flexible.
Let's take a look at our sageEdit Angular controller:
Okay - this is a shedload of code and most of it isn't relevant to you. I share it as I like to see things in context. Let's focus in on the important bits that you should take away. Firstly, our controller has a property called
Secondly, when we attempt to save our server sends back a JSON payload which, given a validation failure, looks something like this:
So let's pare back our
save function to the bare necessities (those simple bare necessities, forget about your worries and your strife...):
At the point of save we wipe any server error messages that might be stored on the client. Then, if we receive back a payload with errors we store those errors and set the validity of the relevant form element to false. This will trigger the display of the message by our directive.
That's us done for the client side. You're no doubt now asking yourself this question:
So glad you asked. We've a simple model that looks like this which has a number of data annotations:
When we save we post back to a Web API controller that looks like this:
As you can see, when
ModelState is not valid we send back a dictionary of the
ModelState error messages keyed by property name. We generate this with an extension method I wrote called
That's it - your solution front to back. It would be quite easy to hook other types of validation in server-side (database level checks etc). I hope you find this useful.