What is the best way to set AngularJS $provide.con

2020-06-21 09:52发布

I have an AngularJS application with a .NET MVC/WebAPI backend. I have one MVC action that serves up my main HTML page that loads my AngularJS app. This MVC action loads several application settings from the Web.config as well as the database and returns them to the view as a model. I'm looking for a good way to set those MVC Model values as $provide.constant values in my AngularJS .config method.

MVC Controller method:

public ActionResult Index() {
    var model = new IndexViewModel {
        Uri1 = GetUri1(),
        Uri2 = GetUri2()
        //...etc
    };
    return View(model);
}

My MVC _Layout.cshtml:

@model IndexViewModel
<!doctype html>
<html data-ng-app='myApp'>
<head>
    @Styles.Render("~/content/css")
    <script type='text/javascript'>
        @if (Model != null)    //May be null on error page
        {
            <text>
                var modelExists = true;
                var uri1 = '@Model.Uri1';
                var uri2 = '@Model.Uri2';
            </text>
        }
        else
        {
            <text>
                var modelExists = false;
            </text>
        }
    </script>
</head>
<body>
    <!-- Body omitted -->
    @Scripts.Render("~/bundles/angular", "~/bundles/app") //Loads angular library and my application
</body>

app.js:

"use strict";
angular.module('myApp', [])
    .config(['$provide' '$window', function ($provide, $window) {
        if ($window.modelExists){
            $provide.constant('const_Uri1', $window.uri1);
            $provide.constant('const_URi2', $window.uri2);
        }            
    }]);

This is a vastly simplified version of my code but I think it illustrates my concern. Is there a better or standard way of doing this that I am overlooking? I don't like the code in my _Layout.cshtml because I have many more configuration values.

1条回答
太酷不给撩
2楼-- · 2020-06-21 10:17

If you have a bunch of config values and you don't mind an extra network call, one way to do this is to create an MVC view that returns the settings as an Angular constant...

using System.Web.Script.Serialization;

// ...

public ActionResult Settings(string angularModuleName = "myApp")
{
    var settings = new 
    {
        uri1 = GetUri1(),
        uri2 = GetUri1()
        // ...
    };

    var serializer = new JavaScriptSerializer();
    var json = serializer.Serialize(settings);

    var settingsVm = new SettingsViewModel
    {
        SettingsJson = json,
        AngularModuleName = angularModuleName
    };

    Response.ContentType = "text/javascript";
    return View(settingsVm);
}

In the Razor view...

@model MyApp.SettingsViewModel
@{
    Layout = null;
}

(function (app) {
    app.constant('settings', @Html.Raw(Model.SettingsJson));
})(angular.module('@Model.AngularModuleName'));

In the pages that need the files, just add a script tag to bring in the constants...

@Scripts.Render("~/bundles/angular", "~/bundles/app") //Loads angular library and my application
<script src="/home/settings?appname=foo"></scripts>

This will return the script...

(function (app) {
    app.constant('settings', {
        "uri1": "https://uri1",
        "uri2": "https://uri2"
    });
})(angular.module('foo'));

Now you can inject the settings service anywhere in your Angular code. Nothing is leaked into the global scope.

You can also use this technique to inject the settings directly into a particular HTML view, but I generally prefer to split it out so that it is included only when needed.

查看更多
登录 后发表回答