Service Property is Updated, Computed Property is Not


#1

I have a service where I change a prop ‘loggedIn’ from false to true. When I access the service’s prop through a computed property on my controller, I get the old value.
When I access the prop directly from the service, I see the new value.

The computed property on the controller only runs once – at app start. Why isn’t this the computed prop updated when the value it references in the service is updated?

Anyone have any clues as to what I am missing? I’m running Ember 3.1.3

Service:

// services/session
export default Service.extend({
    loggedIn: false,
    login() {
        this.set('loggedIn', true);
    },
    isLoggedIn() {
        return this.get('loggedIn');
    }
});

Controler:

export default Controller.extend({
    session: computed(function() {
        return getOwner(this).lookup('service:session');
     }),

    isLoggedIn: computed('session', function() {
        console.log(" isLogggedIn"); //  this is only called once (when app starts)
        let session = this.get('session');
        let isUserLoggedIn = session.isLoggedIn();
        return isUserLoggedIn;
    })
});

Route:

export default Route.extend({
    session: computed(function() {
       return getOwner(this).lookup('service:session');
    }),
    actions: {
       loginUser() {
           this.get('session').login();
       }
    }
});

Template:

<button class="button" {{action "loginUser"}}>Login</button>

{{!-- After user clicks "login" button, values are: --}}
<h2>{{isLoggedIn}}</h2> {{!-- false --}}
<h2>{{session.loggedIn}}</h2> {{!-- true --}}

#2

U need to observer the property not entire object. The object itself didn’t change.

computed('session.loggedIn', function() { ... })

#3

Got it. Thanks very much!


#4

I would recommend to refactor your code. There is no need for a isLoggedIn method on your service if it only returns a property. Controller and Route should use inject() provided by @ember/service package. isLoggedIn of Controller should use readOnly() macro provided by @ember/object/computed.


#5

Yes, using @jelhan’s suggestions it would look like this:

import { inject } from '@ember/service';
import { readOnly } from '@ember/object/computed' 
export default Controller.extend({
    session: inject(),
    isLoggedIn: readOnly('session.loggedIn')
});

#6

Thanks very much for the replies @heatbr @jelhan @ef4 I appreciate you helping a n00b get going with this stuff!