1

I am developing an online game for 2 players using Vue js and Firestore.

The game starts as follows: The active user will choose a random person from online users and play games with him.

When the new game button is clicked;

  1. A random player will be selected from online users.
  2. A new game room will be created: game number and player information will be saved in the firestore database.
  3. For the random user selected, game number and opponent information will be matched.
  4. Both users will be directed to the Game page.

My codes

import db from "@/firebase/init";
export default {
    name: "Home",
    data() {
        return {
            activeUsers: [],
            currentUser: null,
            opponent: null,
            gameNo: null
        };
    },
    created() {
        this.currentUser = this.$session.get("user");
        this.createOnlineUser();
        this.getOnlineUsers();
    },
    methods: {
        createOnlineUser() {
            let ref = db.collection("game_users").doc(this.currentUser.email);
            ref.get().then(doc => {
                if (!doc.exists) {
                    ref.set({
                        user_id: this.currentUser.id,
                        username: this.currentUser.username,
                        is_play: false
                    });
                }
            });
        },
        getOnlineUsers() {
            db.collection("game_users")
                .where("is_play", "==", false)
                .onSnapshot(snapshot => {
                    snapshot.docChanges().forEach(change => {
                        let doc = change.doc;

                        var user = {
                            user_id: doc.data().user_id,
                            username: doc.data().username,
                            email: doc.id
                        };

                        if (change.type === "added") {
                            if (doc.data().user_id != this.currentUser.id) {
                                let userIndex = this.activeUsers.findIndex(
                                    element => element.user_id == user.user_id
                                );
                                if (userIndex === -1) {
                                    this.activeUsers.push(user);
                                }
                            }
                        } else if (change.type === "removed") {
                            this.activeUsers = this.activeUsers.filter(element => {
                                return element.user_id != user.user_id;
                            });
                        }
                    });
                });
        },
        newGame() {
            this.opponent = this.randomUser();
            this.createGameRoom();
        },
        createGameRoom() {
            this.gameNo = Date.now();
            db.collection("game_rooms")
                .add({
                    gameNo: this.gameNo,
                    players: [this.currentUser.email, this.opponent.email],
                })
                .then(() => {
                    this.addGameNoSession();
                })
                .then(() => {
                    this.createGameAndOpponent();
                });
        },
        createGameAndOpponent() {
            db.collection("game_rooms").onSnapshot(snapshot => {
                snapshot.docChanges().forEach(change => {
                    if (change.type == "added") {
                        let doc = change.doc;
                        let players = doc.data().players;
                        let currentUserIndex = players.indexOf(this.currentUser.email);
                        if (currentUserIndex != -1) {
                            if (!this.$session.exists("gameNo")) {
                                this.gameNo = doc.data().gameNo;
                                this.addGameNoSession();
                            }
                        }
                        this.addOpponentSession(currentUserIndex, players);
                        this.$router.push({ name: "Game" });
                    }
                });
            });
        },
        addGameNoSession() {
            this.$session.set("gameNo", this.gameNo);
        },
        randomUser() {
            var item = this.activeUsers[
                Math.floor(Math.random() * this.activeUsers.length)
            ];
            return item;
        },
        addOpponentSession(currentUserIndex, players) {
            let opponent = null,
                opponentIndex = null;
            if (currentUserIndex == 0) {
                opponentIndex = 1;
            } else {
                opponentIndex = 0;
            }
            opponent = this.activeUsers.find(
                user => user.email === players[opponentIndex]
            );
            this.$session.set("opponent", opponent);
        },
    }
};
<template>
  <div id="home">
    <Navbar />
    <div class="home container">
      <div class="card">
        <a  @click="newGame"> New Game
        </a>
      </div>
    </div>
  </div>
</template>

Vue Router - index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import Game from '../views/Game.vue'
import Login from '../views/auth/Login.vue'
import Signup from '../views/auth/Signup.vue'
Vue.use(VueRouter)



const routes = [{
        path: '/',
        name: 'Home',
        component: Home,
        meta: {
            requiresAuth: true
        }
    }, {
        path: '/game',
        name: 'Game',
        component: Game,
        meta: {
            requiresAuth: true
        }
    },
    {
        path: '/login',
        name: 'Login',
        component: Login
    },
    {
        path: '/signup',
        name: 'Signup',
        component: Signup
    }

]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})


router.beforeEach((to, from, next) => {
    if (to.matched.some(rec => rec.meta.requiresAuth)) {

        if (Vue.prototype.$session.exists('user')) {
            next()
        } else {
            next({ name: 'Login' })
        }
    } else {
        if (Vue.prototype.$session.exists('user')) {

            if (to.name == "Login" || to.name == "Signup") {
                next({ name: 'Home' })
            }
        }
        next()
    }
})

export default router

I'm checking inside the createGameAndOpponent function:

If there is a change in "game_rooms" or a new game has been created, find the opponent from online users and redirect both users to the game page. But there is an error during the redirection here. The page is not redirected and gives the following error.

But I get the error below

"Uncaught (in promise)"

Error Detail:

vue-router.esm.js:2086 Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated", message: "Navigating to current location ("/game") is not allowed", stack: "Error↵ at new NavigationDuplicated (webpack-int…c/views/Home.vue?vue&type=script&lang=js&:175:31)"}_name: "NavigationDuplicated"name: "NavigationDuplicated"message: "Navigating to current location ("/game") is not allowed"stack: "Error↵ at new NavigationDuplicated (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2009:14)↵ at HTML5History.confirmTransition (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2125:18)↵ at HTML5History.transitionTo (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2069:8)↵ at HTML5History.push (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2400:10)↵ at eval (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2812:22)↵ at new Promise ()↵ at VueRouter.push (webpack-internal:///./node_modules/vue-router/dist/vue-router.esm.js:2811:12)↵ at eval (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:204:26)↵ at Array.forEach ()↵ at Object.eval [as next] (webpack-internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:175:31)"proto: Error
eval @ vue-router.esm.js:2086
abort @ vue-router.esm.js:2117
confirmTransition @ vue-router.esm.js:2125
transitionTo @ vue-router.esm.js:2069
push @ vue-router.esm.js:2400
eval @ vue-router.esm.js:2812
push @ vue-router.esm.js:2811
eval @ cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:204
eval @ cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:175
next @ index.cjs.js:22426
eval @ index.cjs.js:20155
setTimeout (async)
AsyncObserver.scheduleEvent @ index.cjs.js:20153
AsyncObserver.next @ index.cjs.js:20142
QueryListener.raiseInitialEvent @ index.cjs.js:17098
QueryListener.onViewSnapshot @ index.cjs.js:17033
EventManager.listen @ index.cjs.js:16889
eval @ index.cjs.js:20004
eval @ index.cjs.js:1698
Promise.then (async)
AsyncQueue.enqueueInternal @ index.cjs.js:1696
AsyncQueue.enqueue @ index.cjs.js:1692
AsyncQueue.enqueueAndForget @ index.cjs.js:1639
FirestoreClient.listen @ index.cjs.js:20003
Query.onSnapshotInternal @ index.cjs.js:22432
Query.onSnapshot @ index.cjs.js:22413
oyunVeRakipTanimla @ cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:174
eval @ cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:155
Promise.then (async)
createGameRoom @ cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:154
newGame @ cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/Home.vue?vue&type=script&lang=js&:133
invokeWithErrorHandling @ vue.runtime.esm.js:1853
invoker @ vue.runtime.esm.js:2178
original._wrapper @ vue.runtime.esm.js:6907

Where am I making mistakes?

What method should I follow to direct both users to the game page in real time?

Community
  • 1
  • 1
Mustafa
  • 977
  • 3
  • 12
  • 25
  • 1
    Previous stackoverflow questions said that this error happens when you create a router link or attempt to push the router to a view that you are already in. if you're inside of `/game` and try to navigate to `/game` this error will pop up – Kevin Hernandez Feb 20 '20 at 19:49
  • 1
    See [this](https://stackoverflow.com/questions/57837758/navigationduplicated-navigating-to-current-location-search-is-not-allowed) question here – Kevin Hernandez Feb 20 '20 at 19:50
  • 1
    Try doing `this.$router.push('/game')` or whatever you have the name of the physical route set to – Kevin Hernandez Feb 20 '20 at 19:52
  • The method you said didn't work. It gives the same error. I am reviewing the resource you shared. @KevinHernandez – Mustafa Feb 20 '20 at 21:07
  • 1
    Try calling the method on vues next tick `this.$nextTick(() =>this.$router.push('/game'))` – Kevin Hernandez Feb 20 '20 at 21:08
  • I tried this method:`this.$nextTick(() =>this.$router.push('/game'))`. I printed the name of the current page inside the `createGameAndOpponent` function:`console.log("Before going to the game page:"+this.$route.path);` But sometimes it gives the result of "/game" although it is also on the Homepage. @KevinHernandez – Mustafa Feb 21 '20 at 09:07
  • 1
    Yeah that means the component is loaded before you call router.push something is causing your component to load prematurely – Kevin Hernandez Feb 21 '20 at 12:05
  • I updated the question details. I also shared the "Vue Router - index.js" details.You can review – Mustafa Feb 21 '20 at 12:21
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/208248/discussion-between-kevin-hernandez-and-hibrit-usta). – Kevin Hernandez Feb 21 '20 at 12:25

0 Answers0