我试图重构一些AngularJS 1.5服务代码以利用类。
我的服务定义如下:
(() => {
"use strict";
class notification {
constructor($mdToast, $mdDialog, $state) {
/* injected members */
this.toast = $mdToast
this.dialog = $mdDialog
this.state = $state
/* properties */
this.transitioning = false
this.working = false
}
openHelp() {
this.showAlert({
"title": "Help",
"textContent": `Help is on the way!`,
"ok": "OK"
})
}
showAlert(options) {
if (angular.isString(options)) {
var text = angular.copy(options)
options = {}
options.textContent = text
options.title = " "
}
if (!options.ok) {
options.ok = "OK"
}
if (!options.clickOutsideToClose) {
options.clickOutsideToClose = true
}
if (!options.ariaLabel) {
options.ariaLabel = 'Alert'
}
if (!options.title) {
options.title = "Alert"
}
return this.dialog.show(this.dialog.alert(options))
}
showConfirm(options) {
if (angular.isString(options)) {
var text = angular.copy(options)
options = {}
options.textContent = text
options.title = " "
}
if (!options.ok) {
options.ok = "OK"
}
if (!options.cancel) {
options.cancel = "Cancel"
}
if (!options.clickOutsideToClose) {
options.clickOutsideToClose = false
}
if (!options.ariaLabel) {
options.ariaLabel = 'Confirm'
}
if (!options.title) {
options.title = "Confirm"
}
return this.dialog.show(this.dialog.confirm(options))
}
showToast(toastMessage, position) {
if (!position) { position = 'top' }
return this.toast.show(this.toast.simple()
.content(toastMessage)
.position(position)
.action('OK'))
}
showYesNo(options) {
options.ok = "Yes"
options.cancel = "No"
return this.showConfirm(options)
}
uc() {
return this.showAlert({
htmlContent: "<img src='img\\underconstruction.jpg'>",
ok: "OK",
title: "Under Construction"
})
}
}
angular.module('NOTIFICATION', []).service("notification", notification)
})()
该服务似乎创建得很好,但是,当我从组件的控制器中引用它时,它已被注入到服务方法内部“this”引用服务已注入的控制器而不是服务。在查看调试器中的控制器时,似乎我为服务定义的所有方法实际上都已添加到控制器中。
在控制器中,我基本上将一些控制器方法映射到服务的方法,如下所示:
function $onInit() {
Object.assign(ctrl, {
// Properties
title: "FTP Order Processing",
menuComponent: "appMenu",
reportsOn: false,
userName: "",
notification: notification,
// working: false,
// Methods
closeSideNav: closeSideNav,
menuHit: menuHit,
openHelp: notification.openHelp,
showConfirm: notification.showConfirm,
showSideNav: showSideNav,
showAlert: notification.showAlert,
showToast: notification.showToast,
showYesNo: notification.showYesNo,
toggleReports: toggleReports,
// uc: uc
})
Object.defineProperty(ctrl, "working", {
get: () => { return ctrl.notification.working },
set: (value) => { ctrl.notification.working = value }
})
}
因此,“this”指的是控制器。当我使用非基于类的服务时,它无关紧要,因为我使用引用该服务的变量引用了服务中的服务成员。
所以我想我的问题是,当这些方法映射到另一个对象时,如何从其方法中引用服务类的成员?
答案 0 :(得分:1)
这是我们为我们的类做的事情,ES6使用Angular 1.5 +:
import { decorator } from 'app/decorators';
export default class FooClass {
/* @ngInject */
constructor(Restangular) {
this._Restangular = Restangular;
}
@decorator
someMethod(argument_one) {
return argument_one.property;
}
}
所以它和你的一样,略有不同。为了以防万一,我留下了一个装饰器示例。
答案 1 :(得分:1)
这个问题与ES6类没有关系(它们只是ES5构造函数的语法糖),而是与JS有关。
将方法分配给其他对象时,如
foo.baz = bar.baz
foo.baz()
将foo
作为this
- 除非bar.baz
被绑定为bar.baz = bar.baz.bind(baz)
,或者是具有bar
的ES6箭头功能作为词汇this
。
将控制方法分配给控制器,这种方法不会很好,并且会导致错误的上下文。
这可以像
一样修复Object.assign(this, {
...
showAlert: notification.showAlert.bind(notification)
});
或
Object.assign(this, {
...
showAlert: (...args) => notification.showAlert(...args)
});
但好的方法是不要让服务方法失去他们的背景。
控制器应该只将服务实例分配为
this.notification = notification;
并访问控制器中的this.notification.openHelp()
或视图中的{{ $ctrl.notification.openHelp() }}
等方法。
否则最好使用类原型方法:
showAlert(options) {
return this.notification.showAlert(options);
}
由于它暴露了控制器原型上的方法,因此允许使用对于实例方法不可用的继承和测试方法(当控制器多次实例化时也更有效)。