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),
});
Related
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.
As the title says, i get the error - vue.js:634 [Vue warn]: Unknown custom element: - did you register the component correctly?
I guess it's a silly typo, and i looked, but can't find it.
I think the root Vue instance is fine, because it renders and displays as it should.
This is my root and component code :
new Vue({
el: "#root",
data: {
cats: [{name: "kalduna", spasobni: 0}, {name:"zaxarich", spasobni:1}, {name:"leqso", spasobni:0}],
newCat: "",
spasobniValue: null,
},
methods: {
addNewCat: function(){
this.cats.push({name: this.newCat, spasobni: parseInt(this.spasobniValue)
})
console.log(this.spasobniValue)
}
},
computed: {
kaldunify: function(){
if (this.newCat){
return this.newCat + " vis aswavli ubans she axvaro shena"
}
}
}
})
Vue.component('catsy', {
template: `
<p>Hello this is cat</p>
`
})
This is my HTML part, where i try to display it :
<div id="root">
<h1 v-for="cat in cats" :class="{fancyClass : cat.spasobni}">
{{cat.name }}
</h1>
<input v-model="newCat" #keyup.enter="addNewCat" >
<br>
<label>Is he spasobni?<br>
<input type="radio" name="spasobni" v-model="spasobniValue" value="1">yass
<br>
<input type="radio" name="spasobni" v-model="spasobniValue" value="0">naay
</label>
<br>
<button #click="addNewCat">
+ Add Cat
</button>
<catsy v-bind:cats="cats"/>
</div>
Vue.component() is a global registering method.
These components are globally registered. That means they can be used
in the template of any root Vue instance (new Vue) created after
registration.
Source: https://v2.vuejs.org/v2/guide/components-registration.html#Global-Registration
So, you have to register these components before the new Vue().
I changed the order of Vue.component() and new Vue(), and also added a locally registered component (ComponentA with PascalCase; also note that I added the closing tags in the HTML template):
Vue.component('catsy', {
props: ['cats'],
template: `<p>Hello this is cat: <ul><li v-for="cat in cats">{{cat.name}}</li></ul></p>`
})
const ComponentA = {
props: ['innerList'],
template: `<div><strong>Other component</strong><catsy :cats="innerList"></catsy>After the inner list.</div>`
}
new Vue({
el: "#root",
components: {
'component-a': ComponentA
},
data: {
cats: [{
name: "kalduna",
spasobni: 0
}, {
name: "zaxarich",
spasobni: 1
}, {
name: "leqso",
spasobni: 0
}],
newCat: "",
spasobniValue: null,
},
methods: {
addNewCat: function() {
this.cats.push({
name: this.newCat,
spasobni: parseInt(this.spasobniValue)
})
console.log(this.spasobniValue)
}
},
computed: {
kaldunify: function() {
if (this.newCat) {
return this.newCat + " vis aswavli ubans she axvaro shena"
}
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.0"></script>
<div id="root">
<h1 v-for="cat in cats" :class="{fancyClass : cat.spasobni}">
{{cat.name }}
</h1>
<input v-model="newCat" #keyup.enter="addNewCat">
<br>
<label>Is he spasobni?<br>
<input type="radio" name="spasobni" v-model="spasobniValue" value="1">yass
<br>
<input type="radio" name="spasobni" v-model="spasobniValue" value="0">naay
</label>
<br>
<button #click="addNewCat">+ Add Cat</button>
<catsy v-bind:cats="cats"></catsy>
<component-a :inner-list="cats"></component-a>
</div>
I also added the prop in the catsy component.
I'm looking for a click-and-edit Vue component.
I've found a fiddle and made some edits. It works like this:
The fiddle is here.
The problem: I need an additional click to make the input focused. How can I make it focused automatically?
The code from the fiddle. HTML:
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for = "todo in todos">
<input v-if = "todo.edit" v-model = "todo.title"
#blur= "todo.edit = false; $emit('update')"
#keyup.enter = "todo.edit=false; $emit('update')">
<div v-else>
<label #click = "todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
JS:
new Vue({
el: '#app',
data: {
todos: [{'title':'one value','edit':false},
{'title':'one value','edit':false},
{'title':'otro titulo','edit':false}],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function(todo) {
this.editedTodo = todo;
},
}
})
You can use a directive, for example
JS
new Vue({
el: '#app',
data: {
todos: [
{ title: 'one value', edit: false },
{ title: 'one value', edit: false },
{ title: 'otro titulo', edit: false }
],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function (todo) {
this.editedTodo = todo
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
})
HTML
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for="todo in todos">
<input
v-if="todo.edit"
v-model="todo.title"
#blur="todo.edit = false; $emit('update')"
#keyup.enter="todo.edit=false; $emit('update')"
v-focus
>
<div v-else>
<label #click="todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
You can find more info here
https://v2.vuejs.org/v2/guide/custom-directive.html
With #AitorDB's help I have written a Vue component for this, I call it Click-to-Edit. It is ready to use, so I'm posting it.
What it does:
Supports v-model
Saves changes on clicking elsewhere and on pressing Enter
ClickToEdit.vue: (vue 2.x)
<template>
<div>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
#keyup.enter.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
v-focus=""
/>
<p v-else="" #click="edit = true;">
{{valueLocal}}
</p>
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>
Edit for 3.x: [Breaking changes between 2.x and 3.x]
remove .native from the event handlers
change the focus hook to mounted as described in Custom Directives 3.x.
Built on #Masen Furer's work. I added some protection to handle when a user deletes all of the data. There is probably a way to accomplish this using "update" but I couldn't get it working.
I also added the ability to hit escape and abandon any changes.
<template>
<span>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur="save($event);"
#keyup.enter="save($event);"
#keyup.esc="esc($event);"
v-focus=""/>
<span v-else #click="edit = true;">
{{valueLocal}}
</span>
</span>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value,
oldValue: (' ' + this.value).slice(1)
}
},
methods: {
save(event){
if(event.target.value){
this.valueLocal = event.target.value;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
esc(event){
this.valueLocal = this.oldValue;
event.target.value = this.oldValue;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>
I've an issue in this code
let bus = new Vue();
Vue.component('building-inner', {
props: ['floors', 'queue'],
template: `<div class="building-inner">
<div v-for="(floor, index) in floors" class="building-floor" :ref="'floor' + (floors - index)">
<h3>Floor #{{floors - index }}</h3>
<button type="button" class="up" v-if="index !== floors - floors">up</button>
<button type="button" class="down" v-if="index !== floors - 1">down</button>
</div>
</div>`,
beforeMount(){
bus.$emit('floors', this.$refs);
}
})
Vue.component('elevator', {
data: {
floorRefs: null
},
props: ['floors', 'queue'],
template: `<div class="elevator" ref="elevator">
<button type="button" v-for="(btn, index) in floors" class="elevator-btn" #click="go(index + 1)">{{index + 1}}</button>
</div>`,
beforeMount() {
bus.$on('floors', function(val){
this.floorRefs = val;
console.log(this.floorRefs)
})
},
methods: {
go(index) {
this.$refs.elevator.style.top = this.floorRefs['floor' + index][0].offsetTop + 'px'
}
}
})
new Vue({
el: '#building',
data: {
queue: [],
floors: 5,
current: 0
}
})
<div class="building" id="building">
<elevator v-bind:floors="floors" v-bind:queue="queue"></elevator>
<building-inner v-bind:floors="floors" v-bind:queue="queue"></building-inner>
</div>
I tried to access props inside $refs gets me undefined, why?
You should use a mounted hook to get access to the refs, because on "created" event is just instance created not dom.
https://v2.vuejs.org/v2/guide/instance.html
You should always first consider to use computed property and use style binding instead of using refs.
<template>
<div :style="calculatedStyle" > ... </div>
</template>
<script>
{
//...
computed: {
calculatedStyle (){
top: someCalculation(this.someProp),
left: someCalculation2(this.someProp2),
....
}
}
}
</script>
It's bad practice to pass ref to another component, especially if it's no parent-child relationship.
Refs doc
Computed
UPDATE: Almost there. Added the template to HTML. Added v-if and v-else to the button (couldn't get it to work on the template). Hard coded the example below. Trying to sus out final object path to array - for some reason v-if="this.id == favourites.listings_id" isn't working.
I'm building a favourites feature using vue.js. The create and delete requests both work fine. Finally what's required is to either show class favourited or notFavourited with appropriate action template create or delete depending on if the user has favourited the object or not. The users favourites array passes to the favourites component - and I've been trying to handled it that way.
I've commented out what I'm trying to achieve in the js code below.
HTML
<div id="app">
<listings>
</listings>
</div>
<template id="listing-template">
<div class="container">
<div v-for="listing in listings" class="panel panel-default">
<div class="panel-body">
<div>#{{ listing.id }}</div>
<favourite :id="listing.id"></favourite>
</div>
</div>
</div>
</template>
<template id="favourite-template">
<form><input class="hidden" type="input" name="_method" value="#{{ id }}" v-model="form.listings_id"></input><button v-if="this.id == 2" class="not-favourited" #click.prevent="create(favourite)" :disabled="form.busy"><i class="fa fa-heart" aria-hidden="true"></i><button v-else class="favourited" #click.prevent="delete(favourite)" :disabled="form.busy"><i class="fa fa-heart" aria-hidden="true"></i></button></form>
</template>
VUE.JS
new Vue({
el: '#app'
});
Vue.component('favourite', {
props: ['id'],
data: function() {
return {
form: new SparkForm({
listings_id: ''
}),
favourited: {
color: 'red',
fontSize: '12px'
},
notFavourited: {
color: 'black',
fontSize: '12px'
},
favourites: [], listings: [],
};
},
created() {
this.getFavourites();
},
methods: {
getFavourites() {
this.$http.get('/api/favourites')
.then(response => {
this.favourites = response.data;
});
},
// if favourite exists in favourites array
// then give class favourited and call template delete
// else give class notFavourited and call template create
create() {
Spark.post('/api/favourite', this.form)
.then(favourite => {
this.favourite.push(favourite);
this.form.id = '';
});
},
delete(favourite) {
this.$http.delete('/api/favourite/' + this.id);
this.form.id = '';
}
}
});
Vue.component('listings', {
template: '#listing-template',
data: function() {
return {
listings: [],
};
},
created() {
this.getListings();
},
methods: {
getListings() {
this.$http.get('/api/listings')
.then(response => {
this.listings = response.data;
});
}
}
});
EXAMPLE OBJECT IN FAVOURITES ARRAY
4: Object
created_at: "2016-07-22 21:14:40"
id: 81
listings_id: 1
updated_at: "2016-07-22 21:14:40"
user_id: 3