I am trying to change prop of my component if it is rendered more than once. By default the first prop will have fixed value but the second calling of the component will get it's prop from parent's parent. In my example, the value from App.vue doesn't change prop going in myBox.vue
Here is my link
App.vue
<template>
<div id="app">
{{years}}
<myBox :years="years"/>
<button #click="changeProp">Change prop</button>
</div>
</template>
<script>
import myBox from "./components/myBox";
export default {
name: "App",
components: {
myBox
},
data() {
return {
years: ""
};
},
methods: {
changeProp() {
this.years = 100;
}
}
};
</script>
mySelect.vue
<template>
<div class="select">
<select>
{{years}}
<option v-for=" (i, index) in years" :key="index">{{i}}</option>
</select>
</div>
</template>
<script>
import myBox from "./myBox";
export default {
data() {
return {};
},
components: {
myBox
},
props: ["years"]
};
</script>
<style>
.select {
width: 100px;
height: 100px;
}
</style>
mySelect.vue
<template>
<div class="box">
<mySelect :years="24"/>
<mySelect :years="24"/>
<mySelect :years="24"/>
</div>
</template>
<script>
import mySelect from "./mySelect.vue";
export default {
data() {
return {
//years: [2000, 2001, 2002, 2003, 2004, 2005, 2006],
value: 5
};
},
components: {
mySelect
}
};
</script>
<style>
div.box {
width: 100%;
height: auto;
background: lightblue;
}
</style>
Currently my code generates the second and thrid component dynamic with v-if and takes the default props value, whereas I want it to get from parent's parent.
Is it possible?
Related
In Parent I included one ChildComponent as such:
<template>
<div>
<ChildComponent :value="var1" v-slot="{value}">
<input v-model="value.name"/>
</ChildComponent>
</div>
</template>
<script>
import ChildComponent from "../components/ChildComponent.vue";
export default {
components: { ChildComponent },
data() {
return {
var1: {
name: "Vue.js",
message: "LocalHost"
}
};
}
</script>
ChildComponent:
<template>
<div>
<div id="divToShow" v-if="this.$slots.default || this.$scopedSlots.value">
<slot/>
</div>
<div v-else id="divFallback">
<p>Nothing in your input component!</p>
</div>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: {
value: String
}
}
</script>
However, divToShow does not appear, so divFallback takes its place. How should I go about making divToShow show up when Parent defines a (seemingly) dynamic name slot like this?
I am trying to practice vue application using props but when I click on the the name, I tried to do console.log the problem but it hasn't helped me. Maybe I am new to filter option but I want to know what I am doing wrong?
App.vue
<template>
<div id="app">
<h1>All Friends</h1>
<AllFriends :Totalfriends="friends" />
<h1>Online Friends</h1>
<OnlineFriends :Totalfriends="friends" #toggleStatus="toggleStatus" />
</div>
</template>
<script>
import AllFriends from "./components/AllFriends"
import OnlineFriends from "./components/OnlineFriends"
export default {
name: 'App',
components: {
AllFriends,
OnlineFriends
},
data(){
return{
friends: [
{name:'Mario', online: true},
{name:'Luigi', online: false},
{name:'Todd', online: true},
{name:'Bowzer', online: false}
]
}
},
methods: {
toggleStatus(payload){
this.friends = this.friends.filter((friend)=>{
if(friend !== payload){
console.log(friend)
}
})
}
}
}
</script>
OnlineFriends.vue
<template>
<div>
Online Friends
<div v-for="(friends, index) in Totalfriends" :key="index">
<p #click="toggleStatus(friends.name)" v-if="friends.online">{{friends.name}}</p>
</div>
</div>
</template>
<script>
export default {
props:["Totalfriends"],
methods: {
toggleStatus(friend){
this.$emit("toggleStatus",{friend})
}
}
}
</script>
AllFriends.vue
<template>
<div>
All Friends
<div v-for="(friend, index) of Totalfriends" :key="index">
<p>{{friend.name}}</p>
</div>
</div>
</template>
<script>
export default {
name: "AllFriends",
props: ["Totalfriends"]
}
</script>
I have a header, logo, menu, and menu item.
The menu item contains the text "This is a menu item", but vue is not processing and displaying it.
These are the components:
App.vue
<template>
<div id="app">
<mainHeader />
</div>
</template>
<script>
import mainHeader from './components/mainHeader.vue'
export default {
name: 'App',
components: {
mainHeader
}
}
</script>
<style>
html,body{
box-sizing: border-box;
margin:0px;
padding:0px;
}
#app{
background-color:gray;
}
</style>
./components/mainHeader.vue
<template>
<div id="main-header">
<logo />
<mainMenu />
</div>
</template>
<script>
import logo from "./logo.vue";
import mainMenu from "./mainMenu.vue";
export default
{
name: 'mainHeader',
components:
{
logo,
mainMenu,
}
}
</script>
./components/mainMenu.vue
<template>
<div id="main-menu">
<menuItem />
</div>
</template>
<script>
import menuItem from "./menuItem.vue";
export default
{
name: "mainMenu",
components:
[
menuItem
]
}
</script>
./components/menuItem.vue
<template>
<div class="menu-item">
This is a menu item
</div>
</template>
<script>
export default
{
name: "menuItem"
}
</script>
When I check the DOM, the menuItem is not being parsed into a div with the message:
<div id="app">
<div data-v-ea6a1e94="" id="main-header">
<div data-v-4b16403b="" data-v-ea6a1e94="" id="logo"></div>
<div data-v-d2968a70="" data-v-ea6a1e94="" id="main-menu">
<menuitem data-v-d2968a70=""></menuitem>
</div>
</div>
</div>
How can I get the component to work?
The components option has an object as a value :
components:{
menuItem
}
it's recommended to name the component using kebab-case:
name: "menu-item"
and the file name with CamelCase MenuItem
and import it like :
import MenuItem from "./MenuItem.vue";
then register it like :
components:{
MenuItem
}
finally use it like <menu-item ... />
I am trying to create a splash screen (loading-screen) in Vue JS that after a few seconds fades away, revealing my defaut view. I have tried several approaches but just can't get any to work. The closest is this example on CodePen But ideally the component wouldn't be inside main.js and instead inside its own component. Despite that the below code won't work.
My main.js is as below:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
Vue.config.productionTip = false;
// FILTERS
Vue.filter('snippet', function(value) {
return value.slice(0,100);
});
Vue.component('loading-screen', {
template: '<div id="loading">Loading...</div>'
})
new Vue({
router,
store,
render: h => h(App),
data: {
isLoading: true
},
mounted () {
setTimeout(() => {
this.isLoading = false
}, 3000)
}
}).$mount("#app");
and my App.vue is as follows
<template>
<div id="app">
<loading-screen v-if="isLoading"></loading-screen>
<Top/>
<router-view/>
<PrimaryAppNav/>
</div>
</template>
<script>
import Top from './components/Top.vue'
import PrimaryAppNav from './components/PrimaryAppNav.vue'
export default {
name: 'app',
components: {
Top,
PrimaryAppNav
}
}
</script>
A LoadingScreen.vue component could look like this:
<template>
<div :class="{ loader: true, fadeout: !isLoading }">
Loading ...
</div>
</template>
<script>
export default {
name: "LoadingScreen",
props: ["isLoading"]
};
</script>
<style>
.loader {
background-color: #63ab97;
bottom: 0;
color: white;
display: block;
font-size: 32px;
left: 0;
overflow: hidden;
padding-top: 10vh;
position: fixed;
right: 0;
text-align: center;
top: 0;
}
.fadeout {
animation: fadeout 2s forwards;
}
#keyframes fadeout {
to {
opacity: 0;
visibility: hidden;
}
}
</style>
Be aware that the loader needs to be aware if loading is done to be able to fade out. You need to check that in your App as well, so it's not showing while it still needs to prepare data. Otherwise, information from the app part in the background could be leaking (for example scrollbars might be visible on the LoadingScreen). So App.vue could have a template like this:
<template>
<div id="app">
<LoadingScreen :isLoading="isLoading" />
<div v-if="!isLoading">
...your main content here...
</div>
</div>
</template>
If you want to have the LoadingScreen divs to disappear completely, you need to manage the state of the fadeout animation in the App.vue itself, making it a bit more complicated (I'd probably use two props for LoadingScreen then: isLoading and fadeout, where fadeout is a callback that gets called in LoadingScreen as soon as the fadeout animation is complete).
I have prepared a codesandbox for you with the state management inside the LoadingScreen.
This is a working App.vue with a splash screen:
<template>
<div id="app">
<v-app :light="!nav.dark" :dark="nav.dark">
<transition name="slide-fade" mode="out-in">
<router-view></router-view>
</transition>
</v-app>
<div v-if="loading" style="position:absolute; width: 100%; height:100%; top:0; left:0; z-index:10000; background-color:white">
<div style="margin-left: auto; margin-right: auto">
Loading...
</div>
</div>
</div>
</template>
<script>
export default {
name: "app",
data: () => ({
loading: true
}),
mounted() {
setTimeout(() => {
this.loading = false
}, 3000)
}
}
</script>
Note that there is a z-index trick and mounted is in App component.
You can of course create a component just for loading, so it will become:
App.vue
<template>
<div id="app">
<v-app :light="!nav.dark" :dark="nav.dark">
<transition name="slide-fade" mode="out-in">
<router-view></router-view>
</transition>
</v-app>
<loader v-if="loading"/>
</div>
</template>
<script>
import Loader from "./Loader"
export default {
name: "app",
data: () => ({
loading: true
}),
mounted() {
setTimeout(() => {
this.loading = false
}, 3000)
}
}
</script>
Loader.vue
<template>
<div style="position:absolute; width: 100%; height:100%; top:0; left:0; z-index:10000; background-color:white">
<div style="margin-left: auto; margin-right: auto">
Loading...
</div>
</div>
</template>
<script>
export default {
name: "loader"
}
</script>
After that, I strongly suggest that you use dynamic components for your router components, Top and PrimaryAppNav. Like that they will load during your splash screen. You will find how to do that very easily in my answer in this thread (only section 2 is relevant for you): here
At beginning show fullscreen splash (with class binding listens for loadedApp).
When vuejs mounted, (or your any other process completed then, change data loadedApp = true.
Then fadeoutHide style will run and hides your splash
<div class="fullscreen-splash" :class="{fadeoutHide:loadedApp}">
// splash logo etc
</div>
data() {
return {
loadedApp: false
}
},
mounted() {
this.loadedApp = true
}
.fadeoutHide {
animation: fadeoutHide .5s forwards;
}
#keyframes fadeoutHide {
to {
opacity: 0;
visibility: hidden;
}
}
I have read several examples with the same error but they do not fit my case very well and I can not understand why this error occurs. "Property or method" data "is not defined", if I do it in the first way I have no problem but if I do it as in the second one yes. why?
Thanks so much for any help¡
First Way (This works)
RenderD.vue
<script>
import { Doughnut, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Doughnut,
mixins: [reactiveProp],
props: ['options'],
mounted () {
this.renderChart(this.chartData, {tresponsive: true,
maintainAspectRatio: false})
}
}
</script>
ReactD.vue
<template>
<div class="AngleDisplay">
<div class="row ">
<div class="col-xl-12">
<h2>Angle-Display</h2>
</div>
</div>
<div class="row">
<RenderD :chart-data="datacollection" class="col-xl-12"></RenderD>
</div>
</div>
</template>
<script>
import RenderD from './RenderD'
export default {
components: {
RenderD
},
data () {
return {
datacollection: null
}
},
mounted () {
setInterval(() => {
this.fillData()
}, 100)
},
methods: {
fillData () {
this.datacollection = {
labels: ['Speed', 'Blank'],
datasets: [
{
label: ['Speed', 'Blank'],
backgroundColor: ['#A8201A', '#001427'],
borderColor: '#001427',
data: [this.getRandomInt(), this.getRandomInt()]
}
]
}
},
getRandomInt () {
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
}
}
}
</script>
<style>
</style>
RadarMain.vue
<template>
<div id="RadarMain">
<div class="container-fluid">
<div class="row col-xl-12 title">
<h1 class="col-xl-12 text-center">Arduino-Radar Interface</h1>
</div>
<div class="row col-xl-12 ">
<React class="col-xl-8"></React>
<div class="col-xl-4 ">
<div class="row">
<ReactD :chart-data="data" class="col-xl-12"></ReactD>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import React from './components/React'
import ReactD from './components/ReactD'
export default {
name: 'RadarMain',
components: {
React,
ReactD
},
}
</script>
<style>
body {
background-color: #001427;
color: #FDFFFF;
}
h1 {
margin-top: 50px;
display: block;
}
#media screen and (max-width:1200px) {
.angle-display {
display: none;
}
}
#media screen and (max-width:550px) {
.title {
padding-bottom:50px;
}
}
</style>
Second Way(This don´t works)
ReactD.vue
<script>
import { Doughnut, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
name: 'ReactD',
extends: Doughnut,
mixins: [reactiveProp],
props: ['options'],
components: {
},
data () {
return {
datacollection: {}
}
},
methods: {
fillData () {
this.datacollection = {
labels: ['Speed', 'Blank'],
datasets: [
{
label: ['Speed', 'Blank'],
backgroundColor: ['#A8201A', '#001427'],
borderColor: '#001427',
data: [this.getRandomInt(), this.getRandomInt()]
}
]
}
},
getRandomInt () {
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
}
},
mounted () {
this.renderChart(this.chartData, this.options)
setInterval(() => {
this.fillData()
}, 100)
}
}
</script>
RadarMain.vue
<template>
<div id="RadarMain">
<div class="container-fluid">
<div class="row col-xl-12 title">
<h1 class="col-xl-12 text-center">Arduino-Radar Interface</h1>
</div>
<div class="row col-xl-12 ">
<React class="col-xl-8"></React>
<div class="col-xl-4 ">
<div class="row">
<ReactD :chart-data="datacollection" class="col-xl-12"></ReactD>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import React from './components/React'
import ReactD from './components/ReactD'
export default {
name: 'RadarMain',
components: {
React,
ReactD
}
}
</script>
<style>
body {
background-color: #001427;
color: #FDFFFF;
}
h1 {
margin-top: 50px;
display: block;
}
#media screen and (max-width:1200px) {
.angle-display {
display: none;
}
}
#media screen and (max-width:550px) {
.title {
padding-bottom:50px;
}
}
</style>