Share and Enjoy !

Introduction

Recently, I had a need to have certain “start up” data present the moment that an AngularJS app I was developing started running. Due to JS’s asynchronous nature, I couldn’t make a call back to the server to fetch the data without angular attempting to use the data before the call was completed.

Normally, when you need something to happen after an AJAX style call has been issued, you’d have your call return a promise and use the ‘then’ function to do what you needed. In this case, my AJAX call was being made by a service called in my angular ‘app.run(…)’ function. The service issued an HTTP GET to a WebAPI controller I had defined who’s sole purpose was to return some essential data I needed for my application to run.

Race condition

I also had an Angular controller that, at the same time, was trying to consume the data my aforementioned AJAX call was trying to retrieve. Obviously, that’s an issue and a fairly common one known as a ‘race condition.’

I don’t know if he came up with the solution or if he found it online, but I have to thank my former colleague, Sean Hester, for providing me with a a nifty solution to bootstrapping an Angular app with server-side data.

I recalled that, while we were working on another AngularJS project, Sean had implemented a way of injecting some data that we coded in C# in such a way that it was exposed in our Angular app’s javascript code. It was never clear to me how that happened but, since it worked and time was a constraint, I never looked into it.

MVC ApiController

Thankfully, I still have a copy of that code. After reviewing, what Sean had done was create an MVC ApiController that we added to our required data. On the return, he took that data, serialized it, and returned a formatted string that was actually a javascript function that simply defined our data in a namespace. Then, in our main layout, he added a script tag and set the ‘src’ attribute to the Route for the aforementioned ApiController. When the browser reaches the tag, it calls the ApiController, gets the string and inserts it between the script tags. Then, all you have to do is reference the namespace where you need it and, boom, you have your startup data.

My example HTML page.

  <html>
    <head>
      <script src="api/startup"></script>
      <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
      <script src="/scripts/angular/myApp.js">
    </head>
    <body>
     <div>{{currentUserName}} : {{currentUserId}}</div>
    </body>
  </html>

My example “Startup” API Controller

[RoutePrefix("api/startup")]
[HttpGet]
public class StartupController : ApiController
{
  [Route("")]
  public HttpResponseMessage Startup()
  {
    var data = new
    {
       userName: "Will Holland",
       userId: "U1234"
    }
    try
    {
      const string scriptFormat = "(function(s) {{ s.blog = s.blog || {{}}; s.blog.config = {0}; }})(window || scope)";
      var json = JsonConvert.SerializeObject(data);
      var script = String.Format(scriptFormat, json);
      response = Request.CreateResponse(HttpStatusCode.OK);
      response.Content = new StringContent(script, Encoding.UTF8, "text/plain");
    }
    catch (Exception ex)
    {
      //Error Handling
    }
    return response;
  }  
}

My Example Angular App

(function(s){
  var app = angular.module("myApp", []);
  
  if(demo.config == null) console.error("The Configuration Data must be defined before the angular app can run");
  
  app.run(["$rootScope", "config", function($rootScope, config){
    $rootScope.currentUserName = config.userName;
    $rootScope.currentUserId = config.userId;
  }]
})(window||scope);

Share and Enjoy !

Related Content: