0

I am going over the 2048 game tutorial from ng-newsletter and I am stuck on my gridservice methods not being defined.

Here is the code module that injects the Grid module and its GridService

angular.module('Game', ['Grid'])
  .service('GameManager', ['GridService', function(GridService) {

        // create a new game
        this.newGame = function() {
            GridService.buildEmptyGameBoard();
            GridService.buildStartingPosition();
            this.reinit();
        };
  }]);

Here is my Grid module and Gridserivce along with the methods angular references as being undefined:

    angular.module('Grid', [])

            /**
             * GridService handles all the conditions of the board
             */
            .service('GridService', ['TileModel', function(TileModel) {

                return {
                    buildEmptyGameBoard: buildEmptyGameBoard
                }

                this.startingTileNumber = 2;



                // grid array acts the as the board and remains static
                this.grid = [];

                // tiles array acts the pieces on the board and will be dynamic
                this.tiles = [];
                this.tiles.push(new TileModel({x: 1, y: 1}, 2));
                this.tiles.push(new TileModel({x: 1, y: 2}, 2));

                // Size of the board
                this.size = 4;


                //this.buildEmptyGameBoard = function() {
                function buildEmptyGameBoard() {
                    var self = this;

                    // Initialize our grid
                    for(var x = 0; x < this.size * this.size; x++) {
                        this.grid[x] = null;
                    }

                    // Initialize our tile array 
                    // with a bunch of null objects
                    this.forEach(function(x,y) {
                        self.setCellAt({x:x, y:y}, null);
                    });

                }


        // Run a method for each element in the tiles array
                this.forEach = function(cb) {
                    var totalSize = this.size * this.size;
                    for(var i = 0; i < totalSize; i++) {
                        var pos = this._positionToCoordinates(i);
                        cb(pos.x, pos.y, this.tiles[i]);
                    }
                };

    // Convert i to x,y
            // cell position from single dimensional array
            // converts to x and y coords for pos on game board
            this._positionToCoordinates = function(i) {
                var x = i % service.size;
                    y = (i - x) / service.size;
                return {
                    x: x,
                    y: y
                };
            };


}])

    /**
     * TileModel Factory to define values for our tile directive css positions
     */
    .factory('TileModel', function() {
        var Tile = function(pos, val) {
            this.x = pos.x;
            this.y = pos.y;
            this.value = val || 2;
        };

        return Tile;
    });

Curretnly I am getting this: Error: this.forEach is not a function

I have been able to work out some other errors in this app. all the errors have been about methods in my gridService not being defined or not a function. Seems to be something fundamentally wrong or missing with my GridService that I am failing to see.

Note: both files are called and loading properly in my index.html file

0

2 Answers 2

1
  1. You have an early return statement. This, at the beginning of the function:

    return {
        buildEmptyGameBoard: buildEmptyGameBoard
    }
    

    means that the following statements will never be executed:

    this.startingTileNumber = 2;
    ...etc...
    

    Javascript runs the declarations in the first pass (i.e. buildEmptyGameBoard is declared and will be defined), but not the statements (i.e. this.forEach = function(cb) {} will wait to run at the second pass). But at the second pass, a return is executed immediately and nothing else runs.

    So **put the return at the end of the function.

  2. A service is not a controller, it is not instantiated with new. Your service returns an object with 1 method, buildEmptyGameBoard. this.forEach = function(cb) {} will attach the foreach function to some unknown object, certainly not the object you return. So change your code to:

    function buildEmptyGameBoard() { ... }
    function foreach(cb) { ... }
    ...etc...
    
    return {
        buildEmptyGameBoard: buildEmptyGameBoard,
        foreach: foreach,
        ...etc...
    };
    
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot, this was very helpful in understanding the flow of it. I ended up using the var self = this work around so I wouldnt have to attach all my methods to the return statement
0

You have a couple of bugs here - one immediate one, and another that you'll uncover as soon as you fix the first.

  1. 'this' is not always what you expect in Javascript. Calling a function doesn't change context (you can use things like call/apply/bind for that) so watch your 'this' pointer. You'll have better results with the standard JS trick:

    var self = this;
    

    Then use 'self' everywhere instead of 'this'.

  2. this.forEach does not exist because you're calling it either on your service itself (this) or the caller's context (depending on how you call your service). Don't you mean this.tiles.forEach()?

  3. You call GridService.buildStartingPosition(); but you have not defined it. As soon as you fix your forEach, this will throw an exception here.

1 Comment

Thanks a lot for the pointers here I forgot about the self = this work around. This fixed my problem

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.