在开发Web应用程序时,用户交互的响应性是非常重要的。为了提高用户体验,常常需要在用户进行某些操作时提供即时的反馈。例如,当用户提交表单或删除记录时,显示一个加载提示,如“保存中...”或“删除中...”。本文将介绍如何在AngularJS中使用拦截器来实现这一功能。
背景:在与数据库等后端服务通信时,可能会存在延迟。为了让用户知道系统正在处理他们的请求,需要在用户执行操作时显示通知。例如,当用户尝试查看与某个联系人相关的所有记录时,会显示一个“加载中...”的通知。
实现这一功能的一种方法是将通知服务注入到所有的AngularJS服务中,然后根据操作显示通知,一旦Promise返回,就隐藏通知。这种方法在只有一页和几个操作的情况下是可行的,但如果需要在许多页面上重复这一过程,就会违反DRY(Don't Repeat Yourself)原则。
因此,更好的解决方案是使用AngularJS的拦截器来拦截请求/响应,并注入通知服务以显示通知。AngularJS的拦截器允许在请求执行之前和响应返回并显示给最终用户之后注入自定义代码。
以下是代码示例。将在另一篇文章中展示通知服务的实际实现。
使用代码:代码非常直观,但重要的部分是:
// 注册自定义Http拦截器到AngularJS
angular.module("CRM").config(["$httpProvider", ($httpProvider: any) => {
$httpProvider.interceptors.push(HttpInterceptor.Factory);
}]);
注入自定义通知服务到自定义拦截器:
static $inject = ["$injector", "$q"];
constructor($injector: ng.auto.IInjectorService, $q) {
this.$q = $q;
this.notificationService = $injector.get("CRM.Common.NotificationService");
this.$log = $injector.get("$log");
this.$injector = $injector;
}
使用自定义通知服务并解析HTTP方法:
public request = (config) => {
this.notificationService.blockUi(this.getMessageBasedOnHttpMethod(config.method));
return config;
};
module CRM.Config {
() => {
angular.module("CRM", ["toaster", "ngTasty", "ui.bootstrap", "darthwade.dwLoading"]);
angular.module("CRM").config(["$httpProvider", ($httpProvider: any) => {
$httpProvider.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
$httpProvider.interceptors.push(HttpInterceptor.Factory);
}]);
}();
}
export class HttpInterceptor {
private $q;
public notificationService: CRM.Common.INotificationService;
public $log: ng.ILogService;
public $injector: ng.auto.IInjectorService;
public responseError = (rejection) => {
this.notificationService.unblockUi();
if (rejection.data.message) {
this.notificationService.showError(rejection.data.message);
}
return this.$q.reject(rejection);
};
public response = (response) => {
if (this.$q.when(response)) {
this.notificationService.unblockUi();
return this.$q.when(response);
}
return response || this.$q.when(response);
}
public request = (config) => {
this.notificationService.blockUi(this.getMessageBasedOnHttpMethod(config.method));
return config;
};
private getMessageBasedOnHttpMethod(httpMethod: string): string {
var message = "";
switch (httpMethod.toLowerCase()) {
case "get":
message = "Loading...";
break;
case "post":
message = "Saving...";
break;
case "put":
message = "Updating...";
break;
case "delete":
message = "Deleting...";
break;
default:
message = "Please Wait...";
}
return message;
}
public requestError = (rejection) => {
this.$log.log("requestError", rejection);
this.notificationService.unblockUi();
if (rejection.data.message) {
this.notificationService.showError(rejection.data.message);
}
return this.$q.reject(rejection);
};
public static Factory($injector, $q: ng.IQService) {
HttpInterceptor.Factory.$inject = ["$injector", "$q"];
return new HttpInterceptor($injector, $q);
}
static $inject = ["$injector", "$q"];
constructor($injector: ng.auto.IInjectorService, $q) {
this.$q = $q;
this.notificationService = $injector.get("CRM.Common.NotificationService");
this.$log = $injector.get("$log");
this.$injector = $injector;
}
}