Search code examples
arraysfirebasepolymer2-way-object-databinding

Set values of a Firebase data array using Polymer


Problem:
I want to try to have multiple games running at the root of my Firebase, they all have Firebase generated id's,
when I'm trying to fetch them using the <firebase-collection> I'm always getting an array of the Objects, and 2-way binding is very hard with Polymer.
Is there a way to get the Firebase data as an Object?

I tried to add the data-as-object attribute, but it didn't worked, I also got an array.
I even tried to use the <firebase-document> element by simply change form
<-collection> to <-document>, but then updating the game data didn't push to firebase.
I don't know if this is possible ...

Or is there a way for good two-way binding?
I can't use the index of the array item, like this: this.set('gameData.' + i), because then I'm getting the error Uncaught Error: unexpected key 2, when I try to modify the values under the Object in the array

Full code on Github

My code:
Data provider:

<firebase-collection location="https://***.firebaseio.com" 
                     data="{{data}}" data-as-object log>
</firebase-collection>
<!-- script -->
Polymer({
    is: 'tmp-game-data',
    properties: {
        data: {
            notify: true
        }
        }
});

Game Element:

<!-- map with several players(Array), -->
<!-- an player(Object) has some properties -->
<!-- on-map-ready, when the map is fully configured --> 
<tmp-map players="{{game.players}}" 
         on-map-ready="_mapReadyCallback">
</tmp-map>
<!-- menu user for creating and -->
<!-- joining games with selected settings -->
<tmp-menu on-start-global-game="startGlobalGame" 
          on-join-game="joinGame">
</tmp-menu>
<tmp-game-data data="{{gamesData}}"></tmp-game-data>
<!-- script -->
var blocks = []; //Map blocks, global access

Polymer({
    is: 'tmp-game',

    properties: {
        gamesData: {
            notify: true
        },
        game: {
            notify: true
        },
        gameId: {
            type: String
        }
    },

    startGlobalGame: function(e) {
        var gameId = getRandomString(6);
        this.set('gameId', gameId);

        var player = {id: /*playerId*/};
        var players = [player];

        this.push('gamesData', {
            gameId: gameId,
            maxPlayers: e.detail.maxPlayers,
            players: players
        });

        this.selectGame();

        //generate map
    },

    joinGame: function(e) {
        var gameId = e.detail.gameId;
        for (var i = 0; i < this.gamesData.length; i++) {
            if(this.gamesData[i].gameId === gameId) {
                var map = this.get('gamesData.' + i + '.map');
                //generate map with the map of the game
            }
        }
        this.selectGame();
    },

    selectGame: function() {
        for (var i = 0; i < this.gamesData.length; i++) {
            if(this.gamesData[i].gameId === this.gameId) {
                this.set('game', this.gamesData[i]);
                this.linkPaths('game', 'gamesData.' + i);
            }
        }
    },

    _mapReadyCallback: function(e) {
        for (var i = 0; i < this.gamesData.length; i++) {
            if(this.gamesData[i].gameId === this.gameId) {
                //get the map as a json
                var map = JSON.stringify(blocks);
                this.set('gamesData.' + i + '.map', map);
            }
        }
    }
});

Solution

  • I don't think that there is a way to manipulate the data as Object instead of Array...

    In your snippet, you do not specify the Array type for data and gamesData

    You will have to use Polymer API to manipulate the Array you get through data-binding, like this.push, this.splice, etc... like you did already.

    You should also be able to this.set('gamesData.' + i + '.map', map); like described here