Ember计算属性取决于服务属性不更新

时间:2016-11-26 05:16:12

标签: ember.js coffeescript

在我的Ember 2.8应用程序中,我正在服务中建立一个Websocket连接。用户登录时连接URL会更改(然后将用户身份验证令牌包含为查询参数)。

当前的用户服务很简单:

CurrentUserService = Ember.Service.extend(
  name: "current-user"

  user: null

  load: ->
    // Do some stuff
    @set("user", user)
 )

它完全按预期工作,我用它来显示页面上的当前用户用户名(以及其他内容)。

在Websocket服务中,我所做的就是创建一个计算属性,具体取决于currentUser.user,它设置连接(取决于用户是否登录):

ActionCableService = Ember.Service.extend(
  name: "action-cable"

  cable: service()
  currentUser: service()

  testObs: Ember.observer("currentUser", ->
    console.log "currentUser changed, #{ @get("currentUser.user") }"
  )

  consumer: Ember.computed("currentUser.user", ->
     consumerUrl = "ws://localhost:10000/cable"

    if @get("currentUser").user?
      consumerUrl += "?token=#{ @get("currentUser.user.authToken") }"

    console.log(consumerUrl)
    return @get("cable").createConsumer(consumerUrl)
  ) 
)

问题是,消费者财产永远不会得到更新。它在页面加载时设置一次,当currentUser服务的用户属性发生更改时,consumer不会更新,我的测试观察者也不会更新。

当我刷新页面时,有时会使用登录的consumerUrl,有时则不会 我猜测有时候会话恢复首先发生,有时行动电缆服务首先发生。

首先加载动作有线电视服务时,我期望发生的是:

  1. 操作有线服务已加载,尚未设置当前用户,连接到公共websocket
  2. 处理从会话数据触发恢复用户的逻辑,设置currentUser.user(发生这种情况,我可以在我的页面上看到用户名)
  3. consumer计算属性会通知currentUser.user更改并连接到私有consumerUrl(不会发生)
  4. 我可以很容易地以不依赖于计算属性的方式解决这个问题,但我想知道这里出了什么问题。

2 个答案:

答案 0 :(得分:2)

Computed properties, by default, observe any changes made to the properties they depend on, and are dynamically updated when they're called.

除非您正在调用或调用该计算属性,否则它将不会执行您想要的代码。

另一方面,

Observers在没有调用时做出反应,当他们正在观看的属性发生变化时。但它们经常被过度使用,并且由于它们的同步特性而容易引入错误。

您可以将观察者和计算属性重构为直接调用的辅助函数。这使得它们也更容易进行单元测试。

控制器中,您可以处理登录的初始操作,如下所示:

currentUser: Ember.inject.service(),

actions: {
  login() {
    this.auth({ username: 'Mary' });
  },
},

auth(data) {
  // Send data to server for authentication...

  // ...upon response, handle the following within the promise's `then`
  // method, failures caught within `catch`, etc. But for purposes of 
  // demonstration, just mocking this for now...
  const response = { username: 'Mary', authToken: 'xyz', };
  this.get('currentUser').setConsumer(response);
},

当前用户服务可以设置它的属性,并在action-cable服务上调用辅助函数:

actionCable: Ember.inject.service(),

authToken: null,
username: null,

setConsumer(response) {
  this.set('authToken', response.authToken);
  this.set('username', response.username);
  this.get('actionCable').setConsumer();
},

操作有线服务currentService读取属性,设置consumerUrl,并调用电缆服务来创建消费者:< / p>

cable: Ember.inject.service(),
currentUser: Ember.inject.service(),

setConsumer() {
  var consumerUrl = "ws://localhost:10000/cable";

  if (this.get("currentUser.username") !== null) {
    consumerUrl += "?token=" + (this.get("currentUser.authToken"));
  }

  console.log("ACTION CABLE SERVICE, Consumer URL: ", consumerUrl);
  this.get("cable").createConsumer(consumerUrl);
}

我创建了一个Ember Twiddle来演示。

答案 1 :(得分:1)

另一种方法是在服务中发出event,然后在init方法中订阅该事件,并设置计算属性的依赖键的值,以强制重新计算/更新它。 / p>