Everything is fine in my main.js
import User from './components/User.vue'
new Vue({
el: '#user',
render: h => h(User),
data() {
return {
groups: []
}
},
mounted() {
this.getGroups();
},
methods: {
getGroups: function () {
axios.get('http://vagrant.dev/groups')
.then(response => this.groups = response.data)
.catch(error => console.log(error));
}
}
});
User.vue
<template>
<div id="user">
{{groups}} <!-- must be printed but it doesn't seem -->
</div>
</template>
<script>
export default {
name: 'user',
props: ['groups']
}
</script>
and index.html
<div id="user">
<user :groups="groups"></user>
</div>
Where is the mistake?
I do not get any errors, but I didn't understand why the value was not printed on the screen
Seems like you are putting 2 Vue instances on the same template since in your main file you are defining the template as el: "#user" which is already controlled by User.vue.
In you index.html add a div with id="app" and in main.js set el: "#app"
Your main.js and index.html shouldn't mix template in HTML and render function. So your main.js should be:
```new Vue({
el: '#user',
components: { User },
data() {
return {
groups: []
}
},
...```
You shouldn't directly reassign data value because Vue cannot detect property additions and rerender view. You should do it via Vue.set or this.$set like this:
this.$set(this, 'groups', response.data)
You can read more about how vue reactive in https://v2.vuejs.org/v2/guide/reactivity.html and Vue.set API: https://v2.vuejs.org/v2/api/#Vue-set
Related
I am writing a sample Vue component that works with an Event.
I get this error by rendering the index.html: "Property or method "onCouponApplied" is not defined on the instance but referenced during render" in the console.
index.html
<div id="root">
<coupon #applied="onCouponApplied"></coupon>
</div>
and below is Vue codes
main.js
window.Event = new Vue();
Vue.component('coupon',{
template: `<input placeholder="Enter" #blur="onCouponApplied">`,
methods:{
onCouponApplied() {Event.$emit('applied');}
}
})
new Vue({
el:"#root",
created() {
Event.$on('applied', ()=>alert('Received'));
},
});
First, Vue template code doesn't belong in index.html: <div id="root"></div>
Then you're mixing up event-bus and normal custom Vue events.
It's either:
window.Event = new Vue();
Vue.component("coupon", {
template: `<input placeholder="Enter" #blur="onCouponApplied">`,
methods: {
onCouponApplied() {
Event.$emit("applied");
}
}
});
new Vue({
el: "#app",
template: `<coupon></coupon>`,
created() {
Event.$on("applied", () => alert("Received"));
},
});
or:
Vue.component("coupon", {
template: `<input placeholder="Enter" #blur="$emit('applied')">`,
});
new Vue({
el: "#app",
template: `<coupon #applied="onCouponApplied"></coupon>`,
methods: {
onCouponApplied() {
alert("Received");
}
}
});
I put $testCounter in a plugin to make it global :
Vue.use({
install(Vue) {
Vue.prototype.$testCounter = 0;
Vue.prototype.$incrementCounter = () => {
Vue.prototype.$testCounter++;
};
});
I want to output it in some component. I also need its value to be updated globally, and reactively :
<template>
<p>{{ $testCounter }}</p>
</template>
<script>
mounted() {
let comp = this;
comp.watcherId = setInterval(() => {
comp.$incrementCounter();
// I want to remove this line and still be reactive :
comp.$forceUpdate();
}, 1000);
}
</script>
I need the property to be reactive, I tried a multiple solution as watchers, computed props, vm.$set(...), but I can't find the right way to do this.
Solution 1: use Vuex
Solution 2: set the global reactive data in root component and use it by calling this.$root
demo: https://jsfiddle.net/jacobgoh101/mdt4673d/2/
HTML
<div id="app">
<test1>
{{$root.testCounter}}
</test1>
</div>
Javascript
Vue.component('test1', {
template: `
<div>
test1
<slot></slot>
</div>
`,
mounted() {
setInterval(() => {
this.$root.incrementCounter();
}, 1000)
}
});
new Vue({
el: "#app",
data: {
testCounter: 1
},
methods: {
incrementCounter: function() {
this.testCounter++;
}
}
})
This must be simple, but haven't cracked it...
In vue, I think I get how to pass props from parent to child components. And I understand that I have an app state in the data member of the vue instance. What I don't understand is how to get the data state into the root app as props.
It seems there are a few ways to organize a vue app, so here's what I'm trying to make work:
index.ts
import app from './app.vue'
export default new Vue({
// App Root Element
el: '#app',
render: (c) => c('app'),
components: {
app
},
data: {
someValue: 42
}
})
app.vue
<template>
<div>
Some Value: {{someValue}}
</div>
</template>
<script lang="ts">
export default {
props: ['someValue']
};
</script>
I assume it should be something like the following, but I don't know how to get a reference directly to the data - unless I keep a reference to it outside of vue for this purpose, but that seems like it should not be necessary:
render: (c) => c('app', { someValue: ??? }),
Use this to get data or property values inside your render method (or methods or computed values, etc). Don't use an arrow function to define your render function if you're going to use this inside it.
new Vue({
el: "#app",
render(c) {
return c('app', {props:{someValue: this.someValue}})
},
components: {
app
},
data: {
someValue: 42
}
})
Example.
console.clear()
const app = {
props: ["someValue"],
template: `<div>Some Value: {{someValue}}</div>`
}
new Vue({
el: "#app",
render(c) {
return c('app', {props:{someValue: this.someValue}})
},
components: {
app
},
data: {
someValue: 42
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
</div>
As #RoyJ pointed out, this is the key section of the documentation.
I do not get vue components really .... I have a vue component in my html and want to show it, but it does not show anything, what do I do wrong?
What is the proper way to register and show a component in vue? Can someone give me a simple example for a beginner? :)
This is my code:
HTML
<div id="na-vue-app">
<activity-filter>
<template>
'Some Text'
</template>
</activity-filter>
</div>
Vue
new Vue({
el: '#na-vue-app'
});
const filterActivity = Vue.extend({
data: function () {
return {
distance:100,
}
},
mounted() {
},
methods: {
}
});
Vue.component('activity-filter', filterActivity);
Look at this pen: https://codepen.io/Nartub600/pen/oopBYJ
HTML
<div id="app">
<my-component msg="Hi!">
</my-component>
</div>
JS
Vue.component('my-component', {
props: ['msg'],
template: '<p>{{ msg }}</p>'
})
var app = new Vue({
el: '#app'
})
It's the easiest form to try components I think
I have experience with both single page apps and multi-page apps (classic websites). In the past I have used AngularJS 1.x on each page, it has been useful because all components can live in separate files and be executed as they appear on each page.
I'm now looking at VueJS to replace AngularJS, but not finding it easy to understand how to architect my multi-page app.
As expected I want to use some components on all the pages, and some on only a few pages.
Example:
I came across SFC - single file components using ES2015 which looked promising, but my backend is Java which outputs my html from JSPs. It appears that .vue files are precompiled by webpack, but if my templates are only ready when the page is rendered that won't be possible will it?
How would one architect a solution so that each component is modular but utilize either an x-template in the html and somehow attach it to a .vue SFC, or is there some other way to have components in separate files which can be imported using ES2015?
I hope this is making sense, can't seem to figure it out.
One possible approach would be to set the template for the Vue Component inline. So this would be to have a Component File like
Home.vue:
<script>
export default {
data() {
return {
msg: 'text',
}
}
}
</script>
import it as a global component for Vue (using require, import, etc.)
Vue.component('home', require('./components/Home.vue'));
and in your server generated HTML you'd have to use an inline template, which will have all the flexibility from normal templates
home.jsp:
<home inline-template>
<h2 v-text="msg"></h2>
</home>
Update
I've added an example on GitHub here
If I understand your question, you have want to make single file components out of HTML.
If this is the case, you should make use of the render() function and regular components.
The render function decides what to use as a template for a component:
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
render (createElement) {
return createElement({
template: '<div>Hello World</div>'
})
},
})
</script>
</body>
</html>
will render Hello World to the screen.
Now, let's see how this function is reactive:
<script type="text/javascript">
new Vue({
el: '#app',
data: {
count: 0
},
render (createElement) {
return createElement({
template: '<div>Hello World ' + this.count + '</div>'
})
},
created () {
setTimeout(() => {
this.count++
}, 2000)
}
})
</script>
Here, after 2 seconds, the counter in <div>Hello World ' + this.count + '</div> will increment from 0 to 1.
Now, what if we want to separate the template from the data?
<script type="text/javascript">
new Vue({
el: '#app',
render (createElement) {
return createElement({
template: '<div>Hello World {{ count }}</div>',
data () {
return {foo: 'bar'}
}
})
}
})
</script>
This code will display Hello World bar.
Now, let's see what happen if we try to load our template over http. We'll use the axios library to do so. Let's create a remote.html file to contain our html code:
<div>
I'm a remote component {{ foo }}
</div>
Now, let's try to load it via Ajax:
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.2/axios.min.js"></script>
<script type="text/javascript">
new Vue({
el: '#app',
data: {
template: null
},
render (createElement) {
return createElement({
template: this.template ? this.template : '<div>Hello World {{ foo }}</div>',
data () {
return {foo: 'bar'}
}
})
},
created () {
axios({
url: '/remote.html',
method: 'get'
}).then(response => {
this.template = response.data
})
}
})
</script>
This code will display I'm a remote component {{ foo }} as soon as remote.html has been loaded from the browser.
Note that the object passed to the createElement function is actually a component structure. You can use the same methods on it:
render (createElement) {
return createElement({
template: this.template ? this.template : '<div>Hello World {{ foo }}</div>',
data () {
return {foo: 'bar'}
},
mounted () {
alert('Hello from mounted')
}
})
}
will trigger an alert on the browser.
Anyway, here is a complete example with nested components:
Index.html
<!DOCTYPE html>
<html>
<head>
<title>Vue</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.2/axios.min.js"></script>
<script type="text/javascript">
const headerComponent = {
data () {
return {
template: '<div>Loading...</div>'
}
},
render (createElement) {
return createElement({
template: this.template,
data () {
return {
search: ''
}
}
})
},
created () {
axios('/header.html').then(response => {
this.template = response.data
})
}
}
new Vue({
el: '#app',
data: {
template: null
},
render (createElement) {
return createElement({
template: this.template ? this.template : 'Loading...',
data () {
return {foo: 'bar'}
},
components: {
'my-header': headerComponent
}
})
},
created () {
axios({
url: '/remote.html',
method: 'get'
}).then(response => {
this.template = response.data
})
}
})
</script>
</body>
</html>
header.html
<div>
<label>Search</label>
<input v-model="search" name=""> The search is: {{ search }}
</div>
I'm not sure that this is really the best approach and if I'm really responding to the question, but it will at list give you some tips on how Vue handles rendering and components...