How to hook lifecycle events from root App component in Vue.js - vue.js

The structure of the app:
src/
|-- App.vue
|-- components/
|-- MyComponent.vue
|-- OtherComponent.vue
If I do, in MyComponent.vue
// MyComponent.vue
export default {
name: 'MyComponent',
methods: {
mounted() {
alert('MyComponent mounted')
}
}
}
This works as expected — an alert box is triggered when the component is mounted.
However, if I do the exact same thing in App.vue:
// App.vue
import MyComponent from './components/MyComponent.vue'
import OtherComponent from './components/OtherComponent.vue'
export default {
name: 'app',
components: {
MyComponent,
OtherComponent
},
methods: {
mounted() {
alert('app mounted')
}
}
}
Then nothing happens. I've tried with created, mounted, I've also try to wrap the alert() call into this.$nextTick({ ... }) — no success.
My problem is: I want something to happen (in this example, alert('app mounted')) once the child components have been mounted, because this "thing" needs to have all components mounted before executing.
Is it possible to hook a lifecycle event (ideally, mounted) in the App component?

All lifecycle methods need not to be declared within methods.
Should be as below.
// App.vue
import MyComponent from './components/MyComponent.vue'
import OtherComponent from './components/OtherComponent.vue'
export default {
name: 'app',
components: {
MyComponent,
OtherComponent
},
mounted() {
alert('app mounted')
},
methods: {
}
}
For more details read here

mounted is life cycle method of vue component. don't put it in methods.
Change
// MyComponent.vue
export default {
name: 'MyComponent',
methods: {
mounted() {
alert('MyComponent mounted')
}
}
}
To
// MyComponent.vue
export default {
name: 'MyComponent',
methods: {
},
mounted() {
alert('MyComponent mounted')
}
}

Related

How to manually define props type in vue3 with typescript

I can do
defineComponent({
props: {
name: { type: String as PropType<string> }
}
})
to tell vue3 that my props type is { name: string }, but if I have several component have the same props type, how can I share the defination?
If I define props in :
const props = {
name: String as PropType<string>
}
then use it like this:
defineComponent({
props: props,
})
It won't work, the type I got in setup function of props is not right.
this answer is purely addition to #Xinchao's answer.
one way is to destructure common props like following:
// taken from #Xinchao's answer
const commonProps = {
name: { type: String as PropType<string> }
}
defineComponent({
props:{
...commonProps,
extra: { }
}
})
another way is to write function which returns specific object like following
function getStringProp(required=false) {
return {
type: String as PropType<string>,
required,
default: '',
};
}
defineComponent({
props:{
name: getStringProp(true),
nickName: getStringProp(),
extra: { }
}
})
this case specifically come handy where prop is Array or Object; where we can cast the type like following
function getArrayProp<T>(required=false) {
return {
type: Array as PropType<T[]>,
required,
default: () => [],
};
}
defineComponent({
props:{
options: getArrayProp<Options>(true),
stringOptions: getArrayProp<string>(true),
}
})
The props options provided for defineComponent is a plain js object solely for type annotation purpose, so you can employ whatever technics in javascript for sharing structures between objects:
// in common.ts
export const commonProps = {
name: { type: String as PropType<string> }
}
// in your component.vue
import commonProps from "./common.ts";
defineComponent({
props:{
...commonProps,
extra: { }
}
})
If you're using the composition API with Vue 2 in preparation for switching to Vue 3, you have to use the PropType from that package instead of the vue package.
// Wrong for Vue 2
import Vue, { PropType } from 'vue'
import { defineComponent } from '#vue/composition-api'
// Right for Vue 2
import { defineComponent, PropType } from '#vue/composition-api'

Value from other Vue component

How can I get the value of an element in another Vue component and use it in another Component. For example I want to get the value of a textbox from a separate component and use it another.
By using event bus to communicate between any components,
Component A:
<script>
export default {
name: 'ComponentA',
methods: {
onTextAreaChange: function(event) {
this.$root.$emit('changed', event)
}
}
}
</script>
Component B:
<script>
export default {
name: 'App',
mounted() {
this.$root.$on('changed', (data) => {
//...console data here
})
}
}
</script>

Dependency injection in separated files of vue

I'm using Vue for my project.
Everything seems to be fine at beginning because I have knowledge about Angular before.
Now, I'm trying to implement DI in my Vue application.
I created a file named user.service.vue :
<script>
export default {
name: '$user',
provide: {
getUser: function(){
console.log('Hello world');
console.log(this.$http);
}
}
}
</script>
And I'm trying to inject the $user into my App.vue as below:
<script>
import NavigationBar from './components/shared/navigation-bar';
import UserService from './services/user.service';
export default {
components: {
NavigationBar
},
inject: ['$user'],
mounted(){
console.log(this.$user);
}
}
</script>
When I run the application, one error message shows up:
vue.runtime.esm.js?2b0e:587 [Vue warn]: Injection "$user" not found
How can I inject separated service files into my Vue app ?
Thanks,
Update 1
Even having changed my user.service.vue to :
<script>
export default {
provide: {
'$user': 'Hello world'
}
}
</script>
I still have the same problem.
But when I changed my App.vue to :
export default {
components: {
NavigationBar
},
provide: {
'$user': 'From app'
}
}
And create one component which is App's child: (Call it user-dashboard.vue for example)
export default {
name: 'user-dashboard',
inject: ['$user'],
data() {
return {
users: []
}
},
mounted() {
console.log(this.$user);
}
}
When I run the app, I get the message: From app in my console.
What I'm thinking is: the $user service must be provided by App.vue to inject to its children.
But in my application, there could me many services, such as: user.service, customer.service, ... Therefore, I cannot declare everything in my App.vue. It will be hard to maintain and fix bugs.
Any solutions please ?
What's wrong with using the service directly in your script?
see below:
<script>
import NavigationBar from './components/shared/navigation-bar';
import UserService from './services/user.service';
export default {
components: {
NavigationBar
},
mounted(){
UserService.someMethod().then((response) => {
console.log(response);
})
}
}
</script>

Vue.js parent-child components , why my prop is not yet available in child component?

In a parent component Member.vue , I get the user and account data from Vuex store via getters
<script>
import { mapGetters } from 'vuex'
import Profile from '#/components/Member/Profile.vue'
export default {
name: 'member',
components: {
Profile
},
data () {
return {
}
},
computed: {
...mapGetters(['user', 'account'])
},
methods: {
},
created () {
console.log('MEMBER VUE CREATED user: ', this.user)
console.log('MEMBER VUE CREATED account: ', this.account)
}
}
</script>
In the child component profile , I get the user data from props, but it's undefined ...
<script>
export default {
name: 'profile',
props: ['user'],
computed: {
...
},
methods: {
...
},
created: function () {
console.log('user data from parent component:')
console.log('user: ', this.user)
}
}
</script>
I guess it's related to the Parent-Child lifecycle hooks... but I don't see actually how to solve it easily ... thanks for feedback
In your HTML you need to pass the property down to the children, in your case it would be something like:
<profile :user="user" ...></profile>

Call a method of another component

How to call a method of another component ?
Like I have a component named Modal.vue . I have a method like below
<script>
export default {
name: 'modal'
methods: {
getUsers() {
//some code here
}
},
created: function () {
this.getUsers();
}
}
</script>
I would like to call that method in another component named Dashboard.vue.
<script>
export default {
name: 'dashboard'
methods: {
add_adddress () {
this.getUsers(); // I would like to access here like this
//some code here
}
},
}
</script>
I read this question, but how can I use $emit,$on,$broadcast in my current setup ?
In order to use emit one of the components need to call the other (parent and child). Then you emit from the child component to the parent component. For example if Dashboard component uses the Modal component you can emit from the Modal to the Dashboad.
If your components are separate from one another you can make use of Mixins. You can create a mixin UsersMixin.js like the following:
export default {
methods: {
getUsers: function () {
// Put your code here for a common method
}
}
}
Then import the mixin in both your components, and you will be able to use its methods:
Modal.vue
<script>
import UsersMixin from './UsersMixin';
export default {
name: 'modal'
mixins: [
UsersMixin
],
created: function () {
this.getUsers();
}
}
</script>
Dashboard.vue
<script>
import UsersMixin from './UsersMixin';
export default {
name: 'dashboard',
mixins: [
UsersMixin
],
methods: {
add_adddress () {
this.getUsers(); // I would like to access here like this
//some code here
}
},
}
</script>