Wie konfiguriere ich verschiedene Umgebungen in Angular.js?

220

Wie verwalten Sie Konfigurationsvariablen / -konstanten für verschiedene Umgebungen?

Dies könnte ein Beispiel sein:

Meine Rest-API ist auf erreichbar localhost:7080/myapi/, aber mein Freund, der unter Git-Versionskontrolle mit demselben Code arbeitet, hat die API auf seinem Tomcat bereitgestellt localhost:8099/hisapi/.

Angenommen, wir haben so etwas:

angular
    .module('app', ['ngResource'])

    .constant('API_END_POINT','<local_end_point>')

    .factory('User', function($resource, API_END_POINT) {
        return $resource(API_END_POINT + 'user');
    });

Wie füge ich je nach Umgebung dynamisch den korrekten Wert des API-Endpunkts ein?

In PHP mache ich solche config.username.xmlDinge normalerweise mit einer Datei, indem ich die Basiskonfigurationsdatei (config.xml) mit der lokalen Umgebungskonfigurationsdatei zusammenführe, die anhand des Namens des Benutzers erkannt wird. Aber ich weiß nicht, wie ich so etwas in JavaScript verwalten soll?

rbarilani
quelle

Antworten:

209

Ich bin etwas spät dran, aber wenn Sie Grunt verwenden, hatte ich großen Erfolg damit grunt-ng-constant.

Der Konfigurationsabschnitt für ngconstantin meinem Gruntfile.jssieht aus wie

ngconstant: {
  options: {
    name: 'config',
    wrap: '"use strict";\n\n{%= __ngModule %}',
    space: '  '
  },
  development: {
    options: {
      dest: '<%= yeoman.app %>/scripts/config.js'
    },
    constants: {
      ENV: 'development'
    }
  },
  production: {
    options: {
      dest: '<%= yeoman.dist %>/scripts/config.js'
    },
    constants: {
      ENV: 'production'
    }
  }
}

Die Aufgaben, die verwendet werden, ngconstantsehen so aus

grunt.registerTask('server', function (target) {
  if (target === 'dist') {
    return grunt.task.run([
      'build',
      'open',
      'connect:dist:keepalive'
    ]);
  }

  grunt.task.run([
    'clean:server',
    'ngconstant:development',
    'concurrent:server',
    'connect:livereload',
    'open',
    'watch'
  ]);
});

grunt.registerTask('build', [
  'clean:dist',
  'ngconstant:production',
  'useminPrepare',
  'concurrent:dist',
  'concat',
  'copy',
  'cdnify',
  'ngmin',
  'cssmin',
  'uglify',
  'rev',
  'usemin'
]);

Wenn Sie also ausführen, grunt serverwird eine config.jsDatei generiert app/scripts/, die so aussieht

"use strict";
angular.module("config", []).constant("ENV", "development");

Schließlich erkläre ich die Abhängigkeit von den Modulen, die sie benötigen:

// the 'config' dependency is generated via grunt
var app = angular.module('myApp', [ 'config' ]);

Jetzt können meine Konstanten bei Bedarf abhängig injiziert werden. Z.B,

app.controller('MyController', ['ENV', function( ENV ) {
  if( ENV === 'production' ) {
    ...
  }
}]);
André Dion
quelle
10
Anstatt setzen 'ngconstant:development'in 'serve'- wenn Sie es in config Uhr setzen unter 'gruntfile'so tasks: ['ngconstant:development']- Sie Neustart nicht benötigt , grunt servewenn Sie die Entwicklung Variablen im gruntfile aktualisieren.
verbrachte den
10
Anstatt Ihre Konstanten in die Datei gruntfile.js einzufügen, können Sie separate Dateien wie diese package: grunt.file.readJSON('development.json')
einfügen
3
Es gibt eine aktualisierte Syntax für Gruntfile.js in der Version 0.5 der grunt-ng-Konstante: github.com/werk85/grunt-ng-constant/issues/31 . Tolle Antwort, danke!
Pherris
10
Für diejenigen, die Schluck verwenden, gibt es Schluck-Ng-Konstante .
Dheeraj Vepakomma
4
Ich habe festgestellt, dass es auch erforderlich ist, die Datei scripts / config.js in den Winkel aufzunehmen, um das Modul zu finden, wie folgt: <script src = "scripts / config.js"> </ script>
Toni Gamez
75

Eine coole Lösung könnte darin bestehen, alle umgebungsspezifischen Werte in ein separates Winkelmodul zu unterteilen, von dem alle anderen Module abhängen:

angular.module('configuration', [])
       .constant('API_END_POINT','123456')
       .constant('HOST','localhost');

Dann können Ihre Module, die diese Einträge benötigen, eine Abhängigkeit davon deklarieren:

angular.module('services',['configuration'])
       .factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
           return $resource(API_END_POINT + 'user');
       });

Jetzt könnten Sie über weitere coole Sachen nachdenken:

Das Modul, das die Konfiguration enthält, kann in configuration.js unterteilt werden, die auf Ihrer Seite enthalten sein werden.

Dieses Skript kann von jedem von Ihnen einfach bearbeitet werden, solange Sie diese separate Datei nicht in git einchecken. Es ist jedoch einfacher, die Konfiguration nicht einzuchecken, wenn sie sich in einer separaten Datei befindet. Sie können es auch lokal verzweigen.

Wenn Sie nun ein Build-System wie ANT oder Maven haben, können Ihre weiteren Schritte darin bestehen, einige Platzhalter für die Werte API_END_POINT zu implementieren, die während der Build-Zeit durch Ihre spezifischen Werte ersetzt werden.

Oder Sie haben Ihr configuration_a.jsund configuration_b.jsund entscheiden im Backend, welches Sie einbeziehen möchten.

kfis
quelle
30

Für Gulp- Benutzer ist die gulp-ng-Konstante auch in Kombination mit gulp-concat , event-stream und yargs nützlich .

var concat = require('gulp-concat'),
    es = require('event-stream'),
    gulp = require('gulp'),
    ngConstant = require('gulp-ng-constant'),
    argv = require('yargs').argv;

var enviroment = argv.env || 'development';

gulp.task('config', function () {
  var config = gulp.src('config/' + enviroment + '.json')
    .pipe(ngConstant({name: 'app.config'}));
  var scripts = gulp.src('js/*');
  return es.merge(config, scripts)
    .pipe(concat('app.js'))
    .pipe(gulp.dest('app/dist'))
    .on('error', function() { });
});

In meinem Konfigurationsordner habe ich folgende Dateien:

ls -l config
total 8
-rw-r--r--+ 1 .. ci.json
-rw-r--r--+ 1 .. development.json
-rw-r--r--+ 1 .. production.json

Dann können Sie laufen gulp config --env developmentund das schafft so etwas:

angular.module("app.config", [])
.constant("foo", "bar")
.constant("ngConstant", true);

Ich habe auch diese Spezifikation:

beforeEach(module('app'));

it('loads the config', inject(function(config) {
  expect(config).toBeTruthy();
}));
Rimian
quelle
Gibt es eine Möglichkeit, das Abhängigkeitsarray mit der Konstante gulp ng zu entfernen? Ich habe keine Abhängigkeit von meinen Konstanten wie Sie in diesem zB "ngAnimate". Wenn ich es nicht einbinde, erhalte ich ein leeres Abhängigkeitsarray als angle.module ("my.module.config", []), aber ich möchte die Ausgabe als angle.module ("my.module.config"). Ich sehe keine Option in der gulp ng-Konstante, aber ich sehe, dass Sie deps übergeben können: false im grunt ng-Konstantenpaket. Irgendeine Hilfe?
Arun Gopalpuri
17

Um dies zu erreichen, empfehle ich Ihnen, das AngularJS Environment Plugin zu verwenden: https://www.npmjs.com/package/angular-environment

Hier ist ein Beispiel:

angular.module('yourApp', ['environment']).
config(function(envServiceProvider) {
    // set the domains and variables for each environment 
    envServiceProvider.config({
        domains: {
            development: ['localhost', 'dev.local'],
            production: ['acme.com', 'acme.net', 'acme.org']
            // anotherStage: ['domain1', 'domain2'], 
            // anotherStage: ['domain1', 'domain2'] 
        },
        vars: {
            development: {
                apiUrl: '//localhost/api',
                staticUrl: '//localhost/static'
                // antoherCustomVar: 'lorem', 
                // antoherCustomVar: 'ipsum' 
            },
            production: {
                apiUrl: '//api.acme.com/v2',
                staticUrl: '//static.acme.com'
                // antoherCustomVar: 'lorem', 
                // antoherCustomVar: 'ipsum' 
            }
            // anotherStage: { 
            //  customVar: 'lorem', 
            //  customVar: 'ipsum' 
            // } 
        }
    });

    // run the environment check, so the comprobation is made 
    // before controllers and services are built 
    envServiceProvider.check();
});

Und dann können Sie die Variablen von Ihren Controllern wie folgt aufrufen:

envService.read('apiUrl');

Ich hoffe es hilft.

Juanpablob
quelle
1
Wie wechselt er zwischen Entwicklung und Produktion?
Mawg sagt, Monica
Hallo Juan Pablo oder @Mawg, wenn du es herausgefunden hast. Bevor ich eine Frage zu SO stelle / ein Problem zu Github anspreche; Wie erkennt man angular-environmentdie Umgebung? dh was müssen Sie auf Ihrem lokalen Computer / Webserver tun, damit dieser weiß, dass es sich um dev / prod handelt?
StevieP
Durch erneutes Lesen der Dokumente ... " envServiceProvider.check()... wird automatisch die entsprechende Umgebung basierend auf bestimmten Domänen festgelegt". Ich gehe davon aus, dass es die aktuelle Domain erkennt und die Umgebung entsprechend einstellt - Zeit, sie zu testen!
StevieP
13

Sie können verwenden, lvh.me:9000um auf Ihre AngularJS-App zuzugreifen (zeigt lvh.menur auf 127.0.0.1) und dann einen anderen Endpunkt anzugeben, wenn lvh.mees sich um den Host handelt:

app.service("Configuration", function() {
  if (window.location.host.match(/lvh\.me/)) {
    return this.API = 'http://localhost\\:7080/myapi/';
  } else {
    return this.API = 'http://localhost\\:8099/hisapi/';
  }
});

Fügen Sie dann den Konfigurationsdienst ein und verwenden Configuration.APISie ihn überall dort, wo Sie auf die API zugreifen müssen:

$resource(Configuration.API + '/endpoint/:id', {
  id: '@id'
});

Ein bisschen klobig, funktioniert aber gut für mich, wenn auch in einer etwas anderen Situation (API-Endpunkte unterscheiden sich in Produktion und Entwicklung).

Jure Triglav
quelle
1
deshalb denke ich oft, dass die Leute die Dinge überkompliziert haben. Die einfache Verwendung von window.location.hostwar für mich mehr als ausreichend.
Joseym
7

Wir könnten auch so etwas machen.

(function(){
    'use strict';

    angular.module('app').service('env', function env() {

        var _environments = {
            local: {
                host: 'localhost:3000',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            dev: {
                host: 'dev.com',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            test: {
                host: 'test.com',
                config: {
                    apiroot: 'http://localhost:3000'
                }
            },
            stage: {
                host: 'stage.com',
                config: {
                apiroot: 'staging'
                }
            },
            prod: {
                host: 'production.com',
                config: {
                    apiroot: 'production'
                }
            }
        },
        _environment;

        return {
            getEnvironment: function(){
                var host = window.location.host;
                if(_environment){
                    return _environment;
                }

                for(var environment in _environments){
                    if(typeof _environments[environment].host && _environments[environment].host == host){
                        _environment = environment;
                        return _environment;
                    }
                }

                return null;
            },
            get: function(property){
                return _environments[this.getEnvironment()].config[property];
            }
        }

    });

})();

Und in Ihrem controller/servicekönnen wir die Abhängigkeit einfügen und die get-Methode mit der Eigenschaft aufrufen, auf die zugegriffen werden soll.

(function() {
    'use strict';

    angular.module('app').service('apiService', apiService);

    apiService.$inject = ['configurations', '$q', '$http', 'env'];

    function apiService(config, $q, $http, env) {

        var service = {};
        /* **********APIs **************** */
        service.get = function() {
            return $http.get(env.get('apiroot') + '/api/yourservice');
        };

        return service;
    }

})();

$http.get(env.get('apiroot') würde die URL basierend auf der Host-Umgebung zurückgeben.

Thalaivar
quelle
5

Gute Frage!

Eine Lösung könnte darin bestehen, die Datei config.xml weiterhin zu verwenden und API-Endpunktinformationen aus dem Backend für Ihr generiertes HTML bereitzustellen, wie folgt (Beispiel in PHP):

<script type="text/javascript">
angular.module('YourApp').constant('API_END_POINT', '<?php echo $apiEndPointFromBackend; ?>');
</script>

Vielleicht keine schöne Lösung, aber es würde funktionieren.

Eine andere Lösung könnte darin bestehen, den API_END_POINTkonstanten Wert so zu halten , wie er in der Produktion sein sollte, und nur Ihre Hosts-Datei so zu ändern, dass diese URL stattdessen auf Ihre lokale API verweist.

Oder vielleicht eine Lösung localStoragefür Overrides wie diese:

.factory('User',['$resource','API_END_POINT'],function($resource,API_END_POINT){
   var myApi = localStorage.get('myLocalApiOverride');
   return $resource((myApi || API_END_POINT) + 'user');
});
Joakimbeng
quelle
Hallo Joakimbeng, ich habe die Lösung geschrieben, die ich in PHP verwende, um den Punkt zu erklären. Wir versuchen, einen reinen Javascript-Client mit einem reinen RESTful-Java-Backend zu codieren, daher ist der PHP / JS-Mix nicht mein Fall, und auch wenn ich in PHP schreibe, versuche ich immer, PHP und JS nicht gemischt zu halten. aber danke für die antwort. Ich denke, die @ kfis-Antwortlösung könnte funktionieren: Eine Datei configuration.js, die nicht der Versionskontrolle unterliegt und ein Konfigurationsmodul enthält. Mit diesem Ansatz kann ich zu Testzwecken auch ein anderes Konfigurationsmodul injizieren / laden, falls dies erforderlich ist. Danke Leute.
Rbarilani
@ hal9087 Ich stimme dem Teil zum Mischen von Sprachen voll und ganz zu, er sollte unbedingt vermieden werden :) Ich mag auch die Lösung von configuration.js, ich werde sie im Hinterkopf behalten, wenn ich etwas Ähnliches brauche!
Joakimbeng
4

Sehr spät zum Thread, aber eine Technik, die ich vor Angular verwendet habe, besteht darin, JSON und die Flexibilität von JS zu nutzen, um Sammlungsschlüssel dynamisch zu referenzieren und unveräußerliche Fakten der Umgebung (Hostservername, aktuelle Browsersprache) zu verwenden usw.) als Eingaben zur selektiven Unterscheidung / Bevorzugung von Schlüsselnamen mit Suffix innerhalb einer JSON-Datenstruktur.

Dies bietet nicht nur einen Bereitstellungsumgebungskontext (pro OP), sondern einen beliebigen Kontext (z. B. Sprache), um i18n oder eine andere Varianz bereitzustellen, die gleichzeitig und (idealerweise) innerhalb eines einzelnen Konfigurationsmanifests ohne Duplizierung und lesbar offensichtlich ist.

IN ÜBER 10 LINIEN VANILLA JS

Übermäßig vereinfachtes, aber klassisches Beispiel: Eine API-Endpunkt-Basis-URL in einer JSON-formatierten Eigenschaftendatei, die je nach Umgebung variiert, wobei (Host) der Host-Server ebenfalls variiert:

    ...
    'svcs': {
        'VER': '2.3',
        'API@localhost': 'http://localhost:9090/',
        '[email protected]': 'https://www.uat.productionwebsite.com:9090/res/',
        '[email protected]': 'https://www.productionwebsite.com:9090/api/res/'
    },
    ...

Ein Schlüssel zur Unterscheidungsfunktion ist einfach der Server-Hostname in der Anforderung.

Dies kann natürlich mit einem zusätzlichen Schlüssel kombiniert werden, der auf den Spracheinstellungen des Benutzers basiert:

    ...
    'app': {
        'NAME': 'Ferry Reservations',
        'NAME@fr': 'Réservations de ferry',
        'NAME@de': 'Fähren Reservierungen'
    },
    ...

Der Umfang der Unterscheidung / Präferenz kann auf einzelne Schlüssel (wie oben) beschränkt werden, wobei der "Basis" -Schlüssel nur überschrieben wird, wenn ein passender Schlüssel + Suffix für die Eingaben in die Funktion vorhanden ist - oder eine gesamte Struktur und diese Struktur selbst rekursiv analysiert für übereinstimmende Diskriminierungs- / Präferenzsuffixe:

    'help': {
        'BLURB': 'This pre-production environment is not supported. Contact Development Team with questions.',
        'PHONE': '808-867-5309',
        'EMAIL': '[email protected]'
    },
    '[email protected]': {
        'BLURB': 'Please contact Customer Service Center',
        'BLURB@fr': 'S\'il vous plaît communiquer avec notre Centre de service à la clientèle',
        'BLURB@de': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
        'PHONE': '1-800-CUS-TOMR',
        'EMAIL': '[email protected]'
    },

Wenn also ein besuchender Benutzer der Produktionswebsite die Einstellung für die deutsche ( De- ) Sprache hat, wird die obige Konfiguration wie folgt zusammengefasst:

    'help': {
        'BLURB': 'Bitte kontaktieren Sie unseren Kundendienst!!1!',
        'PHONE': '1-800-CUS-TOMR',
        'EMAIL': '[email protected]'
    },

Wie sieht eine solche magische Präferenz- / Diskriminierungs-JSON-Umschreibungsfunktion aus? Nicht viel:

// prefer(object,suffix|[suffixes]) by/par/durch storsoc
// prefer({ a: 'apple', a@env: 'banana', b: 'carrot' },'env') -> { a: 'banana', b: 'carrot' }
function prefer(o,sufs) {
    for (var key in o) {
        if (!o.hasOwnProperty(key)) continue; // skip non-instance props
        if(key.split('@')[1]) { // suffixed!
            // replace root prop with the suffixed prop if among prefs
            if(o[key] && sufs.indexOf(key.split('@')[1]) > -1) o[key.split('@')[0]] = JSON.parse(JSON.stringify(o[key]));

            // and nuke the suffixed prop to tidy up
            delete o[key];

            // continue with root key ...
            key = key.split('@')[0];
        }

        // ... in case it's a collection itself, recurse it!
        if(o[key] && typeof o[key] === 'object') prefer(o[key],sufs);

    };
};

In unseren Implementierungen, die Angular- und Pre-Angular-Websites enthalten, booten wir die Konfiguration einfach weit vor anderen Ressourcenaufrufen, indem wir den JSON in einen selbstausführenden JS-Abschluss einfügen, einschließlich der Funktion prepare (), und grundlegende Eigenschaften von Hostname und einspeisen Sprachcode (und akzeptiert alle zusätzlichen beliebigen Suffixe, die Sie möglicherweise benötigen):

(function(prefs){ var props = {
    'svcs': {
        'VER': '2.3',
        'API@localhost': 'http://localhost:9090/',
        '[email protected]': 'https://www.uat.productionwebsite.com:9090/res/',
        '[email protected]': 'https://www.productionwebsite.com:9090/api/res/'
    },
    ...
    /* yadda yadda moar JSON und bisque */

    function prefer(o,sufs) {
        // body of prefer function, broken for e.g.
    };

    // convert string and comma-separated-string to array .. and process it
    prefs = [].concat( ( prefs.split ? prefs.split(',') : prefs ) || []);
    prefer(props,prefs);
    window.app_props = JSON.parse(JSON.stringify(props));
})([location.hostname, ((window.navigator.userLanguage || window.navigator.language).split('-')[0])  ] );

Eine Pre-Angular-Site hätte jetzt ein reduziertes Fenster (keine @ Suffix-Schlüssel) window.app_props , auf das verwiesen werden kann .

Eine Angular-Site kopiert als Bootstrap / Init-Schritt einfach das Dead-Drop-Requisitenobjekt in $ rootScope und zerstört es (optional) aus dem globalen Bereich / Fensterbereich

app.constant('props',angular.copy(window.app_props || {})).run( function ($rootScope,props) { $rootScope.props = props; delete window.app_props;} );

anschließend in Steuerungen einzuspritzen:

app.controller('CtrlApp',function($log,props){ ... } );

oder von Bindungen in Ansichten verwiesen:

<span>{{ props.help.blurb }} {{ props.help.email }}</span>

Vorsichtsmaßnahmen? Das @ -Zeichen ist keine gültige JS / JSON-Variablen- / Schlüsselbenennung, wird jedoch bisher akzeptiert. Wenn dies ein Deal-Breaker ist, ersetzen Sie jede Konvention, die Sie mögen, wie "__" (doppelter Unterstrich), solange Sie sich daran halten.

Die Technik kann serverseitig angewendet, auf Java oder C # portiert werden, aber Ihre Effizienz / Kompaktheit kann variieren.

Alternativ könnte die Funktion / Konvention Teil Ihres Front-End-Kompilierungsskripts sein, sodass der vollständige JSON für alle Umgebungen und alle Sprachen niemals über das Netzwerk übertragen wird.

AKTUALISIEREN

Wir haben die Verwendung dieser Technik weiterentwickelt, um mehrere Suffixe für einen Schlüssel zuzulassen, um nicht gezwungen zu werden, Sammlungen zu verwenden (Sie können dies immer noch tun, so tief Sie möchten) und um die Reihenfolge der bevorzugten Suffixe einzuhalten.

Beispiel (siehe auch jsFiddle ):

var o = { 'a':'apple', 'a@dev':'apple-dev', 'a@fr':'pomme',
          'b':'banana', 'b@fr':'banane', 'b@dev&fr':'banane-dev',
          'c':{ 'o':'c-dot-oh', 'o@fr':'c-point-oh' }, 'c@dev': { 'o':'c-dot-oh-dev', 'o@fr':'c-point-oh-dev' } };

/*1*/ prefer(o,'dev');        // { a:'apple-dev', b:'banana',     c:{o:'c-dot-oh-dev'}   }
/*2*/ prefer(o,'fr');         // { a:'pomme',     b:'banane',     c:{o:'c-point-oh'}     }
/*3*/ prefer(o,'dev,fr');     // { a:'apple-dev', b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*4*/ prefer(o,['fr','dev']); // { a:'pomme',     b:'banane-dev', c:{o:'c-point-oh-dev'} }
/*5*/ prefer(o);              // { a:'apple',     b:'banana',     c:{o:'c-dot-oh'}       }

1/2 (Grundverwendung) bevorzugt '@dev'-Schlüssel, verwirft alle anderen Suffix-Schlüssel

3 bevorzugt '@dev' gegenüber '@fr', bevorzugt '@ dev & fr' gegenüber allen anderen

4 (wie 3, bevorzugt jedoch '@fr' gegenüber '@dev')

5 keine bevorzugten Suffixe, löscht ALLE Suffixeigenschaften

Dies wird erreicht, indem jede Eigenschaft mit Suffix bewertet wird und der Wert einer Eigenschaft mit Suffix auf die Eigenschaft ohne Suffix angehoben wird, wenn über die Eigenschaften iteriert wird und ein höher bewertetes Suffix gefunden wird.

Einige Effizienzvorteile in dieser Version, einschließlich der Beseitigung der Abhängigkeit von JSON für das Deep-Copy und der rekursiven Wiederkehr in Objekte, die die Bewertungsrunde in ihrer Tiefe überstehen:

function prefer(obj,suf) {
    function pr(o,s) {
        for (var p in o) {
            if (!o.hasOwnProperty(p) || !p.split('@')[1] || p.split('@@')[1] ) continue; // ignore: proto-prop OR not-suffixed OR temp prop score
            var b = p.split('@')[0]; // base prop name
            if(!!!o['@@'+b]) o['@@'+b] = 0; // +score placeholder
            var ps = p.split('@')[1].split('&'); // array of property suffixes
            var sc = 0; var v = 0; // reset (running)score and value
            while(ps.length) {
                // suffix value: index(of found suffix in prefs)^10
                v = Math.floor(Math.pow(10,s.indexOf(ps.pop())));
                if(!v) { sc = 0; break; } // found suf NOT in prefs, zero score (delete later)
                sc += v;
            }
            if(sc > o['@@'+b]) { o['@@'+b] = sc; o[b] = o[p]; } // hi-score! promote to base prop
            delete o[p];
        }
        for (var p in o) if(p.split('@@')[1]) delete o[p]; // remove scores
        for (var p in o) if(typeof o[p] === 'object') pr(o[p],s); // recurse surviving objs
    }
    if( typeof obj !== 'object' ) return; // validate
    suf = ( (suf || suf === 0 ) && ( suf.length || suf === parseFloat(suf) ) ? suf.toString().split(',') : []); // array|string|number|comma-separated-string -> array-of-strings
    pr(obj,suf.reverse());
}
storsoc
quelle
-8

Haben Sie diese Frage und ihre Antwort gesehen?

Sie können einen global gültigen Wert für Ihre App wie folgt festlegen:

app.value('key', 'value');

und verwenden Sie es dann in Ihren Diensten. Sie können diesen Code in eine config.js-Datei verschieben und beim Laden der Seite oder in einem anderen geeigneten Moment ausführen.

Thalador
quelle
7
Könnte jemand bitte erklären, warum dies eine so schlechte Antwort ist? Es wurde massiv herabgestimmt, aber kein einziger Kommentar ...
aendrew
5
Das ist höllisch alt, aber wenn ich raten müsste, warum die Downvotes, weil es nicht das Problem umgebungsspezifischer Konfigurationen angeht, ist es nur ein Vorschlag, .value () zu verwenden, um einen globalen Wert in einer alten App festzulegen. Es wird nicht erwähnt, wie man dies abhängig von env oder irgendetwas entlang der ursprünglichen Fragenparameter verwenden würde.
Coblr