2016-03-22 4 views
95

Я хотел бы, чтобы некоторые переменные были доступны везде в Angular 2 на языке Typescript. Каков наилучший способ сделать это?Каков наилучший способ объявить глобальную переменную в Angular 2/Typcript

+2

Если это статические переменные, нет необходимости использовать службы. Просто добавьте переменную в некоторый файл, а затем импортируйте ее везде, где она вам нужна. –

+0

К сожалению, у Angular2 есть исключение во время выполнения, говоря «Uncaught ReferenceError: Настройки не определены». Класс «Настройки» с общедоступными статическими переменными установлен на экспорт и импортирован там, где он использовался. –

+0

Я знаю, что это сообщение устарело и что есть много действительных ответов. Но, как сказал Эрик. Если это простое значение, которое вы хотите объявить и имеете доступ к вашему приложению, вы можете создать класс и экспортировать класс со статическим свойством. Статические переменные связаны с классом, а не с экземпляром класса. Вы можете импортировать класс и сможете получить доступ к свойству из класса. –

ответ

129

Вот самое простое решение без Service ни Observer:

Поместите глобальные переменные в файле экспорт им.

// 
// ===== File globals.ts  
// 
'use strict'; 

export const sep='/'; 
export const version: string="22.2.2";  

Чтобы использовать глобалам в другом файле использовать import заявление: import * as myGlobals from './globals';

Пример:

// 
// ===== File heroes.component.ts  
// 
import {Component, OnInit} from 'angular2/core'; 
import {Router} from 'angular2/router'; 
import {HeroService} from './hero.service'; 
import {HeroDetailComponent} from './hero-detail.component'; 
import {Hero} from './hero'; 
import * as myGlobals from './globals'; //<==== this one 

export class HeroesComponent implements OnInit { 
    public heroes: Hero[]; 
    public selectedHero: Hero; 
    // 
    // 
    // Here we access the global var reference. 
    // 
    public helloString: string="hello " + myGlobals.sep + " there"; 

     ... 

     } 
    } 

Спасибо @ Эрик-Martinez

+0

Мне нравится этот подход :) –

+0

Я решаю свою проблему, используя это. спасибо ... –

+3

Получил ошибку в операторе импорта. пришлось использовать 'import * в качестве глобусов из« globals » –

24

Смотрите, например Angular 2 - Implementation of shared services

@Injectable() 
export class MyGlobals { 
    readonly myConfigValue:string = 'abc'; 
} 

@NgModule({ 
    providers: [MyGlobals], 
    ... 
}) 

class MyComponent { 
    constructor(private myGlobals:MyGlobals) { 
    console.log(myGlobals.myConfigValue); 
    } 
} 

или предоставляют индивидуальные значения

@NgModule({ 
    providers: [{provide: 'myConfigValue', useValue: 'abc'}], 
    ... 
}) 

class MyComponent { 
    constructor(@Inject('myConfigValue') private myConfigValue:string) { 
    console.log(myConfigValue); 
    } 
} 
+0

Поскольку Angular2 beta 7 (я думаю), вы не должны регистрировать свою службу непосредственно в корневом компоненте (aka bootstrap). Однако вы можете ввести туда определенного поставщика, если вы хотите переопределить что-то в своем приложении. – Mihai

+1

Не уверен, что вы имеете в виду. Конечно, вы можете зарегистрировать службу в 'bootstrap()'. 'bootstrap()' и корневой компонент - две разные вещи. Когда вы вызываете 'bootstrap (AppComponent, [MyService]), вы регистрируете службу в' boostrap() 'и' AppComponent' является корневым компонентом. В документах упоминается где-то, что предпочитают регистрировать поставщиков (сервис) в корневых компонентах 'провайдеры: ['MyService']', но я еще не нашел аргумента в пользу или против 'bootstrap()' или корневого компонента. –

+0

Вы можете найти свой аргумент в угловом разделе «Инъекция зависимостей» (https://angular.io/docs/ts/latest/guide/dependency-injection.html). Как они говорят, вы можете это сделать, но он ОТКРЫТ. Этот пользователь просит наилучшего способа сделать что-то явно, ваше решение не соответствует. То же самое касается @ThierryTemplier – Mihai

43

Общий сервис является лучшим подходом

export class SharedService { 
    globalVar:string; 
} 

Но вы должны быть очень осторожны, когда регистрируя его, чтобы иметь возможность поделитесь одним экземпляром для всего вашего приложения. Вам нужно определить его при регистрации приложения:

bootstrap(AppComponent, [SharedService]); 

но не определять его снова в пределах providers атрибутов компонентов:

@Component({ 
    (...) 
    providers: [ SharedService ], // No 
    (...) 
}) 

В противном случае новый экземпляр вашей службы будет создан для компонент и его подкомпоненты.

Вы можете посмотреть на этот вопрос о том, как зависимость инъекций и иерархические инжекторы работают в Angular2:

Вы можете заметить, что вы можете также определить Observable свойства в службе уведомлять части своей заявки при изменении глобальных свойств:

export class SharedService { 
    globalVar:string; 
    globalVarUpdate:Observable<string>; 
    globalVarObserver:Observer; 

    constructor() { 
    this.globalVarUpdate = Observable.create((observer:Observer) => { 
     this.globalVarObserver = observer; 
    }); 
    } 

    updateGlobalVar(newValue:string) { 
    this.globalVar = newValue; 
    this.globalVarObserver.next(this.globalVar); 
    } 
} 

Смотрите этот вопрос для более подробной информации:

+0

Кажется, что это разные. Кажется, @ Rat2000 считает, что наш ответ неверен. Обычно я оставляю это решение другим, кроме того, что он дает конкурирующие ответы, но если он убежден, что наши ответы неверны, я думаю, что это действительно так. В документах, на которые он ссылается в комментарии к моему ответу, упоминается, что он DISCOURAGED, но я не вижу недостатка, и аргументы в документах довольно слабы. Также довольно часто добавлять поставщиков к загрузке. Какова была бы цель этого аргумента. А как насчет 'HTTP_PROVIDERS' и тому подобное, должны ли они также не добавляться в' bootstrap() '? –

+2

Да, я просто прочитал аргумент и раздел в документе. Честно говоря, я действительно не понимаю, почему это обескуражено из документа. Является ли это способом определения логического разделения: то, что является специфичным для Angular2 (поставщики маршрутизации, поставщики http) при загрузке и специфическим для приложения в инжекторе компонента приложения. Тем не менее, у нас может быть только один вспомогательный инжектор (один из приложений) для корневого (определенный при загрузке). Я что-то пропустил? Более того, в документе, касающемся иерархических инжекторов, поставщики услуг определены внутри корневого инжектора ;-) –

+3

Единственный аргумент, который я вижу, заключается в том, что сохранение области как можно более узкой и использования корневого компонента по крайней мере теоретически немного уже, чем использование 'bootstrap() ', но на практике это не имеет значения. Я думаю, что перечисление их в 'boostrap()' делает код более понятным. У компонента есть поставщики, директивы, шаблон. Я нахожу это перегруженным без глобальных поставщиков, перечисленных там. Поэтому я предпочитаю 'bootstrap()'. –

4

Я не знаю, лучший способ , но самый простой способ, если вы хотите определить глобальную переменную внутри компонента, - использовать window variabl е писать так:

window.GlobalVariable = "what ever!"

вам не нужно, чтобы передать его для начальной загрузки или импортировать его в других местах, и это глобально доступное весь JS (не только угловые 2 компонентов).

+1

Я бы сказал, это худший путь. Использование статической переменной не сложнее, но не так уродливо ;-) –

+2

Я согласен, что это сложно справиться. Однако я закончил использовать их в разработке до тех пор, пока не найду то, что я хочу разместить в постановках. В статической переменной вам нужно импортировать их снова и снова везде, где вы хотите использовать, рядом был случай, когда я создавал свое представление на ходу с jquery в угловых компонентах - не было шаблона и чтобы добавлять события к созданной DOM, используя статические переменная - боль. –

+1

Плюс, это не статично, вы можете изменить значение везде! –

3

Мне нравится ответ @supercobra, но я хотел бы использовать константный ключевое слово, как в ES6 уже доступны:

// 
// ===== File globals.ts  
// 
'use strict'; 

export const sep='/'; 
export const version: string="22.2.2"; 
63

Я тоже люблю решение от @supercobra. Мне просто хотелось немного улучшить его. Если вы экспортируете объект, который содержит все константы, вы можете просто использовать es6 импорт модуль без использования требует.

Я также использовал Object.freeze, чтобы свойства стали истинными константами. Если вас интересует эта тема, вы можете прочитать это post.

// global.ts 

export const GlobalVariable = Object.freeze({ 
    BASE_API_URL: 'http://example.com/', 
    //... more of your variables 
}); 

Обратитесь к модулю с помощью импорта.

//anotherfile.ts that refers to global constants 
import { GlobalVariable } from './path/global'; 

export class HeroService { 
    private baseApiUrl = GlobalVariable.BASE_API_URL; 

    //... more code 
} 
+0

это лучшее решение, потому что (1) это самый простой с наименьшим количеством кода и (2) он не требует, чтобы вы ввели какую-либо услугу darn в каждый отдельный компонент или место, в которое вы хотите его использовать, и не вам необходимо зарегистрировать его в @NgModule. Я не могу из-за жизни понять, почему для этого нужно создать услугу «Угловая 2», но, возможно, есть что-то, что я пропускаю? На данный момент я использую это замечательное решение, но, пожалуйста, дайте мне знать, почему другие более сложные ответы здесь лучше? – FireDragon

+5

Ваш GlobalVariable не является переменной. Его константа. –

+0

@PriyaR LOL, да, вы правы. Я полагал, что главная цель этого вопроса состояла в том, чтобы иметь безопасный способ доступа к некоторым ценностям во всем мире, поэтому я импровизировал. В противном случае, не стесняйтесь изменять const в var, вы получаете переменную. –

3

Вот так я использую его:

global.ts

export var server: string = 'http://localhost:4200/'; 
export var var2 : number = 2; 
export var var3 : string = 'var3'; 

использовать его только импортировать так:

import {Injectable} from "@angular/core"; 
    import {Http, Headers, RequestOptions} from "@angular/http"; 
    import {Observable} from "rxjs/Rx"; 

    import * as glob from "../shared/global"; //<== HERE 

    @Injectable() 
    export class AuthService { 
      private AuhtorizationServer = glob.server 
     } 

Редакцией: падает на порядок "_" с префиксом, как рекомендовано.

+0

Не используйте «_» в качестве префикса для private properties.https: //github.com/Microsoft/TypeScript/wiki/Coding-guidelines – crh225

11

Создать глобал класс в приложения/globals.ts:

import { Injectable } from '@angular/core'; 

Injectable() 
export class Globals{ 
    VAR1 = 'value1'; 
    VAR2 = 'value2'; 
} 

В компоненте:

import { Globals } from './globals'; 

@Component({ 
    selector: 'my-app', 
    providers: [ Globals ], 
    template: `<h1>My Component {{globals.VAR1}}<h1/>` 
}) 
export class AppComponent { 
    constructor(private globals: Globals){ 
    } 
} 

Примечание: Вы можете добавить поставщик услуг Глобал непосредственно к модулю вместо компонент, и вам не нужно будет добавлять в качестве поставщика для каждого компонента в этом модуле.

@NgModule({ 
    imports: [...], 
    declarations: [...], 
    providers: [ Globals ], 
    bootstrap: [ AppComponent ] 
}) 
export class AppModule { 
} 
+0

Это лучший ответ, так как он предлагает более портативный подход, чем добавлять обслуживание каждого компонента в приложении. Спасибо! –

+2

Код работает. Но обратите внимание, что вводящий класс 'Globals' также добавляя его в' providers: [...] 'означает, что вы не можете изменить значение внутри одного компонента, а затем запросить обновленное значение во втором компоненте. Каждый раз, когда вы вводите «Глобалы», это новый экземпляр. Если вы хотите изменить это поведение, просто сделайте ** NOT ** добавьте 'Globals' в качестве поставщика. –

4

Я думаю, что лучший способ поделиться объект с глобальными переменными во всем приложении путем экспорта и импорта, где вы хотите.

Сначала создайте новый ts- файл, например globals.ts и объявить объект. Я дал ему Object тип, но вы также можете использовать any type or {}

export let globalVariables: Object = { 
version: '1.3.3.7', 
author: '0x1ad2', 
everything: 42 
}; 

После этого импорта он

import {globalVariables} from "path/to/your/globals.ts" 

и использовать его

console.log(globalVariables); 
7

ИМХО для Angular2 (v2.2.3), лучший способ - добавить сервисы, содержащие глобальную переменную, и вставить их в компоненты без тега providers внутри @Component аннотация. Таким образом, вы можете обмениваться информацией между компонентами.

Сервис образец, который владеет глобальную переменную:

import { Injectable } from '@angular/core' 

@Injectable() 
export class SomeSharedService { 
    public globalVar = ''; 
} 

Компонент образец, который обновления стоимости вашей глобальной переменной:

import { SomeSharedService } from '../services/index'; 

@Component({ 
    templateUrl: '...' 
}) 
export class UpdatingComponent { 

    constructor(private someSharedService: SomeSharedService) { } 

    updateValue() { 
    this.someSharedService.globalVar = 'updated value'; 
    } 
} 

компонент образец, который читает значение вашей глобальной переменной:

import { SomeSharedService } from '../services/index'; 

@Component({ 
    templateUrl: '...' 
}) 
export class ReadingComponent { 

    constructor(private someSharedService: SomeSharedService) { } 

    readValue() { 
    let valueReadOut = this.someSharedService.globalVar; 
    // do something with the value read out 
    } 
} 

Note that providers: [ SomeSharedService ] should not be added to your @Component annotation. By not adding this line injection will always give you the same instance of SomeSharedService . If you add the line a freshly created instance is injected.

+0

приятный описание bro! –

+0

Но без добавления линии провайдеров я получил ошибку, подобную этой: 'Unhandled Promise rejection: Нет провайдера для SomeSharedService' – Rocky

+0

Я вижу. Я должен добавить 'поставщиков: [SomeSharedService]' в файл родительского модуля. Благодарю. – Rocky

Смежные вопросы