2015-01-30

Angular is a great tool for enriching an ASP.NET MVC application, but you must bridge the gap between your client-side code and your server-side code in order to use it effectively.  In this post, I’ll show you a couple of ways that you can pass data from your Razor views to your AngularJS components.



The Challenge

The challenge we’re trying to solve is handing data off from our .NET code, which executes server-side, to our JavaScript code, which executes client-side.   Now, I know what you’re thinking, “That’s easy!  Just return the data from Web API as JSON and grab it using $http!  DUH!”  But that’s not the challenge we’re tackling here.  That approach requires two round-trips to the server: one to get the page, and another to get the data.  Instead, we’re going to hand the data off as part of the initial page load.  We’re going to “bootstrap” our client-side app by handing data directly from our Razor view to our JavaScript.

There are several reasons why you may wish to do this rather than using AJAX requests.  First, there’s the aforementioned benefit of grabbing all the data as part of the initial request.  Second, there are some things that just make more sense to pass from Razor.  For example, did you know you can generate URLs for MVC action methods in a strongly-typed way using HtmlHelpers?  You can use these helpers in combination with the techniques below to make sure your Angular components always hit the correct URLs for their AJAX requests.

Alright, so that’s what we’re going to do and why, now let’s look at the how.

Option 1: using ng-init

There’s a seldom used AngularJS directive called ngInit that you can use to modify data on the current scope.  So, you could do something like this in your Razor view:

Our Razor view is handed an array of PersonViewModel objects, and for whatever reason, we want to bind that using Angular rather than just looping over them server-side (maybe we want to provide client-side editing or something like that!)  We can use the ngInit directive to call a function on our controller, and we can use JSON.net to convert our array into JSON to pass to our init function.  Here’s what the final HTML looks like after it’s been rendered by Razor:

As you can see, our server-side model has been serialized to JSON and inlined into our HTML.  Angular will evaluate the value of the ng-init attribute relative to our current scope, so we’ve effectively passed server-side data off to our client-side controller.

This approach does work, but there are a few problems with it.  First, I feel like it breaks the standard way of using AngularJS.  Services, config, etc should be injected into components, not built-up after the fact.  Using ngInit feels more like setter-injection rather than constructor injection. Second, it produces some terribad HTML, especially if you have a lot of data you need to pass.  Finally, even the Angular docs mention that this isn’t a good use of ngInit:

The only appropriate use of ngInit is for aliasing special properties of ngRepeat…

There are still times when ngInit is the right solution, but I typically prefer the second option…

Option 2: using a value provider

A better way (in my not-so-humble opinion) is to use a value provider.  Once we’ve registered our model, it becomes injectable into any Angular component: controllers, directives, and services.

First, we need to register the value on our page.  Assuming you have a Scripts section registered on your layout, you can do something like this:

Now all you have to do is declare it as a dependency in your controller:

This approach works well with other things that you might want globally-accessible, too, like maybe the name of the current user:

BONUS OPTION: globally registering your view model

If you’re like me and you like to bake useful things in to your application framework, this one is for you!  You can register add a bit of magic to your Razor layout to always take the current view model and make it available as an injectable value with Angular.  Here’s what’s in my _Layout.cshtml:

Now any controller, service, or directive can access the current model just by declaring ‘model’ as a dependency!

CAUTION: Be careful what you pass down!

Remember: whatever you pass off to the client, no matter which method you use, puts that data in the hands of the enemy (so to speak).  Be very selective in what you pass down.  DO NOT pass down sensitive information, like database connection strings (yes, I’ve seen examples where people have done exactly that!)

And remember, these techniques are not a replacement for making AJAX requests with $http.  This is just another tool you can add to your bag of tricks.

The source for these methods is available on github.  I’m going to be putting together more examples of combining AngularJS and ASP.NET MVC in the coming weeks in preparation for my next Pluralsight course, so stay tuned!

Do you have other ways for passing data down to Angular?  Sound off in the comments!

Show more