Vue, edit the content of components with another component - javascript

I have a simple Vue js spa app that contain some bulma.io component.
And I need to edit the content of components with another component.
Like this image:
And somehow we need it to dynamically show form component when the panel or message component is clicked.
Thanks
Updated:
index.html
<div id="app">
<div class="columns">
<div class="column is-6">
<message title="Message test title 1" body="Message test body 1" #titleUpdate="title = $event" #bodyUpdate="body = $event"></message>
<message title="Message test title 2" body="Message test body 2" #titleUpdate="title = $event" #bodyUpdate="body = $event"></message>
<card title="Card test title 1" body="Card test body 2" #titleUpdate="title = $event" #bodyUpdate="body = $event"></card>
<card title="Card test title 1" body="Card test body 2" #titleUpdate="title = $event" #bodyUpdate="body = $event"></card>
</div>
<div class="column is-6">
<messageform></messageform>
<cardform></cardform>
</div>
</div>
</div>
main.js
import Vue from 'vue'
import message from './components/message'
import card from './components/card'
import messageform from './components/messageform'
import cardform from './components/cardform'
/* eslint-disable */
new Vue({
el: '#app',
components: { message, card, messageform, cardform }
});
card.vue
<template>
<div class="card">
<div class="card-image">
<figure class="image is-4by3">
<img src="https://bulma.io/images/placeholders/1280x960.png" alt="Placeholder image">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-left">
<figure class="image is-48x48">
<img src="https://bulma.io/images/placeholders/96x96.png" alt="Placeholder image">
</figure>
</div>
<div class="media-content">
<p class="title is-4">{{ title }}</p>
<p class="subtitle is-6">#{{ title }}</p>
</div>
</div>
<div class="content">
{{ body }}
<br>
<time datetime="2016-1-1">11:09 PM - 1 Jan 2016</time>
</div>
</div>
</div>
</template>
<script>
export default {
props: ['title', 'body'],
name: 'card',
methods: {
}
}
</script>
<style scoped>
.card {
margin-top: 20px
}
</style>
message.vue
<template>
<article class="message" v-show="isShow">
<div class="message-header">
<p>{{ title }}</p>
<button class="delete" aria-label="delete" #click="close"></button>
</div>
<div class="message-body">
{{ body }}
</div>
</article>
</template>
<script>
export default {
props: ['title', 'body'],
name: 'message',
data () {
return {
isShow: true
}
},
methods: {
close () {
this.isShow = false
}
}
}
</script>
<style>
</style>
cardform.vue
<template>
<article>
<h1>Card form</h1>
<div class="field">
<label class="label">Card title</label>
<div class="control">
<input class="input" type="text" placeholder="Text input" :value="title">
</div>
</div>
<div class="field">
<label class="label">Card body</label>
<div class="control">
<textarea class="textarea" placeholder="Textarea" :value="body"></textarea>
</div>
</div>
</article>
</template>
<script>
export default {
props: ['title', 'body'],
name: 'cardform'
}
</script>
<style>
</style>
messgeform.vue
<template>
<article>
<h1>Message form</h1>
<div class="field">
<label class="label">Message title</label>
<div class="control">
<input class="input" type="text" placeholder="Text input" :value="title" #input="titleUpdate">
</div>
</div>
<div class="field">
<label class="label">Message body</label>
<div class="control">
<textarea class="textarea" placeholder="Textarea" :value="body" #input="bodyUpdate"></textarea>
</div>
</div>
</article>
</template>
<script>
export default {
props: ['title', 'body'],
name: 'messageform',
methods: {
titleUpdate (event) {
this.$emit('titleUpdate', event.target.value)
},
bodyUpdate (event) {
this.$emit('bodyUpdate', event.target.value)
}
}
}
</script>
<style>
</style>

Not really sure I understood your question, but this may help you if you want to transfer data/use fonction from one component to another.

You should take a look at the usage of Passing Data to Child Components with props and Sending Messages to Parents with Events as it will cover everything you need to know to implement that functionality.
When you want to pass data to child you'll need to use props and get the data back by using the event emitter.
You can use eventbus or even vuex. I suggest you to take a look at props and events first.

Related

Vue.js: Changing background color not working

I'm fetching some content with Axios, looping over an array of objects, and trying to display a few elements with different background colors, but I can't make it work.
This is what I got so far:
<template>
<div class="container">
<div v-for="card in cards" :key="card.id" class="list">
<div class="card-container" v-if="card.id == 1234 || 1236">
<div class="card-container" v-bind:style="background">
</div>
<div class="card">
<p class="card-title">{{ card.title }}</p>
</div>
<div class="card">
<p class="card-short">{{ card.short }}</p>
<router-link to="">See more</router-link>
</div>
</div>
</div>
</div>
</template>
import axios from 'axios';
export default {
name:'Test',
data(){
return {
cards: Object,
background:{
backgroundColor:'red'
}
}
},
What the object looks like
} "cards":[
{"id": 1237,"name": "Card 1", bg_color:"green"},
{"id": 1236,"name": "Card 2", bg_color:"yellow},
{"id": 1234,"name": "Card 3", bg_color:"red},
{"id": 1233,"name": "Card 4", bg_color:"blue},
] here
Because your content is not inside your card-container which you have styled.
<template>
<div id="app">
<div class="container">
<div v-for="card in cards" :key="card.id" class="list">
<div class="card-container" v-if="card.id == 1234 || 1236">
<div class="card-container" v-bind:style="background">
<div class="card">
<p class="card-title">{{ card.title }}</p>
</div>
<div class="card">
<p class="card-short">{{ card.short }}</p>
<router-link to="">See more</router-link>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

Why every text shows on img hover when using v-if, v-else, #mouseover and #mouseleave in Vue.js?

I am trying to create a hover effect on images with Vue.js. I wrote the following code, but now as I hover over one of the images, the text shows up over all the images.
How can I resolve this problem? I want only the text that belongs to the image I hovered over to appear. Thank you in advance for your help.
Vue template:
<template>
<div class="row partner-body-row">
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = true"
#mouseleave="showText = false"
>
<img
class="hover-img"
src="img/img-1"
alt="img-1"
/>
<span v-if="showText">Text 1</span>
</div>
</div>
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = true"
#mouseleave="showText = false"
>
<img
class="hover-img"
src="img/img-2"
alt="img-2"
/>
<span v-if="showText">Text 2</span>
</div>
</div>
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = true"
#mouseleave="showText = false"
>
<img
class="hover-img"
src="img/img-3"
alt="img-3"
/>
<span v-if="showText">Text 3</span>
</div>
</div>
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = true"
#mouseleave="showText = false">
<img
class="hover-img"
src="img/img-4"
alt="img-4"
/>
<span v-if="showText">Text 4</span>
</div>
</div>
</div>
</template>
Script:
export default {
data: () => {
return {
showText: false,
};
},
};
all the conditions are tied to the same variable, have that variable hold each image's number rather than just true/false.
and ideally this should be done in CSS using :hover
<template>
<div class="row partner-body-row">
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = 1"
#mouseleave="showText = 0"
>
<img
class="hover-img"
src="img/img-1"
alt="img-1"
/>
<span v-if="showText === 1">Text 1</span>
</div>
</div>
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = 2"
#mouseleave="showText = 0"
>
<img
class="hover-img"
src="img/img-2"
alt="img-2"
/>
<span v-if="showText === 2">Text 2</span>
</div>
</div>
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = 3"
#mouseleave="showText = 0"
>
<img
class="hover-img"
src="img/img-3"
alt="img-3"
/>
<span v-if="showText === 3">Text 3</span>
</div>
</div>
<div class="col">
<div
class="img-wrapper"
#mouseover="showText = 4"
#mouseleave="showText = 0">
<img
class="hover-img"
src="img/img-4"
alt="img-4"
/>
<span v-if="showText === 4">Text 4</span>
</div>
</div>
</div>
</template>
export default {
data: () => {
return {
showText: 0,
};
},
};
You could just create a component for each Image with tooltip, something like:
Vue.config.productionTip = false;
const Img = {
name: 'Img',
props: ['src'],
data() {
return { showText: false }
},
template: '<div><img #mouseover="showText = true" #mouseleave="showText = false":src="src" /><span v-if="showText">Tooltip</span></div>',
};
const App = new Vue({
el: '#root',
components: { Img },
template: '<div><Img src="https://via.placeholder.com/150"/><Img src="https://via.placeholder.com/150"/></div>',
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="root"/>
if it's only to show the text on hover. You don't need to use v-model. in this case you would use css.
You could remove all the v-if's from the <span> and add this css
.image-container span {
display: 'none';
}
.image-container:hover span {
display: 'block';
}

Invalid end tag in Vue component when all tags are balanced

I am encountering some strange behaviour. My Vue component is not being rendered (output is <!---->), and my IDE is complaining of invalid end of component as though my tags aren't balanced... but they are.
Below is the entire component, it's pretty straightforward:
<template>
<div class="card activity">
<div class="card-body">
<div class="row">
<template v-if="activity.icon">
<div class="col-md-4">
<div class="icon">
<template v-if="activity.icon_type == 'font-awesome'">
<i :class="activity.icon"></i>
</template>
</div>
</div>
</template>
<template v-if="activity.icon">
<div class="col-md-8">
</template>
<template v-else>
<div class="col">
</template>
<h2 v-html="activity.title"></h2>
<template v-if="activity.description">
<p v-html="activity.description"></p>
</template>
<template v-if="activity.link">
<a :href="activity.link" class="btn btn-primary">{{ activity.link_text ? activity.link_text : 'Read More' }}</a>
</template>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
activity: {
type: Object,
required: true
},
},
data() {
return {};
},
mounted() {
console.log(this.activity);
},
computed: {
},
methods: {
}
}
</script>
The error from my IDE (VS Code) is:
[vue/no-parsing-error]
Parsing error: x-invalid-end-tag.eslint-plugin-vue
I've narrowed the problem down to these lines:
<template v-if="activity.icon">
<div class="col-md-8">
</template>
<template v-else>
<div class="col">
</template>
Removing this block fixes the issue. What am I missing?
I see what you are trying to do, instead I suggest replacing the div with this
<div :class="activity.icon ? 'col-md-8' : 'col'">
Try closing the div tags:
<template v-if="activity.icon">
<div class="col-md-8"></div>
</template>
<template v-else>
<div class="col"></div>
</template>

Dynamic data from v-for displayed in imported modal using slots

Problem:
I have a v-for of cards with interpolated data. When someone clicks a card, it triggers a modal component (separate component, using slots).
I want to display the data (title, img, previewUrl, downloadUrl) for whatever card was clicked in the modal, but currently I'm getting an error:
is not defined on the instance but referenced during render
Obviously data is not getting passed into the modal, even though I'm referencing the (card). I want to pass it the index of the card that was clicked, but am unsure of the best way to do this.
I assume that slots can be used to pass dynamic v-for data in the way I'm doing it. I hope I won't have to switch to props as that would muddy things.
Tried so far:
<!-- Cards -->
<div class="card-wrapper">
<div v-for="(card, index) in cards" :key="index" class="card">
<div #click="showModal(card)" class="card-body">
<img :src="card.img" alt="resource img" />
<h4 class="card-title">{{ card.title }}</h4>
<h6 class="card-subtitle">{{ card.subtitle }}</h6>
</div>
</div>
</div>
<!-- MODAL -->
<Modal v-show="isModalVisible" #close="closeModal">
<template v-slot:header>{{ img }} </template>
<template v-slot:body>
{{ title }}
<div class="text-center mb-1 mt-2">
<a :href="previewUrl"><button class="modal-btn btn btn-large">Preview</button></a>
<a :href="downloadUrl"><button class="modal-btn btn btn-large">Download</button></a>
</div>
</template>
</Modal>
DATA
`cards: [
{
title: "Card Title",
subtitle: "Card subtitle",
img: require("#/assets/images/test.jpg"),
previewUrl: "https://test.com",
downloadUrl: "https://test.com"
},`
METHODS:
`methods: {
showModal(card) {
this.isModalVisible = true;
this.title = card.title;
this.img = card.img;
this.previewUrl = card.previewUrl;
this.downloadUrl = card.downloadUrl;
this.isModalVisible = true;
},
closeModal() {
this.isModalVisible = false;
}
}`
The imported modal component
`<template>
<div>
<div class="modal-backdrop" #click.self="close">
<div class="card relative">
<button type="button" class="btn-close" #click="close">
<i class="material-icons">clear</i>
</button>
<header class="modal-header mb-1">
<slot name="header" />
</header>
<div class="mt-1 text-center">
<slot name="header-sub" />
</div>
<slot name="body" />
<footer class="text-center p-2">
<slot name="footer" />
</footer>
</div>
</div>
</div>
</template>
<script>
export default {
name: "modal",
methods: {
close() {
this.$emit("close");
}
}
};
</script>`
you should set the data of modal before and in the click set the correct info
for example in you data set
{
modalInfo:{title:'',img:''}
}
then in click set it like this
showModal(card) {
this.modalInfo.title = card.title;
this.modalInfo.img = card.img;
this.isModalVisible = true;
}
and in the modal part set it like this
<!-- Cards -->
<div class="card-wrapper">
<div v-for="(card, index) in cards" :key="index" class="card">
<div #click="showModal(card)" class="card-body">
<img :src="card.img" alt="resource img" />
<h4 class="card-title">{{ card.title }}</h4>
<h6 class="card-subtitle">{{ card.subtitle }}</h6>
</div>
</div>
</div>
<!-- MODAL -->
<Modal v-show="isModalVisible" #close="closeModal">
<template v-slot:header>{{ modalInfo.img }} </template>
<template v-slot:body>
{{ modalInfo.title }}
<div class="text-center mb-1 mt-2">
<a :href="previewUrl"><button class="modal-btn btn btn-large">Preview</button></a>

How can my Meteor Chat app recognize the users message?

Im having a really hard time with a project. Im pretty new to Meteor and JavaScript for that matter. Any help would be great. I have created a messenger app. When the users sign in, they can select who to chat with. However, when they start chatting. It only recognizes the user who is signed in and not the other chatter. Here is a screenshot of what I mean. I am signed in as a user from firefox and another from chrome.Here is the image, showing the chat.
Here is my HTML
<template name="chat_page">
<h2>Type in the box below to send a message!</h2>
<div class="row">
<div class="col-md-12">
<div class="well well-lg">
{{#each messages}}
{{> chat_message}}
{{/each}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form class="js-send-chat">
<input class="input" type="text" name="chat" placeholder="type a message here...">
<button class="btn btn-default">send</button>
</form>
</div>
</div>
</template>
<template name="chat_message">
<div class = "container">
<div class = "row">
<div class = "col-md-6">
{{> profile}} said: {{text}}
</div>
</div>
</div>
</template>
<template name="profile">
<small>
<img src = "/{{avatar}}" class="img-rounded" width="65" height="50">
{{username}}
</small>
</template>
Here is my JavaScript.
Template.chat_page.helpers({
messages:function(){
var chat = Chats.findOne({_id:Session.get("chatId")});
return chat.messages;
},
other_user:function(){
return ""
},
})
Template.profile.helpers({
username: function() {
return Meteor.user().profile.username;
},
avatar: function() {
return Meteor.user().profile.avatar;
},
})

Categories

Resources