I have a template:
var playersList = Vue.extend({
props: ['players'],
template: '#players-template'
});
Vue.component('players', playersList);
new Vue({
el: 'body',
methods: {
someMethod: function() {
//JSON data from request comes here
//Want to render template of players component with that data
}
}
});
I'm new with Vue.js and don't know how could I make it possible. How can I render the template with data from AJAX request? Someone posted a solution with v-view but documentation for it is gone at official website.
You have to specify the data in your Vue instance where the response is going to be stored
var playersList = Vue.extend({
template: '#players-template',
props: ['players']
}
});
Vue.component('players', playersList);
new Vue({
el: 'body',
data: {
players: ''
},
methods: {
someMethod: function() {
//JSON data from request comes here
//Want to render template of players component with that data
this.$set('players', data);
}
}
});
in your html
<body>
<ul>
<li v-for="player in players">
<players :players="players"></players>
</li>
</ul>
<template id="players-template">
<p>{{player.name}}</p>
</template>
</body>
Once you create the Vue app on the body element, you can use its component anywhere within that element. Since you named the component players, you'd render it like this:
<body>
<players :players="players"></players>
</body>
Then in your Vue
new Vue({
el: 'body',
data: function(){
return { players:[] }
},
methods: {
someMethod: function() {
//var result = ajax result
this.players = result;
}
}
});
Since players is a prop on your list component, you pass it in with :players="players". Then if players updates on the parent app, the list component would automatically update according to the new list.
Related
I want to load the template for a VueJS component dynamically,
I tried this code:
<template>
<div>
<default></default>
<div v-component="{currentView}"></div>
</div>
</template>
<script>
import { Component, Vue, Watch } from "vue-property-decorator";
//import App from './App.vue'
import VueFormWizard from "vue-form-wizard";
#Component({})
export default class detail extends Vue {}
window.addEventListener("load", () => {
window.onload = function() {
//Create the 'default' component
Vue.component("default", {
template: "<div>This should be replaced (and will be in 2 seconds)</div>"
});
//Create the parent ViewModel
var vm = new Vue({
el: "body",
data: {
currentView: "default"
}
});
//Pretend to load the data from the server
//This would actually be $.get("/url", data, function(){...});
window.setTimeout(function() {
//Create the new component using the template we received
Vue.component("BoardFeed", {
template:
'<div>Template returned from server, what I really want</div><br>And directives work too:<div v-repeat="items">{{$value}}</div>',
data: function() {
return {
items: [1, 2, 3]
};
}
});
//And then change the page to that component
vm.currentView = "BoardFeed";
}, 2000);
};
});
</script>
<style>
textarea {
width: 100%;
min-height: 100px;
}
</style>
but I get error:
[Vue warn]: Property or method "currentView" is not defined on the
instance but referenced during render. Make sure that this property is
reactive, either in the data option, or for class-based components, by
initializing the property. See:
https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
How can I fix it?
I want to $emit some data to all child components in vue.js 2 and this is my code :
Root Component
const app = new Vue({
created: function(){
// here is some promise and after it done the below line runs
this.$emit('foo', 'bar');
}
});
Child Component
<template></template>
<script>
export default {
created: function() {
this.$on('foo', function(data) {
console.log(data);
});
}
}
<script>
It's not working.
Is there any way to broadcast some data to all child components from root?
Vuejs is bottom up approach, means child component is compiled first and ask for this.$on so broadcasting will not work here with $emit-$on
Use props in child component to watch root data changes, giving this example where child1 and child2 having same root component data named name
var child1 = Vue.extend({
template: "<div>Child Component1 : Niklesh : {{name}} <div v-if='loading'>Loading...</div></div>",
props: ['name','loading']
});
var child2 = Vue.extend({
template: "<div>Child Component1 : Rishi : {{name}} <div v-if='loading'>Loading...</div></div>",
props: ['name','loading']
});
var app = new Vue({
el: "#vue-instance",
data: {
name: "...",
loading: true
},
mounted() {
var vm = this;
setTimeout(function() {
vm.name = "Raut";
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" :loading="loading"></child1>
<child2 :name="name" :loading="loading"></child2>
</div>
Use another Vue instance as an Event bus
Code Pen Sample
<div id="app">
<child></child>
</div>
var bus = new Vue()
Vue.component('child', {
data() {
return {
message: 'waiting for event...'
}
},
template: '<div>{{ message }}</div>',
created: function() {
bus.$on('foo', data => {
this.message = data;
})
}
})
var app = new Vue({
el: '#app',
created: function() {
setTimeout(()=> {
bus.$emit('foo', 'bar')
}, 1000)
}
})
I'm learning Vue.js for my game and I was wondering if there is a way to dynamically add and remove components in Vue.js ?
Here's my current code
var vue = new Vue({
el: "#fui",
template: ``
})
const HelloCtor = Vue.extend({
props: ['text'],
template: '<div class="hello">{{ text }}</div>',
});
const vm = new HelloCtor({
data: {
text: 'HI :)'
}
});
/*
How can I do something like this?
vue.add(vm);
vue.remove(vm);
*/
The code basically speaks for himself
So, is it possible (and how?) to dynamically add and remove Vue.js components to a Vue?
You need a place to put vm in the template. Then you can $mount the component manually to an element with vm.$mount('el'). You can also delete the element with vm.$destroy(true). Destroy won't delete the element from the DOM. You'll need to do that manually with something like (vm.$el).remove()
I'm not 100% this is what you're looking for, and when you find yourself manually calling $destroy() you are probably not doing things right…but it does let you take control of the creating and destruction of components.
Something like this will let you create then destroy your component (note in this case once you destroy vm it's gone):
<div id="fui">
<button #click="make">Make</button>
<button #click="bye">destroy</button>
<div id="mountme"></div>
</div>
<script>
const HelloCtor = Vue.extend({
props: ['text'],
template: '<div class="hello">This has been {{ text }}</div>',
})
const vm = new HelloCtor ({
data: {
text: "Mounted"
}
})
var vue = new Vue({
el: "#fui",
template: ``,
methods: {
make: () => {
vm.$mount('#mountme')
},
bye: () => {
vm.$destroy(true);
(vm.$el).remove();}
}
})
</script>
I'm currently working with VueJS 2, I would like to pass some params from the HTML to the VueJS component. Let me show you.
My Html Div looks like this :
<div id="app" :id="1"></div>
And my javascript :
new Vue({
store, // inject store to all children
el: '#app',
render: h => h(App)
});
My App Component:
<template>
<div>
{{ id }}
</div>
</template>
<script>
export default {
props: {
id: Number
}
}
</script>
I would like to get the id passed in the Html, in my App component.
How should I do ?
Here is one way.
<div id="app" data-initial-value="125"></div>
new Vue({
el: '#app',
render: h => h(App, {
props:{
id: document.querySelector("#app").dataset.initialValue
}
})
})
But you don't have to use a render function.
new Vue({
el: '#app',
template:"<app :id='id'></app>",
data:{
id: document.querySelector("#app").dataset.initialValue
},
components:{
App
}
})
Also, I'm using querySelector assuming you rendered initialValue (instead of id) to the page as an attribute, but you could just as easily put it somewhere else on the page like a hidden input or something. Really doesn't matter.
I'm playing with new MVVM framework - Vue.js (http://vuejs.org/).
It was really nice in simple examples and demos but now I'm trying to create big SPA with multiple views and I'm realizing that the best pattern how to do it is not described in framework's docs.
The main problem is that I don't know how to handle views on different routes.
For example, I'm using Director (https://github.com/flatiron/director) for routing but how can I change views?
var booksCtrl = function () {
var booksViewModel = new Vue({
el: '#books'
data: { ... }
ready: function () {
// hide previous ViewModel and display this one??
}
});
};
var editBookCtrl = function (id) {
var editBookViewModel = new Vue({
el: '#editBook'
data: { ... }
ready: function () {
// hide previous ViewModel and display this one??
}
});
};
var routes = {
'/books': booksCtrl,
'/books/:id/edit': editBookCtrl
};
var router = new Router(routes);
router.init();
Do I need to create separate Vue.js ViewModels and just display:block / display:none them like in this example?
What would be the right way in your opinion? Thanks!
Nested subviews can be resolved by using v-view and v-ref.
html
<div id="main">
<div v-view="currentView" v-ref="view"></div>
</div>
<ul>
<li>top</li>
<li>nest/view1</li>
<li>nest/view2</li>
</ul>
<script id="top" type="x-template">
<div>top view</div>
</script>
<script id="nest" type="x-template">
<div>
<span>nest view</span>
<div v-view="subview"></div>
</div>
</script>
javascript
Vue.component('top', Vue.extend({
template: "#top",
}));
Vue.component('nest', Vue.extend({
template: '#nest',
components: {
view1: Vue.extend({
template: '<span>this is subview 1</span>',
}),
view2: Vue.extend({
template: '<span>this is subview 2</span>',
}),
},
data: {
subview: "view1",
},
}));
var main = new Vue({
el: "#main",
data: {
currentView: "top",
},
});
var router = new Router({
'/': function() { main.currentView = 'top' },
'/nest/:view': function(view) {
main.currentView = 'nest';
main.$.view.subview = view;
},
});
router.init();
jsfiddle: http://jsfiddle.net/koba04/WgSK9/1/
The officially recommended way to use routing in vuejs applications is to use vue-router :
Quoting from the documentation :
vue-router is the official router for Vue.js. It
deeply integrates with Vue.js core to make building Single Page
Applications with Vue.js a breeze. Features include:
Nested route/view mapping
Modular, component-based router configuration
Route params, query, wildcards
View transition effects powered by Vue.js' transition system
Fine-grained navigation control
Links with automatic active CSS classes
HTML5 history mode or hash mode, with auto-fallback in IE9
Restore scroll position when going back in history mode
The well-written documentation elaborates further on Modular, component-based router configuration, including examples on handling nested routes.
A router-view outlet is made available into which the route configuration can specify which component to render. These components can contain embedded router-view outlets allowing component oriented nested route management.
Example from the docs:
<div id="app">
<router-view></router-view>
</div>
router.map({
'/foo': {
component: Foo,
// add a subRoutes map under /foo
subRoutes: {
'/bar': {
// Bar will be rendered inside Foo's <router-view>
// when /foo/bar is matched
component: Bar
},
'/baz': {
// Same for Baz, but only when /foo/baz is matched
component: Baz
}
}
}
})
You might be able to use v-view and component?
http://vuejs.org/guide/application.html
like this.
javascript
Vue.component('top', Vue.extend({
template: "<div>top view</div>",
}));
Vue.component('other', Vue.extend({
template: "<div>other view</div>",
}));
var main = new Vue({
el: "#main",
data: {
currentView: "top",
},
});
var router = new Router({
'/': function() { main.currentView = 'top' },
'/other': function() { main.currentView = 'other' },
});
router.init();
html
<div id="main">
<div v-view="currentView"></div>
</div>
You could use Named Views if you don't want to nest them.
html
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
javascript
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Baz = { template: '<div>baz</div>' }
const router = new VueRouter({
mode: 'history',
routes: [
{
path: '/',
// a single route can define multiple named components
// which will be rendered into <router-view>s with corresponding names.
components: {
default: Foo,
a: Bar,
b: Baz
}
},
{
path: '/other',
components: {
default: Baz,
a: Bar,
b: Foo
}
}
]
})
jsfiddle: https://jsfiddle.net/posva/6du90epg/
The fiddle is from the doc: https://router.vuejs.org/en/essentials/named-views.html