I'm actually a beginner in Javascript and vue.js.
I followed a tutorial to create a shopping single page application and i learned about router so i wanted to use them on this learning project.
I got some interestiong errors in the console.
Can someone explain me where am i doing something wrong?
index.html:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id = "app">
<h1>Shopping Cart</h1>
<ul>
<li v-for="item in shoppingCart">
{{ item.label }} {{ item.cost }} euros
{{ isSelected(item) }}
</li>
<p>total = {{ getTheTotal }} euros</p>
</ul>
<li v-for="item in shoppingCart">
<router-link to="item.link"><img v-if= "item.selected == true"width="150" height="100" :src="item.url"></img></router-link>
</li>
<router-view></router-view>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src = "vue.js"></script>
</body>
</html>
and the vue.js:
const Bananas = { template: '<div>in bananas</div>' }
const Apples = { template: '<div>in apples</div>' }
const Pears = { template: '<div>in apples</div>' }
const Cars = { template: '<div>in apples</div>' }
const router = new VueRouter ({
routes: [
{ path: '/bananas', component: Bananas },
{ path: '/apples', component: Apples },
{ path: '/pears', component: Pears },
{ path: '/cars', component: Cars }
]
})
const app = new Vue ({
el: "#app",
data: {
shoppingCart: [
{ label: "Apples", cost: 2, selected: false, url: 'https://i2.wp.com/ceklog.kindel.com/wp-content/uploads/2013/02/firefox_2018-07-10_07-50-11.png', link: "/apples" },
{ label: "Pears", cost: 3, selected: false, url: 'https://post.healthline.com/wp-content/uploads/2018/11/10617-Do_You_Have_a_Pear_Allergy-_732x549-thumbnail.jpg', link: "/pears" },
{ label: "Bananas", cost: 5, selected: false, url: 'https://media.lactualite.com/2014/08/banane.jpg',link: "/bananas" },
{ label: "Cars", cost: 5000, selected: false, url: 'https://specials-images.forbesimg.com/imageserve/5d3703e2f1176b00089761a6/960x0.jpg?cropX1=836&cropX2=5396&cropY1=799&cropY2=3364', link: "/cars" }
]
},
computed: {
getTheTotal() {
let rez = 0
this.shoppingCart.forEach(element => {
if (element.selected == true) {
rez += element.cost
}
console.log(rez)
})
return rez
}
},
methods: {
addItem: function(item) {
if (item.selected == false)
item.selected = true
else if (item.selected == true)
item.selected = false
},
isSelected: function(item) {
if (item.selected == true)
return ("remove")
if (item.selected == false)
return ("add")
}
}
}).$mount('#app')
the errors:
[Vue warn]: Error in render: "TypeError: Unable to get property 'matched' of undefined or null reference"
(found in <Root>)
TypeError: Unable to get property 'matched' of undefined or null reference
[Vue warn]: Cannot find element: #app
[Vue warn]: Error in render: "TypeError: Unable to get property 'matched' of undefined or null reference"
(found in <Root>)
TypeError: Unable to get property 'matched' of undefined or null reference
the page doesn't display anything anymore.
Thanks a lot! :)
i'm also a beginner on stack overflow so feel free to tell me if my post is wrong
You didn't pass the router object to the new Vue call so the app is unaware of the router / routes:
const app = new Vue ({
router, // ✅ Add this
el: "#app",
...
});
You also need to use a : binding on the <router-link> to attribute as follows:
<router-link :to="{ path: item.link }">
<img v-if="item.selected" width="150" height="100" :src="item.url">
</router-link>
And fix your data (3 out of 4 say "apples"):
const Bananas = { template: '<div>in bananas</div>' }
const Apples = { template: '<div>in apples</div>' }
const Pears = { template: '<div>in pears</div>' }
const Cars = { template: '<div>in cars</div>' }
You need to call Vue.use(router) before you declare your Vue instance.
Related
I'm trying to toggle between the 2 images by triggering a function on click event, as shown below, how do I apply the same idea to different list items to toggle the images individually for each item? right now, all the list items same image because of one global value i.e val
var app = new Vue({
el: '#app',
data: function() {
return {
val:true,
selectedImg:"",
checked: "#/assets/images/check.png",
unchecked: "#/assets/images/uncheck.png",
items: [
{ message: 'laundry' },
{ message: 'cooking' },
{ message: 'cleaning'}
]
}
},
methods: {
myfunc () {
this.val = (this.val === true ? false : true)
if(this.val === true) {
this.selectedImg = this.checked
} else {
this.selectedImg = this.unchecked
}
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in items" :key="item.message">
<button #click="myfunc"><img :src="selectedImg"/></button>
{{ item.message }}
</li>
</ul>
</div>
You should move selectedImg and val into items objects and pass item to myfunc function.
You can also look at the answer in codepen.
var app = new Vue({
el: '#app',
data: function() {
return {
checked: "#/assets/images/check.png",
unchecked: "#/assets/images/uncheck.png",
items: [
{ message: 'laundry', selectedImg:"" , val:true},
{ message: 'cooking', selectedImg:"", val:true},
{ message: 'cleaning', selectedImg:"", val:true}
]
}
},
methods: {
myfunc (item) {
item.val = (item.val === true ? false : true)
if(item.val === true) {
item.selectedImg = this.checked
} else {
item.selectedImg = this.unchecked
}
},
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul>
<li v-for="item in items" :key="item.message">
<button #click="myfunc(item)"><img :src="item.selectedImg"/></button>
{{ item.message }}
</li>
</ul>
</div>
I have a SPA where I show array of pokemon using v-for, with the option to filter those lists by type or generation. I have a button that clears the filters (sets the type to '' and generation to generation 1), but the v-for loop doesn't re-render the array after the filters are cleared. I've logged the function that returns the array of pokemon to confirm it's working, but Vue JS doesn't render the results. I'm not sure how to proceed.
<div class="pokemon"
v-for="pokemon in filteredPokemon"
:key="pokemon.id">
<h2>{{ pokemon.name }}</h2>
</div>
<script>
import Pokemon from '../pokeData'
export default{
props: ['searchFilters'],
data(){
return{
allPokemon: [],
}
},
created(){
this.allPokemon = Pokemon.getPokemon('gen1');
},
computed: {
filteredPokemon: function(){
if(this.searchFilters.type){
if(this.searchFilters.type === ''){
return this.allPokemon
}
return this.allPokemon.filter(pokemon => {
if(pokemon.types.length === 2){
if(pokemon.types[0].type.name == this.searchFilters.type || pokemon.types[1].type.name == this.searchFilters.type){
return true
}
}
else if(pokemon.types[0].type.name == this.searchFilters.type){
return true
}
})
}
return this.allPokemon
}
},
watch:{
'searchFilters.generation': function(generation){
this.allPokemon = Pokemon.getPokemon(generation)
}
}
}
}
</script>
farincz is right, you are changing the attributes of allPokemon with the function call to getPokemon and Vue.JS can't find the change (documentation), therefore it's a caveat and you would need to handle this in a different way because Vue doesn't support the way you want it.
I would filter all pokemons with a filter method with a computed value and bind the filter value to a data property:
HTML:
<template>
<div>
<textarea v-model="text" name="filter" cols="30" rows="2"></textarea>
<div class="pokemon" v-for="pokemon in filteredPokemon" :key="pokemon.id">
<h2>{{ pokemon.name }}</h2>
</div>
</div>
</template>
JS file:
new Vue({
el: "#app",
data(){
return{
text: '',
pokemons: [
{gen: 'gen1', name: 'psyduck', id: '1'},
{gen: 'gen1', name: 'charizard', id: '2'},
{gen: 'gen1', name: 'pikachu', id: '3'},
{gen: 'gen2', name: 'togapi', id: '4'}
]
}
},
computed: {
filteredPokemon() {
if(this.text === '') return this.pokemons
return this.pokemons.filter(x=>x.gen === this.text)
}
}
})
here's the jsfiddle to play around.
Hello all and thank you very much.
This is my first try with vue.js and I cant get the example working.
this is the error i am getting
vue.runtime.esm.js:620 [Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
What does compile mean? It's seems like a valid ES5. I am using the rollup-plugin-vuehere. What option should I use to get the compiled components. or am I trying to connect to the DOM incorrectly?
Thank you very much :)
var ListItem = Vue.component('ListItem', {
data: function () {
return {
title: ''
}
},
addNewItem: function() {
if(this.newItem.trim().length > 0) {
this.items.push(this.newItem);
this.newItem = "";
}
},
template: `
<div class="list-item">
{{ title }}
</div>
`
});
var DynamicList = Vue.component('DynamicList', {
data: function () {
return {
title: '',
newItem: '',
items: []
}
},
addNewItem: function() {
if(this.newItem.trim().length > 0) {
this.items.push(this.newItem);
this.newItem = "";
}
},
template: `
<div class="dynamic-list">
<h3>{{ title }}</h3>
<div>
<input type="text" v-model="newItem">
<input type="button" >
</div>
<ListItem
v-for="item in items"
v-bind:key="item"
v-bind:title="title"
></ListItem>
</div>
`
});
new Vue({
el: "#vue-container",
data: {},
render: h => h(DynamicList),
});
Bare-bones example from another post...
new Vue({
el: '#app',
data: {
filters: {
id: '',
issuedBy: '',
issuedTo: ''
},
items: [{id:1234,issuedBy:'Operator',issuedTo:'abcd-efgh'},{id:5678,issuedBy:'User',issuedTo:'ijkl-mnop'}]
},
computed: {
filtered () {
const filtered = this.items.filter(item => {
return Object.keys(this.filters).every(key =>
String(item[key]).includes(this.filters[key]))
})
return filtered.length > 0 ? filtered : [{
id: '',
issuedBy: '',
issuedTo: ''
}]
}
}
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css"/><link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.css"/><script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.min.js"></script><script src="//unpkg.com/babel-polyfill#latest/dist/polyfill.min.js"></script><script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.js"></script>
<div id="app">
<b-table striped show-empty :items="filtered">
<template slot="top-row" slot-scope="{ fields }">
<td v-for="field in fields" :key="field.key">
<input v-model="filters[field.key]" :placeholder="field.label">
</td>
</template>
</b-table>
</div>
Now I get how this works, but I am also integrating apollo for a graphql query. I have apollo populate items..
So I add apollo and a mounted (to block)
new Vue({
el: '#app',
apollo: {
searchPersons: GET_PERSON
},
data: {
filters: {
name: '',
location: '',
relocate: ''
},
},
computed: {
filtered () {
const filtered = this.items.filter(item => {
return Object.keys(this.filters).every(key =>
String(item[key]).includes(this.filters[key]))
})
return filtered.length > 0 ? filtered : [{
name: '',
location: '',
relocate: ''
}]
}
},
mounted: function () {
this.$apollo.queries.searchPersons.refetch().then((results) => {
this.totalRows = results.data.searchPersons.length
this.items = results.data.searchPersons
})
},
})
here is my GET_PERSON graphql if you were wondering
import { gql } from "apollo-boost";
export const GET_PERSON = gql`
query {
searchPersons(keyword: "", fromSource: false){
name
location
relocate
currentSalary
resumeBody
personemailSet {
email
}
personphoneSet {
phoneType
verified
number
}
personskillsSet {
term
score
weight
}
personresumeattachmentSet {
attachment
}
personworkplacepreferenceSet{
name
label
}
}
}
`;
So what happens is, the table tries to load (which is fine), but its trying to filter and grab the data before it has been returned so i am left with an error of
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in render: "TypeError: Cannot read property 'filter' of undefined"
and honestly I feel like mounted may not be the right way to do this?
I appreciate any help.
Thanks!
So iitially define it as an empty array.
data: {
filters: {
name: '',
location: '',
relocate: ''
},
items : []
//---^-----
},
I'm implementing Vue paper dashboard sidebar. So I have something like this:
Into Index I have
<template>
<div>
AdminIndex
<side-bar>
</side-bar>
</div>
</template>
<script>
import { faBox, faImages } from '#fortawesome/fontawesome-free-solid';
import Sidebar from '#/components/sidebar/SideBar';
export default {
name: 'admin-index-view',
components: {
SideBar,
},
data() {
return {
showSidebar: false,
sidebarLinks: [
{
name: 'admin.menu.products',
icon: faBoxes,
route: { name: 'adminProducts' },
},
{
name: 'admin.menu.sliders',
icon: faImages,
route: { name: '/admin/stats' },
},
],
};
},
methods: {
displaySidebar(value) {
this.showSidebar = value;
},
},
};
</script>
SideBar component:
<template>
<div :class="sidebarClasses"
:data-background-color="backgroundColor"
:data-active-color="activeColor">
<!--
Tip 1: you can change the color of the sidebar's background using: data-background-color="white | black | darkblue"
Tip 2: you can change the color of the active button using the data-active-color="primary | info | success | warning | danger"
-->
<!-- -->
<div class="sidebar-wrapper"
id="style-3">
<div class="logo">
<a href="#"
class="simple-text">
<div class="logo-img">
<img src="static/img/vue-logo.png"
alt="">
</div>
Paper Dashboard
</a>
</div>
<slot>
</slot>
<ul :class="navClasses">
<!--By default vue-router adds an active class to each route link. This way the links are colored when clicked-->
<router-link v-for="(link,index) in sidebarLinks"
:key="index"
:to="link.route"
tag="li"
:ref="link.name">
<a>
<font-awesome-icon :icon="link.icon" />
<p v-t="link.name" />
</a>
</router-link>
</ul>
<moving-arrow :move-y="arrowMovePx">
</moving-arrow>
</div>
</div>
</template>
<script>
import FontAwesomeIcon from '#fortawesome/vue-fontawesome';
import MovingArrow from './MovingArrow';
export default {
name: 'side-bar',
components: {
MovingArrow,
FontAwesomeIcon,
},
props: {
type: {
type: String,
default: 'sidebar',
validator: value => {
const acceptedValues = ['sidebar', 'navbar'];
return acceptedValues.indexOf(value) !== -1;
},
},
backgroundColor: {
type: String,
default: 'black',
validator: value => {
const acceptedValues = ['white', 'black', 'darkblue'];
return acceptedValues.indexOf(value) !== -1;
},
},
activeColor: {
type: String,
default: 'success',
validator: value => {
const acceptedValues = [
'primary',
'info',
'success',
'warning',
'danger',
];
return acceptedValues.indexOf(value) !== -1;
},
},
sidebarLinks: {
type: Array,
default: () => [],
},
},
data() {
return {
linkHeight: 60,
activeLinkIndex: 0,
windowWidth: 0,
isWindows: false,
hasAutoHeight: false,
};
},
computed: {
sidebarClasses() {
if (this.type === 'sidebar') {
return 'sidebar';
}
return 'collapse navbar-collapse off-canvas-sidebar';
},
navClasses() {
if (this.type === 'sidebar') {
return 'nav';
}
return 'nav navbar-nav';
},
/**
* Styles to animate the arrow near the current active sidebar link
* #returns {{transform: string}}
*/
arrowMovePx() {
return this.linkHeight * this.activeLinkIndex;
},
},
watch: {
$route() {
this.findActiveLink();
},
},
methods: {
findActiveLink() {
this.sidebarLinks.find((element, index) => {
const found = element.path === this.$route.path;
if (found) {
this.activeLinkIndex = index;
}
return found;
});
},
},
mounted() {
this.findActiveLink();
},
};
</script>
I dont receive any issues or vue errors, sidebar just don't display. In Chrome console just return empty: <side-bar data-v-66018f3c=""></side-bar> Someone knows why sidebar is not binded? What I need to do to get correctly implementation of it? Regards
Chrome console error:
[Vue warn]: Unknown custom element: - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.