On hover change multiple elements data in vue framework - javascript

I'm new to vue! I have 3 divs, All divs have a message data (One source)! I've bind a method, that when hover on one div it will change the message! The thing is working fine, but it change all div's message! And I know it's logical! But How can I only changed on that hovered element data! Not affecting others!
Here is my JSFiddle.
Html Is :
<div id="app">
<div class="one" v-on:mouseover="change">
{{ message }}
</div>
<div class="one" v-on:mouseover="change">
{{ message }}
</div>
<div class="one" v-on:mouseover="change">
{{ message }}
</div>
</div>
Vue :
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
},
methods : {
change : function() {
this.message = "Changed"
}
}
}
)

You need to create separate data bindings, one for each message div. There are a number of ways to solve this. The best solution depends on your use case. But, here's a simple solution:
Template:
<div id="app">
<div class="one" v-on:mouseover="change('foo', 'this is a message')">
{{ messages.foo }}
</div>
<div class="one" v-on:mouseover="change('bar', 'here is a different message')">
{{ messages.bar }}
</div>
<div class="one" v-on:mouseover="change('baz', 'message for baz')">
{{ messages.baz }}
</div>
</div>
Vue component:
new Vue({
el: '#app',
data: function () {
return { messages: {} }
},
methods : {
change : function(key, message) {
this.$set(this.messages, key, message)
}
}
})

Related

Vue Component is not visible in <template> html tag

I have a simple problem but I can't find any reliable answer.
So here is what I want to do. The code is simplified for clarity.
<h1>Hello</h1>
<div id='app'>
<template>
<p>Here is the app: {{message}}</p>
#Html.Partial("_Component")
</template>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
message: "App works!"
}
});
</script>
And _Component.cshtml file:
<my-component inline-template>
<div>
<p><button v-on:click="counter += 1">Add One More Click</button></p>
<p>The button has been clicked {{ counter }} times</p>
</div>
</my-component>
<script>
Vue.component('my-component',
{
data: function () {
return {
counter: 1
}
}
});
</script>
Problem with this code is that my-component is not rendering. Overall, I'm working in project of asp.net mvc application and its required to use template tag.
If I remove this tag, the page is a mess until it's rendered.
Is there any solution or workaround to be able to see component in this case?
You declare the component in the wrong place. Should be like this
<h1>Hello</h1>
<div id='app'>
<template>
<p>Here is the app: {{message}}</p>
<my-component inline-template>
<div>
<p><button v-on:click="counter += 1">Add One More Click</button></p>
<p>The button has been clicked {{ counter }} times</p>
</div>
</my-component>
</template>
</div>
<script>
Vue.component('my-component', {
data: function () {
return {
counter: 1
}
}
});
var vm = new Vue({
el: '#app',
data: {
message: "App works!"
}
});
</script>

Vue : Accessing Nested Object Component's Values

I have problems accessing this "name" property on the component. I can only access it statically.
<template>
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
{{ channel.users[0].name }}
</p>
</div>
</template>
Here is an Image of my Vue Devtools
So I have an v-for loop over channels, and I want to: Access the Usernames for each channel (if it is not my own preferably as "username" is set on my own i think its easy to exclude it right?) So that in the end In Channel 1 when there are 2 Users , I want to show the corresponding username, so the "other username", the one i am chatting with, and he should see my name that is the initial goal.
I thought of doing something like this:
<template>
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
<!-- {{ channel.users[0].name }} -->
<span v-for="user,key in channel">{{key}}</span>
</p>
</div>
it at least displays the content of the channels object for each channel, but something like this isnt gonna work: key.user.name , unfortunately im stuck here. please help :)
edit: here is a dd() of the view
click
EDIT 2: Parent Data Provided:
//chat-app.blade.php
<div id="app">
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Chats</div>
<vue-chat :channels="{{ $channels }}" ></vue-chat>
</div>
</div>
</div>
</div>
</div>
</div>
//<vue-chat> component
<template>
<div class="chat">
<div class="container">
<div class="row">
<div class="col-md-3">
<vue-chat-channels
:channels="channels"
:active-channel="activeChannel"
#channelChanged="onChannelChanged"
:username="sername"
></vue-chat-channels>
</div>
<div class="col-md-3">
<vue-chat-messages :messages="messages"></vue-chat-messages>
</div>
<div class="col-md-3">participants</div>
</div>
<div class="message-input-wrapper col-md-12"><vue-chat-new-message :active-channel="activeChannel"
:username="username"></vue-chat-new-message></div>
</div>
</div>
</template>
<script>
export default {
props: ["channels"],
data() {
return {
activeChannel: this.channels[0].id,
messages: [],
username: ''
};
},
methods: {
fetchMessages() {
let endpoint = `/channels/${this.activeChannel}/messages`;
axios.get(endpoint).then(({ data }) => {
this.messages = data;
});
},
onChannelChanged(id) {
this.activeChannel = id;
this.fetchMessages();
}
},
created() {
this.fetchMessages();
axios.get('/userfetch').then( ({data}) => {
console.log("Current User: "+data.name);
this.username = data.name;
});
console.log(this.channels[0].name);
// for (let channel of this.channels) {
this.channels.forEach(channel => {
// Channelname
window.Echo.channel('presence-'+channel.name)
.listen('MessageSent', (channel) => {
console.log(channel.data.message);
this.messages.push({ message: channel.data.message, author_username: channel.data.author_username});
if (this.activeChannel == channel.id) {
console.log("received message");
}
});
});
}
};
</script>
<style>
</style>
//ChatController.php
public function index()
{
$channels = Channel::with('users')->whereHas('users', function($q) {
$q->where('user_id',Auth::id());
})->get();
$user = Auth::user()->name;
return view('chat-app' , compact('channels','user'));
}
Short Explanation: ChatController returns the blade view, which has the data channels and user (my username) , and then vue comes into play which should pass down the prop of my username but i couldnt get it to work just yet
So you need to access users in every channel.
You can try like this:
<div class="col-md-12">
<p
v-for="channel in channels"
:key="channel.id"
class="channel"
:class="{ 'active': channel.id == activeChannel }"
#click="setChannel(channel.id)">
<span v-for="user in channel.users">
{{ user.name }}
</span>
</p>
</div>
This should work. If you have errors provide it here.
If you need to compare every user you can do it simply with v-if:
<span v-for="user in channel.users">
<span v-if="user.name === parentdata">
{{ user.name }}
</span>
</span>

Create unknown in advance Vue instances count

In the question Are multiple Vuejs instances possible?, below solution has been suggested:
new Vue({
el: '#app1',
data () {
return {
message: 'Hello'
}
},
})
new Vue({
el: '#app2',
data () {
return {
message: 'Helloa'
}
}
})
<div id="app1">
{{ message }}
</div>
<div id="app2">
{{ message }}
</div>
Well, it works for two instances, but what if we does not know in advance, how many <div id="appN"> will be? Also, it may not has id.
<!-- we don't know in advance, how many it will be -->
<div class="target">
{{ message }}
</div>
<div class="target">
{{ message }}
</div>
Is Vue's flexibility ends here?

Vue 2, how to data bind to an element that is "data bound"

I created a jsfiddle for this:
JS Fiddle
Basically I have a three text areas. When you enter copy in the first, it should bind to the second, which would also flow to the third.
<div id="app">
<textarea v-model="first"></textarea>
<textarea v-model="second">{{first}}</textarea>
<textarea>{{ second }}</textarea>
You could use watch properties to catch any change in first value and assign it to the second and so on :
new Vue({
el: '#app',
data: {
first: '',
second: '',
third:''
},
watch:{
first(val){
this.second=val;
},
second(val){
this.third=val;
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<textarea v-model="first"></textarea>
<textarea v-model="second" ></textarea>
<p>2 >> {{ second }}</p>
<textarea v-model="third" ></textarea>
<p>3 >> {{ third }}</p>
</div>

How to add condition to HTML code in Vue.js?

I have the following template code:
<template v-for="(index, message) in messages">
{literal}
<div class="message_block {{message.message_type}}" v-if="message.message_type">
<div class="message">
{{message.message}}
</div>
</div>
{/literal}
</template>
What I'm trying to do is show the one line - <div class="message_block"..., if message.message_type is not equal to null, or is not undefined.
This is the data I've got:
var demo = new Vue({
el: '#testblock',
data: {
messages: [
{ message: 'Foo', message_type: "left" },
{ message: 'Bar', message_type: null }
]
}
})
I'm trying to add the wrapper <div class="message_block">, if the message_type is not equal to null.
According to your comment above:
#LinusBorg No, I want the "Bar" to show regardless of the value of message_type, it's just if message_type is null, I don't want a wrapper around it.
There is no other way than to duplicate the inner div.
<template v-for="(index, message) in messages">
{literal}
<div class="message_block {{message.message_type}}" v-if="message.message_type">
<div class="message">
{{message.message}}
</div>
</div>
<div v-if="!message.message_type" class="message">
{{message.message}}
</div>
{/literal}
</template>
If you don't want to duplicate it, you can either define it as a small component to re-use it, or use a partial.

Categories

Resources