我有一个设置页面,用户可以在其中保存一些配置变量,例如用户名。用户还可以更改该页面上的用户名。但是,当我转到另一个组件(页面)并返回时,用户名不会被保存。
我还想在其他组件中显示用户名。我怎么做?有一个全局变量吗?
结构: - 应用程序 - app.ts(主要) - setting.ts - someOtherComponent.ts
答案 0 :(得分:33)
您需要的是维护变量状态的服务。然后,您可以将该服务注入任何组件以设置或获取该变量。
这是一个例子(/services/my.service.ts):
NOTE
You must apply cursor.skip() to the cursor before retrieving any documents from the database.
您可能希望将该服务放在应用程序引导功能的提供程序数组中(可能位于主应用程序组件文件中,也可能位于单独的文件中,具体取决于您的操作方式)。
在您的主应用文件(/app.ts)中:
import {Injectable} from "angular2/core";
@Injectable()
export class MyService {
private myValue;
constructor() {}
setValue(val) {
this.myValue = val;
}
getValue() {
return this.myValue ;
}
}
您不需要在数组中使用COMMON_DIRECTIVES和其他所有大写项目,但通常只包括这些项目,以便您不必在您编写的每个组件中配置它们。
然后你将从像这样的组件(/components/some-component.ts)中访问该服务:
import {MyService} from './services/my.service';
bootstrap(App, [MyService, COMMON_DIRECTIVES, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, HTTP_PROVIDERS]); // directives added here are available to all children
您可能还想添加到服务中,以便将值保存到某处(半)永久性,以便下次用户进入应用程序时可以访问它。
答案 1 :(得分:9)
这可能对您目前的情况有些过分,但如果您要将应用程序扩展到更大的应用程序,这可能会为您节省很多麻烦。也就是说,我相信Angular与Redux-like商店是一个非常强大的组合。我的建议是使用ngrx/store
模块。
受Redux启发的Angular应用程序的RxJS驱动状态管理
下面的代码应概述将ngrx/store
集成到应用程序中时需要遵循的所有步骤。为简洁起见,我省略了您可能拥有的任何现有代码以及您需要添加的所有导入。
安装模块
npm install --save ngrx/core ngrx/store
创建减速器
export const SETTINGS_UPDATE = 'SETTINGS_UPDATE';
const initialState = {
username: ''
};
export function settingsReducer(state: Object = initialState, action: Action) {
switch (action.type) {
case SETTINGS_UPDATE:
return Object.assign({}, state, action.payload);
default:
return state;
}
};
导入StoreModule
@NgModule({
imports: [
// your other imports
StoreModule.provideStore({
settings: settingsReducer
})
]
})
export class AppModule {
//
}
为设置缩减器创建界面
export interface SettingsStore {
username: string;
}
创建商店界面
export interface AppStore {
settings: SettingsStore;
}
创建设置服务
@Injectable()
export class SettingsService {
settings$: Observable<SettingsStore>;
constructor(private store: Store<AppStore>) {
this.settings$ = this.store.select('settings');
}
public update(payload) {
this.store.dispatch({ type: SETTINGS_UPDATE, payload });
}
}
设置组件控制器
@Component({
...
})
export class SettingsComponent implements OnInit {
settings$: Observable<SettingsStore>;
constructor(private settingsService: SettingsService) {
//
}
ngOnInit() {
this.settings$ = this.settingsService.settings$;
}
public updateUsername() {
this.settingsService.update({ username: 'newUsername' });
}
}
设置组件模板
<p *ngIf="(settings$ | async)?.username">
<strong>Username:</strong>
<span>{{ (settings$ | async)?.username }}</span>
</p>
<button (click)="updateUsername()">Update Username</button>
通过上面列出的设置,您可以将SettingsService
注入任何组件并在其模板中显示该值。
同样,您也可以使用store
从任何组件更新this.settingsService.update({ ... });
的值,并且更改将反映在使用该值的所有地方 - 无论是通过通过async
.subscribe()
管道或其他服务。
答案 2 :(得分:2)
您需要一项服务,以便您可以随时随地注入。:
@Injectable()
export class GlobalService{
private value;
constructor(){
}
public setValue(value){
this.value = value;
}
public getValue(){
return this.value;
}
}
您可以在所有模块中提供此服务,但您可能会获得多个实例。因此,我们将使服务成为单身人士。
@NgModule({
providers: [ /* DONT ADD THE SERVICE HERE */ ]
})
class GlobalModule {
static forRoot() {
return {
ngModule: GlobalModule,
providers: [ GlobalService ]
}
}
}
您应该只在forRoot
:
AppModule
方法
@NgModule({
imports: [GlobalModule.forRoot()]
})
class AppModule {}
答案 3 :(得分:2)
弗拉基米尔正确地提到了ngrx
。
我会使用Subject
/ BehaviourSubject
和Observable
到set
和get
我需要的状态(值)的服务。
我们在此讨论了Communication between multiple components with a service by using Observable and Subject in Angular 2如何在没有parent
- child
或child
- parent
关系和没有导入外部库作为ngrx
商店。
答案 4 :(得分:1)
我有同样的问题,大多数组件需要loggedInUser信息。 例如:用户名,首选语言,用户的首选时区等。
因此,一旦用户登录,我们可以执行以下操作:
如果所有信息都在JWT令牌或/我RESTful Api中,那么您可以在其中一个服务中解码令牌。
例如:user.service.ts
@Injectable()
export class UserService {
public username = new BehaviorSubject<string>('');
public preferredLanguage = new BehaviorSubject<string>('');
public preferredTimezone = new BehaviorSubject<string>('');
constructor(
private router: Router,
private jwtTokenService: JwtTokenService
) {
let token: string = localStorage.getItem('token'); // handled for page hard refresh event
if (token != null) {
this.decode(token);
}
}
private decode(token: string) {
let jwt: any = this.jwtTokenService.decodeToken(token);
this.username.next(jwt['sub']);
this.preferredLanguage.next(jwt['preferredLanguage']);
this.preferredTimezone.next(jwt['preferredTimezone']);
}
public setToken(token: any) {
localStorage.setItem('auth_token', token);
this.decode(token);
}
}
它拥有三个公共行为主题,无论是谁正在听这个变量,如果它是变化的话都会得到它。请检查rxjs编程风格。
现在只需要这个变量,只需从该组件订阅。
例如:NavComponent肯定需要用户名。因此代码将如下所示:
export class NavComponent implements OnInit {
public username: string;
constructor(
private userService: UserService,
private router: Router) {
}
ngOnInit() {
this.userService.username.subscribe(data => {
this.username = data;
});
}
}
因此,reactive programming为处理依赖变量提供了更好的解决方案。
如果页面是硬刷新,上面也解决了这个问题,因为我将值存储在localstorage中并在构造函数中获取它。
请注意:假设登录的用户数据来自JWT令牌,如果数据来自Restful Api,我们也可以使用相同的服务(UserHttpService)。例如:api / me