I am completely stuck on getting a component to render through router-view using the vue.js 2.0 and vue-router.
I have vue devtools installed and I do see the "fragment" label next to router-view, but no other details.
Might be important to note that I am using laravel-elixir-vueify and browserify.
App.js
var Vue = require('Vue');
var VueRouter = require('vue-router');
import dashboard from './components/dashboard.vue'
Vue.component('dashboard', dashboard);
Vue.use(VueRouter);
const router = new VueRouter({
routes: [
{ path: '/', component: dashboard }
]
const app = new Vue({
router
}).$mount('#vueapp')
dashboard.blade.php
<div id="vueapp">
//other code removed for space
<router-view></router-view>
</div>
dashboard.vue
<template>
<div class="col-md-12 col-lg-12">
<div class="block">
<div id="showCalendar"></div>
</div>
</div>
</template>
//Note: I tried adding an extra <div></div> within the template, but that didn't make a difference.
<script>
export default{
mounted: function() {
this.CompCalendar();
},
methods: {
CompCalendar: function() {
/* Initialize FullCalendar */
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
this.$nextTick(function() {
var events = this.$http.get('/events/local/index')
.then(function(response){
$('#showCalendar').fullCalendar({
header: {
//unimportant options
},
//unimportant options
eventClick: function(calEvent, jsEvent, view){
var eventId = calEvent.id;
router.push({
path: 'details/'+eventId
});
},
});
})
});
}
}
};
</script>
So the first thing, you dont need to register Vue.component('dashboard', dashboard)
The Reference to in the routes is enough.
Everything else looks good for me. Do you have any Errors in your console?
Try routes = [ { path: '', component ..
It seems like you haven't registered any component for this action
router.push({
path: 'details/'+eventId
});
It seems like you need something like that in your router:
{ path: '/details', component: Details }
Related
I have a small app in Vue 3 which I list data from a local json file and then click over to a detail page to view the rest of the data. I am able to list all the data and link to a detail page, but I cannot seem to figure out how to show the data of just the single id.
router/index.js
...
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'Ndas',
component: Ndas
},
{
path: '/nda/:id',
name: 'NdaDetails',
component: NdaDetails,
props: true
}
]
})
...
views/Ndas.vue -- This Works
<template>
<main>
<h1>NDAS</h1>
<div v-if="loading">Loading...</div>
<div v-for="nda in ndas" :key="nda.id">
<router-link :to="{ name: 'NdaDetails', params: { id: nda.id }}">
<h2>{{ nda.user_signature }}</h2>
</router-link>
</div>
</main>
</template>
<script>
import axios from "axios";
export default {
data() {
return {
loading: true,
ndas: []
}
},
mounted () {
this.loading = true;
axios
.get('../../data/data.json')
.then(response => (this.ndas = response.data))
.catch(error => console.log(error))
.finally(() => this.loading = false)
},
}
</script>
views/NdaDetails.vue -- This Doesn't Work
<template>
<div>
<div v-if="nda">
<h1>NDA's Detail Page</h1>
<p>The job title is {{ nda.user_signature }}</p>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
props: ['id'],
data() {
return {
nda: {}
}
},
async created() {
try {
const res = await axios.get('../../data/data.json/'+this.id);
this.nda = res.data;
} catch (error) {
console.log(error);
}
},
}
</script>
UPDATE: OP fixed the issue by serving his JSON file with a server, now it's working great.
Here, you probably want something like this rather than a prop
const res = await axios.get('../../data/data.json/' + this.$route.params.id)
Props are used in a child/parent content, to pass some state down.
Here, you can access the value of your URL directly (router being global) and remove the props part.
I want to have a dynamic/async component which will be loaded based on menu click. There will be a lot of links and components.
My problem is :
Cannot find test-component even I registered globally using Vue.Component
Can the component1 in root be changed? If it is possible, I will call component file using Ajax.
Thanks in advance.
Index.html
<script src="~/bundle/site.js"></script>
<div id="app">
<input type="button" v-on:click="changeComponent('test-component')" value="Click me"/>
<component v-bind:is="view"></component>
</div>
site.js
import Vue from 'vue';
import axios from 'axios';
global.Vue = Vue;
global.axios = axios;
var vm = new Vue({
el: '#app',
data: {
view: 'component1'
},
components: {
'component1': {
template: '<div>Dynamic Component master</div>'
}
},
methods: {
changeComponent: function (parComp) {
this.component1 = parComp;
},
}
});
Vue.component('test-component', {
template: '<div v-on:click = "changeName()"><h1>{{msg}}</h1></div>',
data: function () {
return {
msg: "Test Componet"
}
},
methods: {
changeName: function () {
this.msg = "mouse clicked";
},
}
})
Update
change vm = new Vue().... to global.vm = new Vue().....
call vm.changeComponent('test-component')
It works now.
Vue.options.components["test-component"] can access it.
But test-component cannot be access in html like :
<test-component></test-component>
The problem solved by :
change vm = new Vue().... to global.vm = new Vue().....
declare Vue.component('test-component'.... before new Vue()
Thanks
Wilson
I'm using async components in my code on CodeSandbox (seen below). When I click on goto product-2 after goto product-1, nothing happens. I expected the <product-item> component to change based on the clicked component, but only the URL changes. I even have a beforeRouteUpdate hook function. How do I fix this?
// main.js
import Vue from "vue";
import App from "./App.vue";
import VueRouter from 'vue-router';
import ProductPage from './product-page.vue';
Vue.use(VueRouter);
Vue.config.productionTip = false;
const routes = [
{ path: '/:productId', component: ProductPage },
]
const router = new VueRouter({
routes // short for `routes: routes`
})
new Vue({
router,
render: h => h(App)
}).$mount("#app");
// App.vue
<template>
<div id="app">
<router-link to="/product-1">goto product1</router-link>
<br>
<br>
<router-link to="/product-2">goto product2</router-link>
<div>Router view:</div>
<router-view :key="$route.params.productId"></router-view>
</div>
</template>
// product-page.vue
<template>
<div>
<product-item></product-item>
</div>
</template>
<script>
export default {
name: "product-page",
components: {
ProductItem: () => ({
component: import("./product-item.vue"),
loading: { template: "<div>loading....</div>" }
})
}
};
</script>
<template>
<div>
product item: {{product}}
</div>
</template>
<script>
export default {
name: "ProductItem",
mounted: function () {
this.product = this.$route.params.productId;
},
beforeRouteUpdate: function(to, from, next) {
this.product = to.params.productId;
next();
},
data: function () {
return {
product: null
}
},
};
</script>
The problem is the route path (i.e., /:productId) does not actually change between the links for /product-1 and /product-2 (even though the parameter values do), so router-view does not re-render.
The workaround is to key the router-view based on the productId parameter:
<router-view :key="$route.params.productId" />
I am trying to integrate Phaser 3 with Vue.js 2.
My goal is to create a Vue.js component associated with a game canvas.
My initial solution was:
<template>
<div :id="id">
</div>
</template>
<script>
import Phaser from 'phaser'
export default {
data () {
return {
id: null,
game: null
}
},
mounted () {
this.id = 'game' + this._uid
var config = {
parent: this.id,
type: Phaser.CANVAS
}
this.game = new Phaser.Game(config)
....
}
}
</script>
This code attach the game canvas to my template. But to my surprise it only worked 'sometimes'.
I figured out, after hours of debugging, that my div element in the DOM wasn't updated with the id when I was instantiating my new Game.
So I came up with the solution of instantiating the id in the beforeMount () method as follow:
<template>
<div :id="id">
</div>
</template>
<script>
import Phaser from 'phaser'
export default {
data () {
return {
id: null,
game: null
}
},
beforeMount () {
this.id = 'game' + this._uid
},
mounted () {
var config = {
parent: this.id,
type: Phaser.CANVAS
}
this.game = new Phaser.Game(config)
....
}
}
</script>
It is working, but I would like to know if there is a more simple and elegant solution ?
One better solution for integrating Phaser.Game into the application is directly passing the config the HTML element, a configuration supported by Phaser.Game.
To get a reference to a HTML element in vue, you can use refs, these are basically id's, but local to the component itself, so there is not risk in creating conflicts.
<template>
<div ref="myDiv">
</div>
</template>
<script>
import Phaser from 'phaser'
export default {
data () {
return {
game: null
}
},
mounted () {
var config = {
parent: this.$refs.myDiv,
type: Phaser.CANVAS
}
this.game = new Phaser.Game(config)
....
}
}
</script>
Vue3 sample:
<script setup>
import { ref,onMounted } from 'vue';
import Phaser from 'phaser'
const myDiv = ref(null)
let canvasWidth = 750;
let canvasHeight = 1450;
onMounted(() => {
const config = {
type: Phaser.AUTO,
parent: popWrap.value,
width: canvasWidth,
height: canvasHeight,
scene: {
preload: preload,
create: create,
update: update
}
};
const game = new Phaser.Game(config);
})
</script>
<template>
<div ref="myDiv">
</div>
</template>
<template>
<div id="app">
<Loading></Loading>
<Content></Content>
</div>
</template>
<script>
import Loading from './Loading.vue'
import Content from './Content.vue'
export default {
name: 'App',
components: {
Loading,
Content
}
}
</script>
What is the best and elegant way to handle a loading component and remove it (or vue component or change styles) when all page is loaded?
I tried with v-cloack, but I think its not working beyond data stuff.
I tried with mounted, but doesn't seems to work.
v-cloak is to hide un-compiled mustache bindings until the Vue instance is ready. So you can use v-if to show/hide loading component.
var child1 = Vue.extend({
template: "<div>Loading...</div>"
});
var child2 = Vue.extend({
template: "<div>After Component loaded</div>",
});
var app = new Vue({
el: "#vue-instance",
data: {
loading: true
},
mounted() {
var vm = this;
setTimeout(function() {
vm.loading = false;
}, 1000);
},
components: {
child1,
child2
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.1/vue.js"></script>
<div id="vue-instance">
<child1 :name="name" v-if="loading"></child1>
<child2 :name="name" v-if="!loading"></child2>
</div>