How to use the Async Component way to import component? - vue.js

I have a question about Async Component.
I got a error message when try to import a component using Async Way.
Is it possible to do that or My concept totally wrong about using Async Component way ?
Failed to mount component: template or render function not defined.
My Dashboard Component
<template>
<div>
<logout></logout>
</div>
</template>
<script>
const logout = resolve => require(['./child/Logout'], resolve)
export default {
name: 'dashboard',
components: {
logout
}
}
</script>
Logout Component
<template>
<div class="view logout">
<el-button>Logout</el-button>
</div>
</template>
<script>
export default {
name: 'logout'
}
</script>

Related

How to pass vmodel property to child component in nuxjs

I can't seem to pass dynamically modified properties from layouts into the <Nuxt /> component.
This is my ~/layouts/default.vue
<template>
<div>
<input v-model="myprop" />
<span>{{myprop}}</span>
<Nuxt />
</div>
</template>
<script>
export default {
provide: function () {
return {myprop: this.myprop};
},
data: () => ({
myprop: 'hello galaxy',
}),
}
</script>
This is my ~/pages/index.vue
<template>
<div>My Prop is: {{myprop}}</div>
</template>
<script>
export default {
inject: ["myprop"]
}
</script>
On the web page I see hello galaxy printed 3 times, once in the input, once in a span, and once in the Nuxt component. But when I edit the input field, only the span is updated. The Nuxt component does not capture the changes in myprop. The Nuxt component continues to show only hello galaxy while put the input and span shows changes as I type on my keyboard
What am I doing wrong?
The provide/inject is useful for simple situation, but if you've some reactive stuff the vuex store is more convenient :
in store/index.js
add a state called search and its mutations and actions :
export const state=()=>({
search:''
})
export const mutations ={
SET_SEARCH(state,payload){
state.search=payload
}
}
export const actions ={
setSearch(context,payload){
context.commit('SET_SEARCH',payload) ​
}
}
in layout/default.vue add computed property with setter/getter bound to the store:
<template>
<div>
<input v-model="search" />
<span>{{search}}</span>
<Nuxt />
</div>
</template>
<script>
export default {
computed:{
search:{
get(){
return this.$store.state.search
},
set(val){
this.$store.dispatch('setSearch',val)
}
}
}
}
</script>
in pages/index.vue :
<template>
<div>My search is: {{search}}</div>
</template>
<script>
export default {
computed:{
search(){
return this.$store.state.search
}
}
}
</script>

Vuex: Child component wait for parent component dispatch action

Parent component (Dashboard):
<template>
<div id="dashboard">
<Header />
<b-container>
<div>
<b-row>
<b-col>
<Overview />
</b-col>
</b-row>
</div>
</b-container>
</div>
</template>
<script>
import Header from '#/components/common/Header';
import Overview from '#/components/dashboard/Overview';
import { mapGetters } from 'vuex';
export default {
name: 'dashboard',
components: {
Header,
Overview
},
mounted() {
const sessionId = this.$cookie.get('connect.sid');
this.$store.dispatch('user/getUser', sessionId).then((userData) => {
this.$store.dispatch('project/getProject', userData.data.user);
});
},
computed: {
...mapGetters('user', {
user: 'getUser'
})
}
}
</script>
Child component (Overview):
<template>
<div class="overview">
<div class="overview__title">
<h1>
Welcome {{user.cn[0]}} // Works
</h1>
</div>
<div class="overview__project">
<p v-for="project in runningprojects" :key="project._id">
{{project.name}} // Does not work at refresh
</p>
</div>
</div>
</template>
<script>
import {mapGetters} from 'vuex';
export default {
name: 'dashboard-overview',
data() {
return {
runningprojects: []
}
},
computed: {
...mapGetters('user', {
user: 'getUser'
}),
...mapGetters('project', {
projects: 'getProjects',
allProjects: 'getAllProjects'
})
},
mounted() {
console.log("mounted this.projects", this.projects);
// add something from this.projects to this.runningprojects
},
methods: {
calcReq() {
...
},
...
}
</script>
In my Dashboard component (parent) I fetch the user data with a vuex action dispatch('user/getUser) and after that I fetch the projects of this user dispatch('project/getProject).
In my Overview component (child) I want to show the project information of this user. I call my mapGetters and I have a component variable runningprojects inside data(). In my mounted() lifecycle I want to push data from my getters to this data array.
The following problem is given:
When I refresh my application, the console.log from my child component mounted() is called before the dispatch jobs are finished in the parent component (dashboard).
It only works if change something in my local files and vue-cli does a live reload.
Because of the page lifecycle of the vue app. when component renders mounted is called after created and it wont wait for the ajax or any async calls.
One solution would be to not render the child component until the async return
<template>
<div id="dashboard">
<Header />
<b-container>
<div>
<b-row>
<b-col>
<Overview v-if="finished"/>
</b-col>
</b-row>
</div>
</b-container>
</div>
</template>
<script>
import Header from '#/components/common/Header';
import Overview from '#/components/dashboard/Overview';
import { mapGetters } from 'vuex';
export default {
name: 'dashboard',
data() {
return {
finished: false,
}
},
components: {
Header,
Overview
},
mounted() {
const sessionId = this.$cookie.get('connect.sid');
this.$store.dispatch('user/getUser', sessionId).then((userData) => {
this.$store.dispatch('project/getProject', userData.data.user);
this.finished = true;
});
},
computed: {
...mapGetters('user', {
user: 'getUser'
})
}
}
</script>
Just add a v-if in the child component and when dispatch has return then set the value to true which will render the child component and the then the mounted will have the values you want
Other solution would be.
Use updated function instead of mounted and which will be called when ever there is a change in the state.

Global check user Logged In - NuxtJS

I config a global check user if LoggedIn or not to rendering components in NuxtJS but I cant do it. Please help me.
I write computed to wrapper components (layouts/default.vue)
~/layouts/default.vue
<template>
<router-view></router-view>
</template>
<script>
import { mapState } from 'vuex'
export default {
computed: {
computed: {
...mapGetters({
LoggedIn: 'authUser'
})
}
}
}
</script>
But I cant use it on children components / pages.
~/pages/index.vue
<template>
<div class="index-page">
<div class="" v-if="LoggedIn">
asdasd
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log(this.LoggedIn)
// Result: Undefined
}
}
</script>

Pass data from one component to all with $emit without using #click in VueJS

Trying to learn vuejs I got to the question how to pass any data from one component to all, using $emit but without using any #click.
It is possible some how that the data to be just available and grab it any time, without using the click?
Let's say we have this example with normal #click and $emit.
main.js
export const eventBus = new Vue()
Hello.vue
<template>
<div>
<h2>This is Hello component</h2>
<button
#click="emitGlobalClickEvent()">Click me</button>
</div>
</template>
<script>
import { eventBus } from '../main'
export default {
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
methods: {
emitGlobalClickEvent () {
eventBus.$emit('messageSelected', this.msg)
}
}
}
</script>
User.vue
<template>
<div>
<h2>This is User component</h2>
<user-one></user-one>
</div>
</template>
<script>
import { eventBus } from '../main'
import UserOne from './UserOne.vue'
export default {
created () {
eventBus.$on('messageSelected', msg => {
console.log(msg)
})
},
components: {
UserOne
}
}
</script>
UserOne.vue
<template>
<div>
<h3>We are in UserOne component</h3>
</div>
</template>
<script>
import { eventBus } from '../main'
export default {
created () {
eventBus.$on('messageSelected', msg => {
console.log('From UserOne message !!!')
})
}
}
</script>
I want to get this message : Welcome to Your Vue.js App from Hello.vue in all components, but without #click, if is possible.
You can create another Javascript file which holds an Object with your initial state. Similar to how you define data in your components.
In this file your export your Object and import it in all Components which need access to this shared state. Something along the lines of this:
import Store from 'store';
data() {
return {
store
}
}
This might help:
https://v2.vuejs.org/v2/guide/state-management.html
At this point if you app grows even more in complexity you might also start checking out Vuex which helps to keep track of changes(mutations) inside of your store.
The given example is essential a very oversimplified version of Vuex.

Existing component throw: Unknown custom element

I'm trying to use a component in another component. On the created event, I can log this component and it returns the good object. However for some reasons, the component doesn't seem to be included. VueJS do not understand the validation tag.
Any ideas?
<template>
<main>
<validation :validate="$v.email" :model="'email'"></validation>
</main>
</template>
<script>
import { Validation } from 'components/helpers'
export default {
name: 'login',
component: { Validation },
created() {
// it works. print the component with his path
window.console.log(Validation)
}
}
</script>
[Vue warn]: Unknown custom element: - did you register
the component correctly? For recursive components, make sure to
provide the "name" option.
In components/helpers I have two file:
1) index.js
export { default as Validation } from './Validation'
2) Validation.vue
<template>
<div>
<span class="form__validation" v-if="validate && !validate.required">Required</span>
<template v-if="validation[model]">
<span class="form__validation" v-for="error in validation[model].messages">{{ error }}</span>
</template>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'validation',
data() {
return {
L: L
}
},
props: ['model', 'validate'],
computed: {
...mapGetters({
validation: 'getValidation'
})
}
}
</script>
Changing component for components did the trick. Shame on me :)