Angular 2+ 的持久化用户设置






4.33/5 (5投票s)
介绍如何在 Angular 2+ 前端应用程序中处理持久化用户设置。
引言
Angular 2 是一个相对较新的框架,目前可用的在线帮助和代码片段较少。因此,共享的代码部分/模块对于帮助其他人处理这个出色的框架可能很有价值。在本文中,我介绍了一个用于在 Angular 2 应用程序中处理持久化用户设置的小组件和服务。设置服务包含处理设置的核心功能:存储、保存和检索设置,而设置组件保存并管理显示设置的视图,与用户交互并将用户输入传输到设置服务。要使用本教程,您需要知道如何创建 Angular 2+ 应用程序以及如何创建和连接组件和服务。
设置数据
我们设置项目的起点是定义用户设置的数据结构。用户设置通常是单选题的答案(通过单选按钮显示)。在我们的应用程序中,用户可以选择以英语或德语显示站点 {'language': ['English', 'German']},或者以摄氏度或华氏度显示温度。注意:多选题也是用户设置的可能类型(通过复选标记显示)。这些可以作为单选题设置的扩展来处理。为了简单起见,在本文中,我们仅处理单选题设置。
单选题设置最容易用 Javascript 对象字面量表示,其中键是设置的类型,值是该键的可能值的数组。生成的对象字面量包含用户可用的所有选项。该组件将通过访问器函数(getSettingsValues()
)使用这些 settingsValues
来填充视图;并且服务将使用设置对象字面量来检查允许值。服务和组件完全依赖于这个对象字面量,因此更改或添加设置不需要对代码进行任何其他更改,也不会破坏任何现有代码。
private static settingsValues: {} = { 'LANGUAGE': ['EN', 'DE', 'HU', 'RO'], 'FORECAST_PERIOD': ['FULL_DAY', 'DAYTIME'], 'WIND_SPEED': ['KNOTS', 'KMH', 'MPH', 'MS'], 'WIND_DIRECTION': ['ARROW', 'CARDINAL', 'DEGREE'], 'TEMPERATURE': ['C', 'F'], 'PRESSURE': ['HPA', 'MB', 'INCHES'], 'PRECIPITATION': ['MM3H', 'IN3H'], 'ALTITUDE': ['M', 'FT'], 'LAPSE_RATE': ['C100M', 'F1000FT'] }; public getSettingsValues() { return SettingsService.SettingsValues; }
填充视图
在 settings-component 中,我们存储键和键值对在两个对象中以构建视图。我们还将用户选择的当前设置存储在第三个对象中。需要 currentSettings
以在视图中显示当前值(通过 ngModel)。
private settingsKeys = Object.keys(this.settingsService.getSettingsValues()); private settingsValues = this.settingsService.getSettingsValues(); private currentSettings = {};
初始化组件时,我们用从 settings-service 检索到的当前用户设置的 {key: value} 对填充 currentSettings
initSettings() { for (const key of this.settingsKeys) { this.currentSettings[key] = this.settingService.getSetting(key); } } ngOnInit() { this.initSettings(); }
视图是根据 settingsKeys 和 settingsValues 生成的。我们有一个外部 ngFor
循环来在单选组中显示 settingsKeys
。注意:translate pipe 用于将键翻译成用户可读的选定语言文本。ngx-translate 用于翻译,但本文中未详细介绍。有一个内部 ngFor 循环,用于将可用值显示为每个设置键的单选按钮。
<form role="form"> <div class="form-group"> <div *ngFor="let key of settingsKeys"> <label>{{key|translate}}</label><br> <label *ngFor="let value of settingsValues[key]" class="radio-inline"> <input type="radio" (click)="saveSetting(key, value)" [(ngModel)]="currentSettings[key]" name="{{key}}" value="{{value}}"> {{value|translate}} </label> </div> </div> </form>
当用户单击单选按钮值时,它会触发函数 saveSetting(key, value)
,并将键和选定值作为参数传递。此函数反过来调用 settings-service 的 setSetting()
函数
saveSetting(key: string, value: string) { this.settingService.setSetting(key, value); }
连接服务
现在我们已经设置了视图,我们需要做的就是实现 settings-service 中的 getter 和 setter 函数。有三个公共函数:getSettingsValues()
、getSetting()
和 setSetting()
。为了实现这些函数,我们有许多不同的选项可用:我们可以将设置存储在本地对象中(非持久化),或者将它们持久化到 localStorage 或服务器。在本文中,我们选择使用 localStorage 在会话之间持久化设置。如果 localStorage
不可用,我们可以退回到将设置存储在 JSON 对象中,以便至少在会话中具有持久性。首先,我们实现将设置存储在对象中的代码
private settingsObject = {}; // store settings of a session if localStorage is not available private initSettingsObject() { // create settings object to store settings for session if localStorage is not available // settingsObject serves also as a fallback before the user sets any personal settings for (const key of Object.keys(SettingsService.forecastSettingsValues)) { this.settingsObject[key] = SettingsService.forecastSettingsValues[key][0]; } } constructor() { this.initSettingsObject(); }
我们终于到达了 settings-service 的公共函数:getSetting()
和 setSetting()
。首先,我们检查设置是否有效(getSetting()
的键和 setSetting()
的 {key: value} 对),然后从本地存储中检索设置或将其保存到本地存储或 settingsObject
(如果本地存储或本地存储中的设置不可用)。
public getSetting(key: string): string { if (!this.isValidKey(key)) { console.log('settings-service.getForecastSetting() - key is invalid: ' + key); return ''; } if ((typeof(Storage) !== 'undefined') && localStorage.getItem(key)) { return localStorage.getItem(key); } else { return this.settingsObject[key]; } } public setSetting(key: string, value: string) { if (!this.isValidSetting(key, value)) { console.log('settings-service: {' + key + ': ' + value + '} setting was incorrect'); return; } if ((typeof(Storage) !== 'undefined')) { localStorage.setItem(key, value); } else { this.settingsObject[key] = value; } }
settings-service 中还有两个辅助函数来检查键或 {key: value} 是否有效:isValidKey()
和 isValidSetting()
public isValidKey(key: string) { if (SettingsService.forecastSettingsValues.hasOwnProperty(key)) { return true; } else { return false; } } public isValidSetting(key: string, value: string) { if (SettingsService.forecastSettingsValues.hasOwnProperty(key) && SettingsService.forecastSettingsValues[key].includes(value)) { return true; } else { return false; } }
结论
代码是健壮的,因为更改设置不需要对代码或 html 进行任何更改。但是,代码中存在一个设计缺陷:当在应用程序的其他部分查询设置时,调用 settingsService.getSetting()
,代码必须知道键的字符串字面量(例如 'TEMPERATURE')。因此,如果更改了键,则使用此键的代码的其他部分将会中断。