0

I'm fairly new to Ember.

This is the code for my component:

import Ember from 'ember';

export default Ember.Component.extend({
  profiles: Ember.inject.service(),
  tagName: 'td',
  classNames: ['grey'],
  classNameBindings: ['unreadMessages'],
  unreadMessages: null,

onInit: function() {
    const id = this.get('conversation.id');
    return this.get('profiles').getMessages(id)
      .then(function(bool) {
        this.set('unreadMessage', bool);
      });
  }.on('init')
});

This throws:

TypeError: Cannot read property 'set' of undefined

So I can gather that I don't have the this context that I need to call this.set inside of the .then()

I need to assign the result of return this.get('profiles').getMessages(id) to the unreadMessages property in my component. So that I can use it for the classNameBinding.

Here is the method I'm calling from the service

  getMessages(id){
    return this.get('ajax').request('/messages?id=' + id)
    .then((obj) => {
      const unreadMessages = obj.messages.filter((e) => e.read === false);

      if (unreadMessages === []) {
         return false;
      } else {
         return true;
      }
    });
  }

I've only been able to access the boolean value that getMessages returns inside of its .then() and I am not able to call this.set() inside of the .then() I'm looking for a work around. I think I'm close and am struggling to due to my lack of experience with Ember.

getMessages makes a 'GET' request to my back end and filters through the messages to check if there are any that are unread and then returns true or false. The purpose of the classNameBinding is to notify the user of whether they have any unread messages for that thread. This is a very simple email style messaging app that I am building for practice.

Thanks!

Arlo Feirman
  • 95
  • 10
  • 1
    It's a normal js tweak, the scope is changed and you are not using arrow functions :) – Surya Purohit Jun 27 '17 at 11:51
  • *this* is not "context". It's a parameter of an execution context that is set by the call, use of bind or adopted from the containing execution context in arrow functions. – RobG Jun 27 '17 at 11:52
  • Instead of `on('init')`, I would encourage you to write it inside `init` method itself, that's good practice. – Ember Freak Jun 27 '17 at 11:59
  • You should also read [*How to access the correct `this` context inside a callback?*](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback) – RobG Jun 27 '17 at 21:04

1 Answers1

2

Change

onInit: function() {
    const id = this.get('conversation.id');
    return this.get('profiles').getMessages(id)
      .then(function(bool) {
        this.set('unreadMessage', bool);
      });
  }.on('init')
});

to

onInit: function() {
    const id = this.get('conversation.id');
    return this.get('profiles').getMessages(id)
      .then((bool) => {
        this.set('unreadMessage', bool);
      });
  }.on('init')
});

The thing here is, the scope changes when you write function(){} inside then and this won't refer to the component this. That's why in ES6 the concept of lexical this was introduced. This will retain the this. So use Arrow function instead and it'll work smoothly..

Surya Purohit
  • 1,090
  • 1
  • 9
  • 29
  • Good answer. Another trick I used (pre Babel) is to assign `this` to a variable (I prefer to name it `self`), then use `self` instead of `this`. Whenever you see "function" in JS, always remember "THIS is not what you might expect...". – Steve H. Jun 27 '17 at 19:33