I'm new to Vue.js and want to use single-file components, but I don't understand the workflow.
For example, I have three components: App, Grid and List
App.vue
<template>
<div id="app">
<div id="grid"></div>
<div id="right"></div>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
message: 'Hello Vue!'
}
}
}
</script>
Grid.vue
<template>
<div id="left"></div>
</template>
<script>
export default {
name: 'grid',
data: function () {
return {
grid: 'some-data'
}
}
}
</script>
List.vue
<template>
<div id="right"></div>
</template>
<script>
export default {
name: 'list',
data: function () {
return {
text: 'some-text'
}
}
}
</script>
Main.js
import Vue from 'vue'
import App from './vue/App.vue'
import Grid from './vue/Grid.vue'
import PatternList from './vue/PatternList.vue'
new Vue({
el: '#app',
render: h => h(App)
});
new Vue({
el: '#grid',
render: h => h(Grid)
});
new Vue({
el: '#right',
render: h => h(PatternList)
});
It works but I hope this isn't the right way to create nested components.
Can anyone show the way it should be done? Thanks
You can register components using the Vue.component method:
import Vue from 'vue'
import App from './vue/App.vue'
import Grid from './vue/Grid.vue'
import PatternList from './vue/PatternList.vue'
Vue.component('grid', Grid);
Vue.component('pattern-list', PatternList);
new Vue({
el: '#app',
render: h => h(App)
});
And then add them to the App template directly using their tag name:
<template>
<div id="app">
<grid></grid>
<pattern-list></pattern-list>
</div>
</template>
This registers the components globally, meaning that any Vue instance can add those components to their templates without any additional setup.
You can also register components to a Vue instance, like so:
new Vue({
el: '#app',
render: h => h(App),
components: {
'grid': Grid,
'pattern-list': PatternList
}
});
Or within the script tag of a single-file component:
<script>
import Grid from './vue/Grid.vue'
export default {
name: 'app',
components: {
'grid': Grid,
'pattern-list': PatternList
}
});
</script>
This registers the components just to that Vue instance, meaning that those registered components will only be available to use within the template for that Vue instance. A child component would not have access to those registered components unless those components are also registered to the child Vue instance.
Related
I'm using the Vue controller to update the content on my SPA. While I can import views and controllers and display them accordingly, I'm having a hard time updating some variables defined in the main Vue instance. I also tried to define them in the main view but I still cannot update them.
Here's my Vue instance:
new Vue({
router,
render: h => h(App),
data: () => {
return {
showYesOrNo: false,
showMultiChoice: false
}
}
}).$mount('#app')
This is my main view:
<script type="text/javascript">
import ContactContainer from "./views/ContactContainer.vue"
export default {
name: "app",
components:{
ContactContainer
},
data: () => {
return { // Redefined the variables here to see if I could access them in some way
showYesOrNo: false,
showMultiChoice: false
}
}
}
</script>
<template>
<div id="app">
<div class="container">
<div id="main_container">
<transition name="fade"><router-view name="YesOrNo" v-show="!showMultiChoice"/></transition>
<transition name="fade"><router-view name="MultiChoice" v-show="!showYesOrNo"/></transition>
<transition name="fade"><ContactContainer name="Contact" v-show="!showMultiChoice && !showYesOrNo"></ContactContainer></transition>
</div>
</section>
</div>
</div>
</template>
Now this is how I try to access the ShowYesOrNo and ShowMultiChoice variables. First in the controller:
const routes = [
{
path: '/YesOrNo',
components: {
YesOrNo: YesOrNoVue,
MultiChoice: MultiChoiceContainer
},
beforeEnter: (to, from, next) => {
console.log(this); //undefined
console.log(this.$parent.showYesOrNo) //undefined
console.log(vm.showYesOrNo) //undefined
next();
}
}
]
Then in the YesOrNo vue:
<template>
<!-- Some HTML -->
</template>
<script>
export default {
data: function(){
return {
name: 'YesOrNoVue'
}
},
created: function(){
console.log(this.showYesOrNo); //undefined
console.log(vm.showYesOrNo); //undefined
}
}
</script>
I'm a little confused with the visibility of these variables so I'd like to know what's the best approach to change them when the router-view is updated (i.e. when the vue is created).
Thanks.
Is possible in Vue.js call component by variable name?
Components are registred:
import Component1 from 'component1'
import Component2 from 'component2'
import Component3 from 'component3'
...
components: {
Component1, Component2, Component3
},
And i am searching for something like this:
created() {
var componentName = 'Component1';
this.components[componentName]
}
You can access the components property like this:
this.$options.components[componentName]
Just a basic example on how you can use dynamic component:
link to jsFiddle to play around: link here
<div id="app">
<component v-bind:is="currentPage">
<!-- component changes when currentPage changes! -->
<!-- output: Updated About -->
</component>
</div>
new Vue({
el: '#app',
data: {
currentPage: 'home'
},
components: {
home: {
template: "<p>Home</p>"
},
about: {
template: "<p>About</p>"
},
contact: {
template: "<p>Contact</p>"
}
},
mounted(){
this.$options.components['about'].template = "<p>Updated About</p>"
this.currentPage = 'about'
}
})
I've added a main vue app in my application. And I want to add a component to the app.
Trying to add TopMenu.vue to the App.vue:
<top-menu></top-menu> in App.vue.
Registered in main.js for app.
Am I using the single file components correct?
main.js
import Vue from 'vue'
import App from './components/App'
import TopMenu from './components/TopMenu'
Vue({
el: '#app',
render: h => h(App),
components: {
'top-menu': TopMenu
}
})
App.vue:
<template>
<div class="wrapper">
<top-menu></top-menu>
<div class="container drop-shadow">
<h1>{{ message }}</h1>
<p1>{{ about }}</p1>
</div>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
message: "Hello kosken!",
about: "Using Parcel In A Vue.js App"
};
}
};
</script>
TopMenu.vue:
<template>
<div class="user-menu drop-shadow"></div>
</template>
<script>
export default {
name: 'top-menu',
data: function () {
return "somedata";
}
}
</script>
You should import it and use it inside your App.vue :
<template>
<div class="wrapper">
<top-menu></top-menu>
<div class="container drop-shadow">
<h1>{{ message }}</h1>
<p1>{{ about }}</p1>
</div>
</div>
</template>
<script>
import TopMenu from './TopMenu'
export default {
name: "App",
data() {
return {
message: "Hello kosken!",
about: "Using Parcel In A Vue.js App"
};
},
components: {
'top-menu': TopMenu
}
};
</script>
import Vue from 'vue'
import App from './components/App'
import TopMenu from './components/TopMenu'
Vue.component('top-menu', TopMenu)
This is how you should register component globally and you can use it anywhere.
It is the first web application I am going to make, so I am totally new to Vue.js Javascript programming. I am using one of Boostrap templates called Beagle.
http://themes.getbootstrap.com/preview/?theme_id=1696&show_new=
I have a file app-charts-morris.js which I hold in my Static folder, here is some code of this file:
var App = (function () {
'use strict';
App.chartsMorris = function( ){
//Donut Chart
function donut_chart(){
var color1 = App.color.warning;
var color2 = App.color.success;
var color3 = App.color.primary;
Morris.Donut({
element: 'donut-chart',
data: [
{label: 'Facebook', value: 33 },
{label: 'Google', value: 33 },
{label: 'Twitter', value: 33}
],
colors:[color1, color2, color3],
formatter: function (y) { return y + "%" }
});
}
donut_chart();
};
return App;
})(App || {});
What it does is it should show me Donut chart with some javascript functions, but nothing appears here only empty space.
Here is my Vue code:
<template>
<div id="donut-chart" style="height: 250px;"></div>
</template>
<script>
export default {
data () {
return {
}
},
computed: {
},
watch: {
},
methods: {
}
}
</script>
and here where I access my javascript file:
<script src="/static/js/app-charts-morris.js" type="text/javascript">
</script>
<script type="text/javascript">
$(document).ready(function(){
//initialize the javascript
App.init()
App.chartsMorris()
App.ChartJs()
App.dashboard()
});
</script>
my main.js file
import Vue from 'vue'
import Vuetify from 'vuetify'
import App from './App'
import * as firebase from 'firebase'
import 'firebase/firestore'
import router from './router'
import { store } from './store'
import {VueMasonryPlugin} from 'vue-masonry'
import InstantSearch from 'vue-instantsearch'
Vue.use(InstantSearch)
Vue.use(Vuetify)
Vue.use(VueMasonryPlugin)
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
render: h => h(App),
created () {
}
})
What is the problem here? Why vue.js does not show my Donut chart? But it shows without any framework
Here is my Vue code:
If it's your App.vue file, as you initialize your Vue instance on an element #app, you need to add it in your template:
<template>
<div id="app">
<div id="donut-chart" style="height: 250px;"></div>
</div>
</template>
Or change the element to donut-chart:
new Vue({
el: '#donut-chart',
router,
store,
render: h => h(App),
})
<template>
<div id="donut-chart" style="height: 250px;"></div>
</template>
I have two components and I want to display what the user enters in one on the other component. I don't really want to use a state manager like vuex because it's probably a bit overkill as it's a small application
this is my main.js:
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
import { routes }from './routes';
export const EventBus = new Vue();
Vue.use(VueRouter);
const router = new VueRouter({
routes,
mode: 'history'
});
new Vue({
el: '#app',
router,
render: h => h(App)
})
Component that emits the event called addHtml.vue
<template>
<div>
<h1>Add HTML</h1>
<hr>
<button #click="navigateToHome" class="btn btn-primary">Go to Library</button>
<hr>
Title <input type="text" v-model="title">
<button #click="emitGlobalClickEvent()">Press me</button>
</div>
</template>
<script>
import { EventBus } from '../../main.js'
export default {
data: function () {
return {
title: ''
}
},
methods: {
navigateToHome() {
this.$router.push('/');
},
emitGlobalClickEvent() {
console.log(this.title);
EventBus.$emit('titleChanged', this.title);
}
}
}
</script>
the file that listens for the event thats emitted and to display what was entered on the other component:
<template>
<div>
<h1>Existing Items</h1>
<hr>
<p>{{ test }}</p>
</div>
</template>
<script>
import { EventBus } from '../main.js';
export default {
data: function () {
return {
test: ''
}
},
created() {
EventBus.$on('titleChanged', (data) => {
console.log('in here!',data);
this.test = data;
});
}
}
</script>
the console.log('in here!',data); inside the listener gets printed out to the console so I know it's picking it up however {{ test }} doesn't get updated to what the user enters when I click back onto the component to view if it was updated, it just remains blank? Any Ideas?
If you are using vue-router to display the secound component. The reason might be that you just see a new instance of that component everytime and the value of test will be reseted when the component is destroyed. You can bind it to a (global) variable to persist test: window.yourApp.test. Maybe webpack will mourn but it is possible. Even eslint has an ignore comment for such cases.
It is like Reiner said, because the component gets destroyed once you switch pages. Try wrapping your router-view inside a keep-alive:
<keep-alive>
<router-view><router-view>
</keep-alive>
Also. If you want to keep the state of just one specific component / page you can use the include tag:
<keep-alive include='name of component'>
<router-view></router-view>
</keep-alive>