I am trying to get a counter value kept up to date dynamically for a list of users in a chat room using pusher
. The variable usersCount
is maintained by the vue
instance and served in a template. The vue
debug tool shows it as undefined
in the code below. I am not passing the variable correctly to the template from the instance.
chat-player-list
template is called like this:
<div class="modal-body" id="sidebar-chat">
<div class="row">
<chat-player-list ref="users" :users="users"></chat-player-list>
</div>
<hr/>
<div class="row">
<div class="col-xs-12">
<chat-player-messages ref="messages" :messages="messages"></chat-player-messages>
<h5>Enemies chit chat</h5>
<chat-player-form v-on:chatmessagesent="addMessage" :player="{{ Auth::user() }}"></chat-player-form>
</div>
</div>
</div>
The players all list and render OK, and additionally the rest of the conditional functions work OK. Just the usersCounter
not rendering.
My chat.js
code contains the main vue
instance:
/**
* Set up Vue components for chat
*/
$(document).ready(function()
{
Vue.component('chat-player-list', require('../components/chat-player-list.vue'));
Vue.component('chat-player-messages', require('../components/chat-player-messages.vue'));
Vue.component('chat-player-form', require('../components/chat-player-form.vue'));
var chatPlayer = new Vue({
el: '#sidebar-chat',
data: function () {
return {
game: game,
messages: [],
users: [],
usersCount: 0
};
},
created() {
this.fetchPlayers();
this.fetchMessages();
Echo.join(chat_channel)
.here((users) => {
$.each(users, function(index, value) {
$('i#online-' + users[index].id).addClass('faa-ring animated player-online');
});
this.usersCount = users.length;
})
.joining((user) => {
$('i#online-' + user.id).addClass('faa-ring animated player-online');
this.usersCount = this.usersCount + 1;
})
.leaving((user) => {
$('i#online-' + user.id).removeClass('faa-ring animated player-online');
this.usersCount = this.usersCount - 1;
})
.listen('ChatMessageSent', (e) => {
this.messages.unshift({
message: e.message.message,
player: e.player
});
});
},
methods: {
fetchPlayers() {
this.users = game.progress.status.players_status;
},
fetchMessages() {
axios.get(chat_get_route)
.then(response => {
this.messages = response.data;
});
},
addMessage(message) {
this.messages.unshift(message);
this.$nextTick(() => {
this.$refs.messages.scrollToTop();
});
axios.post(chat_send_route, message)
.then(response => {
console.log(response.data);
});
}
}
});
});
In my template chat-player-list.vue
I have:
<template>
<div class="col-xs-12">
<h5>Enemies online</h5>
<span id="no-online-players" class="player-label pull-right">{{ usersCount }}</span>
<hr/>
<table id="new-game-opponents" class="new-game-opponents">
<tbody>
<tr v-for="(user, index) in users" :key="index" :class="[isPlayerTurn(user.owner_id) ? playerTurnClass : '']">
<td class="player_number">
<div :class="['opponent player-' + index++]" v-once>{{ index++ }}</div>
</td>
<td class="player-avatar">
<img :id="['player_avatar-' + user.owner_id]" class="setup_player_avatar" :src="[user.avatar]" v-once/>
</td>
<td class="player-name">
<div :id="['player_nickname-' + user.owner_id]" v-once>
{{ user.nickname }}
<i :class="[isThisPlayer(user.owner_id) ? 'fa fa-user-circle-o' : 'hidden']" aria-hidden="true" style="color:DarkOrange;"></i>
</div>
</td>
<td class="player-status text-right">
<div v-if="isPlayerTurn(user.owner_id)">
<span :id="['player_turn-' + user.owner_id]" class="stage-label pull-right">{{ progress }}</span>
</div>
<div v-else>
<i class="fa fa-clock-o" aria-hidden="true" style="margin-right:5px;"></i>
</div>
</td>
<td class="player-status text-right">
<i class="fa fa-comments" :id="['online-' + user.owner_id]" aria-hidden="true"></i>
</td>
<td class="player-status text-right">
<div v-if="isHuman(user.owner_id)">
<i class="fa fa-desktop" aria-hidden="true"></i>
</div>
<div v-else>
<i class="fa fa-user" aria-hidden="true" style="margin-right:2px;"></i>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: ['users', 'usersCount'],
data: function () {
return {
playerTurnClass: 'next-player-turn',
nextPlayerId: game.progress.next_player_id,
progress: game.progress.status.turn_status.current_stage,
myPlayerId: my_player.id
}
},
methods: {
isPlayerTurn(thisUserId) {
return thisUserId == this.nextPlayerId;
},
isThisPlayer(thisUserId) {
return thisUserId == this.myPlayerId;
},
isHuman(thisUserOwnerId) {
return thisUserOwnerId != 'ai';
}
}
};
</script>
What did I miss? Thanks!
Data won't be passed to child component automatically, you need manually declare it as prop.
Updated
You should bind
usersCount
like<chat-player-list ref="users" :users="users" :users-count="usersCount"></chat-player-list>
:a="b"
is a shorthand syntax of v-bind. It means passing current instance's datab
to the child component as a prop nameda
. Without this, the child component cannot receive it even thoughprop:['a']
exists.So just add
:users-count="usersCount"
.As Vamsi mentioned, usersCount should be passed as
users-count
, See: https://vuejs.org/v2/guide/components.html#camelCase-vs-kebab-case