Sorry for the heavy text. All of my router-views work, except for one, which shows blank. I do not see any console errors of warnings and the format is identical between views - the only difference is the template. This was working, but I started a new project because my package.json and dependencies got messy. I've read through the code ad nauseum and I just can't work out why it wont show. The code is condensed as there's lots. If you prefer, here's a link to a sandbox: https://codesandbox.io/s/condescending-monad-5o8qw
<template>
<div class="review-movie-detail">
<div class="movie-image">
<img :src="(`https://image.tmdb.org/t/p/original/${movie.poster_path}`)" alt="Movie Poster" />
</div>
<table class="movie-rating-details">
<tr> <h2>{{movie.original_title}}</h2> </tr>
<p> </p>
<tr>Gore rating: <span class="emojiRatings" >{{getGoreEmoji()}} </span></tr>
<tr><input v-model = "goreRating" type="range" min="1" max="100" class="slider" id="myRange"></tr>
<tr> <div class="star-rating"> <star-rating v-model="rating"> </star-rating></div></tr>
<tr><b-button class="block-button">Submit review</b-button></tr>
</table>
</div>
</template>
<script>
import { ref, onBeforeMount } from 'vue';
import env from '#/env.js'
import { useRoute } from 'vue-router';
import StarRating from 'vue-star-rating'
export default {
components : {StarRating},
setup () {
const movie = ref({});
const route = useRoute();
onBeforeMount(() => {
fetch(`https://api.themoviedb.org/3/movie/${route.params.id}?api_key=${env.apikey}`)
.then(response => response.json())
.then(data => {
movie.value = data;
});
});
return {
movie
}
},
data() {
return {
goreRating: '50',
shockRating : '50',
jumpRating: '50',
plotRating: '50',
supernaturalRating: '50',
rating: '3.5'
}
},
methods: {
getGoreEmoji() {
let emojiRating = ["🩸", "🩸🩸", "🩸🩸🩸", "🩸🩸🩸🩸", "🩸🩸🩸🩸🩸", "🩸🩸🩸🩸🩸🩸"]
return emojiRating[(Math.floor(this.goreRating/20))]
},
}
}
and here is my router:
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
import MovieDetail from '../views/MovieDetail.vue'
import ReviewMovie from '../views/ReviewMovie.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/movie/:id',
name: 'Movie Detail',
component: MovieDetail
},
{
path: '/movie/:id/review',
name: 'Review Movie',
component: ReviewMovie
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
and app.Vue to display the router view...
<template>
<div>
<header>
<GoBack />
<router-link to="/">
<h1><span>Horror</span>Hub</h1>
</router-link>
</header>
<main>
<router-view></router-view>
</main>
</div>
</template>
<script>
import GoBack from "#/./components/GoBack"
export default {
components: {
GoBack
}
}
</script>
How can I find the root cause of this issue (pun intended)?
As you are using Vue 3, you need to use vue-star-rating#next
npm install vue-star-rating#next
or
yarn add vue-star-rating#next
in package.json, it should be
"vue-star-rating": "^2.1.0"
and use the new new syntax as well
<star-rating v-model:rating="rating"></star-rating>
Here is the working codesandbox:
https://codesandbox.io/s/little-sea-xccm4?file=/src/views/ReviewMovie.vue
Related
My vuejs version is 3.
I implement both of these ways to use keep-alive in my app.
1
<template>
<div id="nav" classs="container is-max-desktop"></div>
<keep-alive>
<router-view />
</keep-alive>
</template>
<style>
#import "~bulma/css/bulma.css";
</style>
2
import { createRouter, createWebHistory } from "vue-router";
import Index from "../views/Index.vue";
import Create from "../views/Create.vue";
import Edit from "../views/Edit.vue";
const routes = [
{
name: "Index",
path: "/",
component: Index,
meta: { KeepAlive: true },
},
{
name: "Edit",
path: "/edit/:id",
component: Edit,
meta: { KeepAlive: true },
},
{
name: "Create",
path: "/create",
component: Create,
meta: { KeepAlive: true },
},
{
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue"),
},
];
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
});
export default router;
Simply, I apply many filters on my page but when I came back to that page they are gone. Help me to solve this problem. Thank you.
Keep alive caches components when dynamically switching them which will retain the data's in that particular component while switching. Use the below code for integration,
Maincomponent.vue
<script>
import Component1 from './Component1.vue'
import Component2 from './Component2.vue'
export default {
components: { Component1, Component2 },
data() {
return {
current: 'Component1'
}
}
}
</script>
<template>
<div class="demo">
<label><input type="radio" v-model="current" value="Component1" /> A</label>
<label><input type="radio" v-model="current" value="Component2" /> B</label>
<KeepAlive>
<component :is="current"></component>
</KeepAlive>
</div>
</template>
Component1.vue
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
<template>
<div>
<p>Current component: A</p>
<span>count: {{ count }}</span>
<button #click="count++">+</button>
</div>
</template>
Component2.vue
<script>
export default {
data() {
return {
msg: ''
}
}
}
</script>
<template>
<div>
<p>Current component: B</p>
<span>Message is: {{ msg }}</span>
<input v-model="msg">
</div>
</template>
I'm using VueJS 3 applications using vue-router, vue and core-js applications where I want using compoments. I have in views dirrectory Home.vue file which looks like this:
<template>
<div class="wrapper">
<section v-for="(item, index) in items" :key="index" class="box">
<div class="infobox">
<PictureBox image="item.picture" />
<PropertyBox itemProperty="item.properties" />
</div>
</section>
</div>
</template>
<script>
import { ref } from 'vue'
import { data } from '#/data.js'
import { PictureBox } from '#/components/PictureBox.vue'
import { PropertyBox } from '#/components/PropertyBox.vue'
export default {
components: {
PictureBox,
PropertyBox,
},
methods: {
addRow() {
console.log('This add new row into table')
},
},
setup() {
const items = ref(data)
return {
items,
}
},
}
</script>
I have 2 compoments in compoments directory
src/compoments
|- PictureBox.vue
|- PropertyBox.vue
and for example in PictureBox.vue I have this content:
<template>
<div class="infobox-item-picturebox">
<img class="infobox-item-picturebox-image" :src="require(`#/static/${image}`)" alt="item.title" />
</div>
</template>
<script>
import { reactive, toRefs } from 'vue'
export default {
props: {
image: {
type: String,
},
},
setup() {
const state = reactive({
count: 0,
})
return {
...toRefs(state),
}
},
}
</script>
But I have Warning at compiling:
WARNING Compiled with 2 warnings 10:58:02 PM
warning in ./src/views/Home.vue?vue&type=script&lang=js
"export 'PictureBox' was not found in '#/components/PictureBox.vue'
warning in ./src/views/Home.vue?vue&type=script&lang=js
"export 'PropertyBox' was not found in '#/components/PropertyBox.vue'
App running at:
- Local: http://localhost:8080/
- Network: http://172.19.187.102:8080/
Also in Browser Developer mode I have same warnings:
My Directory structure looks like this:
And my main.js looks like here:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import './assets/style.css'
createApp(App).use(router).mount('#app')
And router page (I'm not using router actually looks like here)
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home,
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes,
})
export default router
Please, can you help me why I have this warning and my content from <template> in PictureBox or in PropertyBox was not loaded? Thank you so much for any advice
The component instance is exported as default (export default {...) in its single file and it should be imported like :
import PictureBox from '#/components/PictureBox.vue'
instead of:
import { PictureBox } from '#/components/PictureBox.vue'
I have a main app page component with a search bar. The Search results that come back is in cards And I am looking to set up a "Click here to view more detail" that would be placed in each card. And it would link to the Details page of the one result clicked. How do I link these components on Vue and if the id could be passed? I am hoping that upon click of the button the component renders on the same page and not a new tab.
Thank you!
App.vue
<template>
<div id="app">
<Header/>
<SearchForm v-on:search="search"/>
<SearchResults
v-if="results.length > 0"
v-bind:results="results"
v-bind:reformattedSearchString="reformattedSearchString"/>
<Pagination
v-if="results.length > 0"
v-bind:prevPageToken="api.prevPageToken"
v-bind:next_page="api.scrollId"
v-on:prev-page="prevPage"
v-on:next-page="nextPage"
/>
</div>
</template>
<script>
import Header from './components/layout/Header';
import SearchForm from './components/SearchForm';
import SearchResults from './components/SearchResults';
import Pagination from './components/Pagination';
import Details from './components/Details'
import axios from 'axios';
export default {
name: 'app',
components: {
Header,
SearchForm,
SearchResults,
Pagination,
Details
},
data() {
return {
results: [],
reformattedSearchString: '',
api: {
baseUrl: 'https://test.org/api/v1/articles?',
max: 25,
q: '',
prevPageToken: '',
scrollId: ''
}
};
},
methods: {
search(searchParams) {
this.reformattedSearchString = searchParams.join(' ');
this.api.q = searchParams.join('+');
const { baseUrl, q, max} = this.api;
const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&recent&max=${max}&full_results`;
this.getData(apiUrl);
},
prevPage() {
const { baseUrl, q, max, prevPageToken } = this.api;
const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&max=${max}&pageToken=${prevPageToken}`;
this.getData(apiUrl);
},
nextPage() {
const { baseUrl, q, max,scrollId } = this.api;
const apiUrl = `${baseUrl}&term=${q}&title_like=${q}&max=${max}&recent&full_results&scroll_id=${scrollId}`;
this.getData(apiUrl);
},
getData(apiUrl) {
axios
.get(apiUrl)
.then(res => {
this.results = res.data.success.data;
this.api.prevPageToken = res.data.success.data.prevPageToken;
this.api.next_page = res.data.scrollId;
})
.catch(error => console.log(error))
}
}
};
</script>
Searchresults.vue
<template>
<div class="container mb-3">
<div class="d-flex mb-3">
<div class="mr-auto">
<h3>Search Results for "{{ reformattedSearchString }}"</h3>
</div>
<div class="btn-group ml-auto" role="group">
<button
#click="changeDisplayMode('grid')"
type="button"
class="btn btn-outline-secondary"
v-bind:class="{ active: displayMode === 'grid' }"
>
<i class="fas fa-th"></i>
</button>
<button
#click="changeDisplayMode('list')"
type="button"
class="btn btn-outline-secondary"
v-bind:class="{ active: displayMode === 'list' }"
>
<i class="fas fa-list"></i>
</button>
</div>
</div>
<div class="card-columns" v-if="displayMode === 'grid'">
<div class="card" v-bind:key="result._gddid" v-for="result in results">
<ArticleGridItem v-bind:result="result"/>
</div>
</div>
<div v-else>
<div class="card mb-2" v-bind:key="result._gddid" v-for="result in results">
<ArticleListItem v-bind:result="result"/>
</div>
</div>
</div>
</template>
<script>
import ArticleListItem from './ArticleListItem';
import ArticleGridItem from './ArticleGridItem';
import Details from './Details';
export default {
name: 'SearchResults',
components: {
ArticleListItem,
ArticleGridItem,
Details,
},
data() {
return {
title: 'Search Results',
displayMode: 'grid'
};
},
methods: {
changeDisplayMode(displayMode) {
this.displayMode = displayMode;
}
},
props: ['results', 'reformattedSearchString']
};
</script>
ArticleListItem.vue
<template>
<div>
<div class="card-body">
<h6 class="card-text">{{ result.title }}</h6>
<p
class="card-subtitle mb-2 text-muted"
>{{ result.publisher }} | {{ result.journal }} | {{ result.year }}</p>
<a :href="'https://test.org/api/articles?docid=' + result._gddid" target="_blank">
<i class="fa fa-download" alt="Download"> </i>
</a>
<router-link>
<v-btn dark to="{name:'Details', params: {id: article._gddid}}">
Click here for more Details
</v-btn>
</router-link>
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'ArticleListItem',
props: ['result'],
}
</script>
index.js
import Vue from 'vue';
import Router from 'vue-router';
import Details from '#/components/Details';
Vue.use(Router)
export default new Router({
routes: [
{
path: '/Details/:id',
name: 'Details',
component: Details
}
]
});
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router/index.js'
import moment from 'moment'
Vue.config.productionTip = false
Vue.filter('formatDate', function (value) {
if (!value) return ''
return moment(value.toString()).format('MM/DD/YYYY hh:mm')
})
new Vue({
router,
render: h => h(App),
}).$mount('#app')
use <router-link> tag for it to work
When using Vue Router, instead of using <a> tags, you can use <router-link> tags.
Here's a basic example similar to the Vue Router documentation for dynamic route matching.
If you have this...
const router = new VueRouter({
routes: [
{ path: '/Details/:id', component: DetailsPage, name: 'Details' }
]
})
You can have router-links declared in, say, your ArticleListItem.vue file like:
<v-btn dark to="{name:'Details', params: {id: article.id}}">
Click here for more Details
</v-btn>
You can't just go to a generic details page. There needs to be some dynamic part of the route (which I've called id in my example) to specify which article's page to go to.
Edit
An additional problem is in your Router setup:
From the Vue Router docs:
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
...needs to be in your main.js file. The declaration of Vue.use in your index.js file isn't doing anything. Just for conciseness. Make it one file:
WhateverYourOneTrueFileIsGoingToBeCalled.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import Details from '#/components/Details';
import moment from 'moment'
Vue.config.productionTip = false
Vue.filter('formatDate', function (value) {
if (!value) return ''
return moment(value.toString()).format('MM/DD/YYYY hh:mm')
})
Vue.use(VueRouter)
router = new VueRouter({
routes: [
{
path: '/Details/:id',
name: 'Details',
component: Details
}
]
})
new Vue({
router,
render: h => h(App),
}).$mount('#app')
I am learning VueJs and trying to understand how to extract route params via props.
I was looking at the following documentation, where it seems to have three options to have this done, but I cannot understand it quite well so far - https://github.com/vuejs/vue-router/tree/dev/examples/route-props.
I have tried adding props: true to my router object array (routes.js file posted below) with no success as well.
As this is vue-cli study project I will post the separate pertinent blocks of code in order to try to illustrate this properly.
Main - App.vue below:
<template>
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
<h1>Routing</h1>
<hr>
<app-header></app-header>
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import Header from './components/Header.vue'
export default {
components: {
appHeader: Header
}
}
</script>
<style>
</style>
Component - Header.vue below:
<template>
<ul class="nav nav-pills">
<router-link to="/" tag="li" active-class="active" exact><a>Home</a></router-link>
<router-link to="/user/10" tag="li" active-class="active"><a>User 1</a></router-link>
<router-link to="/user/5" tag="li" active-class="active"><a>User 2</a></router-link>
</ul>
</template>
Component - User.vue below:
<template>
<div>
<h1>The User Page</h1>
<hr>
<br>
<p>Route ID: {{id}}</p>
<button class="btn btn-primary" #click="goHome">Go to Home</button>
</div>
</template>
<script>
export default {
data(){
return {
id: this.$route.params.id
}
},
watch: {
'$route'(to, from) {
this.id = to.params.id;
}
},
methods: {
goHome(){
this.$router.push('/')
}
}
}
</script>
main.js below:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
import {routes} from "./routes";
Vue.use(VueRouter)
export const router = new VueRouter({
routes,
mode: 'history'
})
new Vue({
el: '#app',
router,
render: h => h(App)
})
routes.js below (located at SRC folder):
import User from './components/user/User.vue'
import Home from './components/Home.vue'
export const routes = [
{path: '', component: Home},
{path: '/user/:id', component: User}
]
Do I need to also set Props at User.vue component as well in order to make it work and quit using watch?
In other words, I would like to see my user route being listened at <p>Route ID: {{id}}</p> from this hardcoded 10 to 5 using this new method which I cannot understand, mentioned at the top of this post.
Could anyone please walk me through this issue in this specific situation?
Thanks in advance to all.
According to the docs on passing Props to Route components, you can decouple it, with the props option on the router config.
import User from './components/user/User.vue'
import Home from './components/Home.vue'
export const routes = [
{path: '', component: Home},
{path: '/user/:id', component: User, props: true}
]
<template>
<div>
<h1>The User Page</h1>
<hr>
<br>
<p>Route ID: {{id}}</p>
<button class="btn btn-primary" #click="goHome">Go to Home</button>
</div>
</template>
<script>
export default {
props: ['id'],
methods: {
goHome() {
this.$router.push('/')
}
}
}
</script>
The name is defined in all my component instances with the correct capitalisation but I still get the error, I've found many similar problems online but the problem always seems to be with the name, however I'm 100% sure all my components have exactly the same name as those in the routes.js folder. Anyone have any ideas for possible solutions? Thanks.
App.vue
<template>
<div id="app">
<router-link to="/search"></router-link>
<router-view> </router-view>
</div>
</template>
<script>
import Search from './components/Search.vue';
import Apod from './components/Apod.vue';
import News from './components/News.vue';
import NotFound from './components/NotFound.vue';
export default {
name: 'app',
components: {
NotFound: NotFound,
Search: Search,
Apod: Apod,
News: News
}
}
</script>
main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
Vue.config.productionTip = false
new Vue({
el: '#app',
router: VueRouter,
render: h => h(App),
}).$mount('#app')
index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Apod from '#/components/Apod';
import Search from '#/components/Search';
import News from '#/components/News';
import NotFound from '#/components/NotFound';
Vue.use(VueRouter)
export default new VueRouter({
routes: [
{
path: '/apod',
name: 'Apod',
component: Apod,
},
{
path: '/search',
name: 'Search',
component: Search,
},
{
path: '/news',
name: 'News',
component: News,
}
]
})
Search.vue
<template>
<div class="search">
<h2> Search: </h2>
<h5>Home</h5>
<form v-on:submit.prevent="getResult(query)">
<input type="text" placeholder="search" v-model="query"/>
</form>
<div class="wrapper">
<div class="results" >
<div class="row" v-for="(r, index) in Math.ceil(results.length / 4)" v-if="index <= 3">
<span class="result" v-for="result in results.slice((r - 1) * 4, r * 4)">
<img :src="result.links[0].href" :alt="result.data[0].keywords[0]"/>
<p class="text"> {{ result.data[0].title }} </p>
</span>
</div>
</div>
</div>
</div>
import axios from 'axios';
export default {
name: 'Search',
data() {
return {
query: '',
results: ''
}
},
methods: {
getResult(query) {
axios.get('https://images-api.nasa.gov/search?q=' + query + '&media_type=image')
.then(response => {
this.results = response.data.collection.items;
console.log(response);
});
}
}
}
In main your should write:
import Vue from 'vue'
import App from './App.vue'
import VueRouter from './path-to-your-router-init-file';
Vue.config.productionTip = false
new Vue({
el: '#app',
router: VueRouter,
render: h => h(App),
}).$mount('#app')