1

EDIT: This question is deprecated. Please see How to set a variable from an $http call then use it in the rest of the application WITHOUT making the whole application asynchronous instead.

In my constant, I need to read from a local file. The way I've seen to do that is $http.get('localfile.ext').then ...

It's telling me $http is undefined. The documentation says constant is special, services are available in a constant.

angular.module('myApp').constant(
  'test',
  ['xml','$http',
  (function ($http, x2js) {
    $http.get('web.config').then(function (response) {
      var appSettings = [];
      /*setting up the response*/
      var json = x2js.xml_str2json(response.data);
      var url = '' /* get url from json */;
    });
    // Use the variable in your constants
    return {
      URL: url
    }
  })()]);

EDIT:

Ok this documentation says you can't use DI in a constant. But I need to use $http to get a value and use it to set a constant. So how can I do it or what would be a alternative that allows me to read the value anywhere in the app once it is set?

Community
  • 1
  • 1
toddmo
  • 20,682
  • 14
  • 97
  • 107

3 Answers3

1

Build a constant

Build the confguration into Angular constant with build system. There are grunt-ng-constant and gulp-ng-constant.

Resolve the dependency

Use ng-route or ui-router resolve to resolve config dependency for all routes.

Defer bootstrap

Defer bootstrapping process to resolve global dependencies before the app is there with angular-deferred-bootstrap.

Use synchronous request

Synchronous requests are blocking, and bad, and blocking... they are bad also. Either raw XMLHttpRequest or jQuery.ajax can be used ($http doesn't support synchronous requests).

app.config(function ($provide) {
  var config;

  var xhr = new XMLHttpRequest();
  xhr.open('GET', 'configfile', false);
  xhr.send();
  if (xhr.status == '200') {
    config = xhr.responseText;
  }

  $provide.constant('config', config);
});
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
0

What I've generally done is to generate the code for the constant on the server. As opposed to having the constant populated by some call back to the server.

using Newtonsoft.Json.Linq;

public class JavascriptConstantsHelper
{
    public static string GetConstantsJavascriptFile()
    {
        var constantsCollectionModel = new JObject();

        constantsCollectionModel.Add("version", CoreAssembly.Version.ToString());


        const string outputTemplate = @"
            (function() {
                'use strict';

                window.myModule.constant('constantsCollection', function() {
                    return {constantsCollection};
                });
            })();";

        return outputTemplate.Replace("{constantsCollection}", constantsCollectionModel.ToString());
    } 
}

The controller could look like this then

public class JavascriptController : Controller
{
    public ActionResult GetConstants()
    {
        return Content(JavascriptConstantsHelper.GetConstantsJavascriptFile(), "application/javascript");
    }
}

The script tag would then look something like this

<script src="/Javascript/GetConstants"></script>
Josh Russo
  • 3,080
  • 2
  • 41
  • 62
  • The constant that I need is the url of the mvc rest api server, which is not this project but another one. However, this angular project does happen to be a .Net MVC project, which right now just has static content (js/css/html). I do not know how to wire your answer up. – toddmo Oct 01 '15 at 15:51
  • I added a controller example. You would then reference the controller path in a – Josh Russo Oct 01 '15 at 15:56
  • One of the keys to this is to capture the module reference in a property of the `window` object. `window.myModule = window.angular.module('myModule', []);` Then make sure your app creation is included prior to the script tag in my example. – Josh Russo Oct 01 '15 at 16:13
  • For what you are trying to do in your initial question, the `GetConstantsJavascriptFile()` method would handle whatever values you are trying to retrieve with the `$http.get('web.config')` call. You would need to do this for any constants that require information from some source on the server – Josh Russo Oct 01 '15 at 16:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91117/discussion-between-josh-russo-and-toddmo). – Josh Russo Oct 01 '15 at 16:20
  • @toddmo If could mark my answer as correct for the way you were initially attempting to solve it, that would be awesome :o) – Josh Russo Oct 01 '15 at 16:43
  • Unfortunately this ended up being overkill for one setting. See my answer. It's a good solution in some cases though, I'm sure. – toddmo Oct 02 '15 at 21:49
0

For posterity sake, here's what I tried first, using Russo's answer as a guide.

However, it added 172 files and 19 MB to the build, so I decided on the other answer. This would not be so bad if I was going to add extensive asp.net server side functionality to the app. But, incrementally, for one setting, it was overkill.

web.config

  <appSettings>
    <add key="RestApiUrl" value="http://localhost/MyWebApiServer/api/"/>
  </appSettings>

index.html

<script src="api/settings"></script>

Controllers/SettingsController.cs

using Microsoft.AspNet.Mvc;
using System.Configuration;
using Newtonsoft.Json.Linq;

namespace MyWebSite
{
  [Route("api/[controller]")]
  public class SettingsController : Controller
  {
    // GET: api/settings
    [HttpGet]
    public ActionResult Get()
    {
      var jObject = new JObject();
      foreach (string key in ConfigurationManager.AppSettings)
        jObject.Add(key, ConfigurationManager.AppSettings[key]);
      return Content(
        string.Format(@"'use strict'; angular.module('myApp').constant('appSettings', {0});", 
                      jObject), 
        "application/javascript");
    }
  }
}

api.js (which WAS my existing constant for api constants. Now it's a factory)

'use strict';

angular.module('myApp').factory('api', 
  ["appSettings",
    function (appSettings) {
      return {
        URL: appSettings.RestApiUrl,
        /* other settings */
      }
    }
  ]
);
toddmo
  • 20,682
  • 14
  • 97
  • 107