1
votes

I'm working on porting an Ember.js app over to ember-cli.

My app is an augmented boardgame and, in it, I have an ember-states StateMachine subclass that manages actions that involve passing the game back and forth between two players.

In that subclass, I call reopen() in order to define a method that's bound to the currentState.name of the state machine:

PassManager.reopen({
  isPassing : function(){
    return this.get("currentState.name") == "pass";
  }.property("currentState.name")
});

See in context here: https://github.com/atduskgreg/SneakGame/blob/ember-cli-refactor/app/models/pass-manager.js#L49

I then call that function in an if-statement in my templates:

<h1>Player character assignments</h1>
{{#if PassManager.isPassing}}
  {{partial 'pass'}}
{{else}}
  <p>You are {{current-player-color}}.</p>
  <p><button {{action 'next'}}>Got it</button></p>
{{/if}}

https://github.com/atduskgreg/SneakGame/blob/ember-cli-refactor/app/templates/character-assignment.hbs#L2

When the PassManager is in the "pass" state this should return true and show the relevant partial and when it's false it should show the rest of the template seen here.

This worked fine before porting to ember-cli, though it did issue a deprecation warning related to this issue: http://emberjs.com/guides/deprecations/#toc_global-lookup-of-views

I've now ported the app to ember-cli and now PassManager.isPassing is no longer evaluated. It always returns false and console.log() statements placed inside it are never executed.

I'm new to working with ES6 modules and was wondering if I'm doing something wrong in how I export PassManager or if there's some more fundamental reason reopen() wouldn't work on an exported module. At the bottom of my pass-manager.js file, I've got:

export default PassManager;

And the PassManager is correctly found in the places I import it in my app. It's just this function defined using reopen() that's not called.

1

1 Answers

1
votes

PassManager is not a subclass of Ember.StateManager, but an instance of it, because you are using create and not extend. Reopen can be used with instances, but applies to the class the instance is of. Therefore, the order is different: the instance method overrides the class method. So the version of isPassing in your Ember.StateManager.create is overriding the one in your PassManager.reopen.

Try structuring your code like this:

import Ember from "ember";
import Game from "./game"

var PassManagerClass = Ember.StateManager.extend({
  reset : function(){
    console.log("PassManagerClass.reset()");
    this.set('players', this.get('gamePlayers'));
    this.set('playerIdx', 0);
    this.transitionTo("pass");
  },

  next : function(){
    if(this.get('currentState.name') == "pass"){
      this.transitionTo("act");
    } else {
      if(this.get('playerIdx') == Object.keys(this.get('gamePlayers')).length - 1){
        this.transitionTo("done");
      } else {
        this.transitionTo("pass");
      }
    }
  },

  isPassing : function(){
    console.log("here");
    return true;
  }.property()
});

PassManagerClass.reopen({
  isPassing : function(){
    console.log("isPassing: " + this.get("currentState.name"));
    return this.get("currentState.name") == "pass";
  }.property("currentState.name")
});

var PassManager = PassManagerClass.create({
  initialState : 'pass',
  playerIdx : 0,
  gamePlayers: Game.players,

  pass : Ember.State.create({
    enter: function(stateManager) {
      console.log("PM entering pass");
    } 
  }),

  act : Ember.State.create({
    enter: function(stateManager) {
      console.log("PM entering act");
    },
    exit: function(stateManager) {
      PassManager.playerIdx = PassManager.playerIdx + 1;
    } 
  }),

  done : Ember.State.create({
    enter: function(stateManager) {
      console.log("PassManager done");
    } 
  }),
});

export default PassManager;

Note: This is just for illustration, and to point you in the right direction. I haven't tested this.