Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using razor views with jQuery validation with angularJS

I'm using AngularJS in my MVC application and trying to use the best of both worlds. I really like how you can in MVC set up your validation logic in your viewmodels and generate client side validation with jQuery validation in your razor views with little effort. I use AngularJS to get the SPA behavior with routing etc, but when I create a razor view that I use to inject into a page with: <div data-ng-view="data-ng-view"></div>

then the jQuery validation stops working, even though the script files is references on the page where the view is injected. See below for my razor view:

@model BandViewModel
<div data-ng-controller="App.BandCreateCtrl">
    <form name="startBandForm">
        @Html.ValidationSummary(true)
        <br />
        @Html.LabelFor(m => m.Name)
        @Html.TextBoxFor(m => m.Name, new { data_ng_model = "band.Name" })
        @Html.ValidationMessageFor(m => m.Name)
        <br/>
        <input data-ng-disabled="startBandForm.$invalid" type="submit" data-ng-click="createBand(band)" value="Create"/>
    </form>
</div>
like image 949
Arnstein Avatar asked Jun 09 '13 13:06

Arnstein


4 Answers

First of all, IMO using Razor to render your templates is fraught with peril, at best. Generally you want to use static HTML for your page and directive templates, and then retrieve and post data as AJAX to your API. The ASP.NET web API is really good at this, actually. If your underlying model has validation, then bad web API calls will throw an exception, which you can catch in your $http or $resource handler and show to the user. Mixing standard HTTP form posts with AngularJS will be... difficult.

To achieve what you want, I think someone (not me) would have to write the AngularJS equivalent to jQuery Unobtrusive Validation library, which itself is using the jQuery Validate plugin. Not trivial. I personally don't see drop-in Angular validation happening soon, especially since it has more to do with markup and less to do with a JS configuration object.

Possibly you could re-initialize the validation when the view has finished loading using the $viewContentLoaded event. But please don't.

like image 128
Barnabas Kendall Avatar answered Nov 16 '22 22:11

Barnabas Kendall


It pains me that everywhere I've looked we get the same replies: "HTML should just be a template". Perhaps, but I'm just not ready to delegate everything to JavaScript

Instead of using the anonymous object for passing the HTML attributes, try using the Dictionary

@Html.TextBoxFor(m => m.Name, new Dictionary<string, object>(){{ "data_ng_model",  "band.Name" }})

Make sure is

Dictionary<string, object>

And not

Dictionary<string, string>

Otherwise the constructor will confuse it for

object HtmlAttribute

Not as pretty though... but it works for the most part.

Lastly, take in mind that if you include AngularJS after jQuery, then it will use jQuery for selectors.

like image 32
percebus Avatar answered Nov 16 '22 23:11

percebus


To anyone still looking for a solution to this problem , there is a simple way to make it work.

    var currForm = $("#myForm");
currForm.removeData("validator");
currForm.removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse(currForm);
currForm.validate();

You could put this code in $viewContentLoaded or other places which are relevant in your code.

While I understand some of the views here which discourage MVC views being used as a templates for your Angular code. My reason being its not not a natural way of doing things in angular and hence there are chances that you will run into issues like this one. But if you benefit from using MVC views as templates its not a path to hell. IT works and can benefit you as well. I have 2 use cases in my project where using MVC views make a lot of sense.

  1. My project actually has a requirement where a client can turn of the required validation on certain field , for this I use the MVC custom data annotation validator which allows me to add or remove the data annotation at the time of rendering the view using a single class , if you were to build the same flexibility in angular , you would have to write a lot more code. So MVC views work great here for me as Custom Data Annotations are triggerd by the DisplayFor and EditorFor helpers
  2. We are heavily invested in Internationalization and while angular is great at other stuff internationalization is not its strong suite ( at the time of writing this atleast )I still feel the internationalization support in MVC with .RESX works great and has been here long . This again uses the data annotation power of the DisplayAttribute.

TLDR : MVC views as templates may give you a few unexpected problems but are worth it if you are really using the full power of the data annotation pipeline created by Microsoft.

Hopefully someone comes up with a Angular HTML Helpers library in the future this would be much simpler.

like image 4
Pratik Avatar answered Nov 16 '22 21:11

Pratik


Maybe using Angular for validation can be less painful than you think. Using a couple of custom directives, you could easily get something quite close to Razor with markup as simple as:

    <validated-input name=username display="User Name" ng-model=model.username required</validated-input>

Check out my sample here and its inspiration here. It only implements required and number at the moment, but customizing it should be easy.

like image 1
Jeff Dunlop Avatar answered Nov 16 '22 23:11

Jeff Dunlop