so, for context, I have a client-side for an app where the server sends the client the client's friends over a socket connection. I can retrieve the friends, and even create clickable list elements so that the user can send a message to a friend, etc. However the one problem that I am having is that when using the mustache syntax to render information, nothing renders. I have the following code.
index.html (the following is inside the app div)
<div id="friends">
<p>Friends</p>
<ul id="friend-list">
<li
v-for="friend in friends"
v-on:click="setFriend(friend.id)"
>Friend:{{friend.text}}
</li>
</ul>
</div>
index.js
var socket = io.connect('http://localhost:3000');
var app = new Vue({
el: '#app',
data: {
messageContent: '',
friends: [],
messages: []
}
})
socket.on('connect', function(){
socket.emit('authentication', Cookies.get('user'));
socket.on('authenticated', function() {
socket.on('sendFriends',(data) => {
data.forEach(element => {
console.log(element.username)
app.friends.push({
text: element.username '.' element.id,
id: element.id
})
})
toUser = app.friends[0].id
})
})
})
Even if I were to fill the friends array without data from the socket connection, the text on each element would not render. By this I mean, there would be bullet points which have the on click function, however no text. However, when I create a codepen, the data is rendered correctly. Does this have to do with the socket connection and how Vue reacts to data change? https://codepen.io/dvub/pen/XWaebyb (codepen link)
CodePudding user response:
Since API calls are asynchronous, Vue is already reading the values of friends
before the call is processed and the data is received. So Vue is already started looping over the friends
array before anything has come back from the API.
The individual friend
is passed as a prop to a child component. The child component inturn is now looking for properties on that object (ie, friend.name
).
But the friends array is empty when the component is first mounted. Therefore adding a simple v-if
to stop the rendering until you have received the information is needed.
<ul id="friend-list" v-if="friends.length">
You may also want to remove
toUser = app.friends[0].id
It does not look like valid JS syntax (where is toUser
declared?).
CodePudding user response:
You can't set properly friends
values unless you're into the Vue's app context. So you should begin to put back all the stuff into your Vue app. It should looks more like something (I can't guarantee it works since I don't know how your socket lib works, but this is how it should be structured) :
<div id="friends">
<p>Friends</p>
<ul id="friend-list">
<li v-for="friend in friends"
v-on:click="setFriend(friend.id)">Friend:{{friend.text}}
</li>
</ul>
</div>
const app = new Vue({
el: '#app',
data: {
socket: null,
messageContent: '',
friends: [],
messages: []
},
mounted: {
// Here it depends on how the library works. You may have to use async / await on connection init :
this socket = io.connect('http://localhost:3000');
this.socket.on('connect', function(){
this.socket.emit('authentication', Cookies.get('user'));
this.socket.on('authenticated', function() {
this.socket.on('sendFriends',(data) => {
data.forEach(element => {
console.log(element.username)
this.friends.push({
text: element.username '.' element.id,
id: element.id
});
});
});
// I don't know what you're trying to do here so I commented this one :
// toUser = app.friends[0].id
});
}
});