How to call to sub component’s method in parent component Vue - javascript

I want to run the sub component’s method from the parent component in vue to refresh some areas of that component. Here is an example of what I want.
Home.vue
<template>
<componentp></componentp>
</template>
<script>
.....
methods:{
parentMethod(){
//I want to call to methodx in componentp
}
}
...
</script>
componentp.vue
<template>
..............
</template>
<script>
....
methods:{
methodx(){
//Run me from parent
}
}
}
...
</script>
I want to call methodx in sub component how can i do it.?

you can watch parent of parameter from component and run function in component after change parent parameter.
see this link.
i need run function in component from page with data page

<template>
<componentp ref="componentp"></componentp>
</template>
<script>
.....
methods:{
parentMethod(){
//I want to call to methodx in componentp
this.$refs.componentp.methodx()
}
}
...
</script>

If you cannot do what #Chris G says, another alternative could be to use a watcher:
https://v2.vuejs.org/v2/guide/computed.html#Watchers
Create some 'control' variable and watch if it changes to make your process.

Related

(Nuxt) Vue component doesn't show up until page refresh

I'm storing nav items in my Vuex store and iterating over them for conditional output, in the form of a Vue/Bulma component, as follows:
<b-navbar-item
v-for='(obj, token) in $store.state.nav'
v-if='privatePage'
class=nav-link
tag=NuxtLink
:to=token
:key=token
>
{{obj.text}}
</b-navbar-item>
As shown, it should be output only if the component's privatePage data item resolves to true, which it does:
export default {
data: ctx => ({
privatePage: ctx.$store.state.privateRoutes.includes(ctx.$route.name)
})
}
The problem I have is when I run the dev server (with ssr: false) the component doesn't show up initially when I navigate to the page via a NuxtLink tag. If I navigate to the page manually, or refresh it, the component shows.
I've seen this before in Nuxt and am not sure what causes it. Does anyone know?
recommendation :
use mapState and other vuex mapping helper to have more readable code :).
dont use v-for and v-if at the same element
use "nuxt-link" for your tag
use / for to (if your addresses dont have trailing slash)
<template v-if='privatePage'>
<b-navbar-item
v-for='(obj, token) in nav'
class=nav-link
tag="nuxt-link"
:to="token" Or "`/${token}`"
:key="token"
>
{{obj.text}}
</b-navbar-item>
</template>
and in your script :
<script>
import {mapState} from 'vuex'
export default{
data(){
return {
privatePage: false
}
},
computed:{
...mapState(['privateRoutes','nav'])
},
mounted(){
// it's better to use name as a query or params to the $route
this.privatePage = this.privateRoutes.includes(this.$route.name)
}
}
</script>
and finally if it couldn't have help you , I suggest to inspect your page via dev tools and see what is the rendered component in html. it should be an <a> tag with href property. In addition, I think you can add the link address (that work with refresh and not by nuxt link) to your question, because maybe the created href is not true in navbar-item.
NOTE: token is index of nav array . so your url with be for example yourSite.com/1.so it's what you want?
This question has been answered here: https://stackoverflow.com/a/72500720/12747502
In addition, the solution to my problem was a commented part of my HTML that was outside the wrapper div.
Example:
<template>
<!-- <div>THIS CREATES THE PROBLEM</div> -->
<div id='wrapper'> main content here </div>
</template>
Correct way:
<template>
<div id='wrapper'>
<!-- <div>THIS CREATES THE PROBLEM</div> -->
main content here
</div>
</template>

Referencing to named slots in vue

I have a vue component with 2 slots (both are filled) and i need to get the position relatively to the page (using getBoundingClientRect method for example), but i can't get access to watchable slot even with refs. Is there any way to do that without this.$el.querySelector method?
<template>
<div class="watchable-container">
<slot name="watchable" ref="refWatchable"></slot>
<div class="bubble-container">
<div class="bubble">
<slot name="content">
</slot>
</div>
<div class="bubble-tail"></div>
</div>
</div>
</template>
<script>
export default {
name: "BubblePopover",
mounted() {
console.log(this.$slots)
console.log(this.$refs);
},
}
</script>
The this.$slots member should work.
this.$slots.watchable
// or
this.$slots.watchable.$el
Try using nextTick in your mounted function to give slot time to render.
mounted() {
nextTick(()=>{
// your code here
})
}
You can also add an ID from your slot content add access it by getElementById
Another options is to use the composition API plugin and then access content from the ref.

vue wrap another component, passing props and events

How can I write my component to wrap another vue component, while my wrapper component get some extra props? My wrapper template component should be:
<wrapper-component>
<v-table></v-table> <!-- pass to v-table all the props beside prop1 and prop2 -->
</wrapper-component>
and the wrapper props:
props: {
prop1: String,
prop2: String
}
Here I want to wrap a table component, and pass to the table component all the props and events that were passed to the wrapper, beside two extra props prop1 and prop2. What is the correct way of doing this in vue?
And is there a solution for events too?
Place the component you wish to wrap into the template of the wrapper component, add v-bind="$attrs" v-on="$listeners" to that component tag, then add the inner component (and, optionally, inheritAttrs: false) to the wrapper component's config object.
Vue's documentation doesn't seem to cover this in a guide or anything, but docs for $attrs, $listeners, and inheritAttrs can be found in Vue's API documentation. Also, a term that may help you when searching for this topic in the future is "Higher-Order Component" (HOC) - which is basically the same as your use of "wrapper component". (This term is how I originally found $attrs)
For example...
<!-- WrapperComponent.vue -->
<template>
<div class="wrapper-component">
<v-table v-bind="$attrs" v-on="$listeners"></v-table>
</div>
</template>
<script>
import Table from './BaseTable'
export default {
components: { 'v-table': Table },
inheritAttrs: false // optional
}
</script>
Edit: Alternatively, you may want to use dynamic components via the is attribute so you can pass in the component to be wrapped as a prop (closer to the higher-order component idea) instead of it always being the same inner component. For example:
<!-- WrapperComponent.vue -->
<template>
<div class="wrapper-component">
<component :is="wraps" v-bind="$attrs" v-on="$listeners"></component>
</div>
</template>
<script>
export default {
inheritAttrs: false, // optional
props: ['wraps']
}
</script>
Edit 2: The part of OP's original question that I missed was passing all props EXCEPT one or two. This is handled by explicitly defining the prop on the wrapper. To quote the documentation for $attrs:
Contains parent-scope attribute bindings (except for class and style) that are not recognized (and extracted) as props
For example, example1 is recognized and extracted as a prop in the snippet below, so it doesn't get included as part of the $attrs being passed down.
Vue.component('wrapper-component', {
template: `
<div class="wrapper-component">
<component :is="wraps" v-bind="$attrs" v-on="$listeners"></component>
</div>
`,
// NOTE: "example1" is explicitly defined on wrapper, not passed down to nested component via $attrs
props: ['wraps', 'example1']
})
Vue.component('posts', {
template: `
<div>
<div>Posts component</div>
<div v-text="example1"></div>
<div v-text="example2"></div>
<div v-text="example3"></div>
</div>
`,
props: ['example1', 'example2', 'example3'],
})
new Vue({
el: '#app',
template: `
<wrapper-component wraps="posts"
example1="example1"
example2="example2"
example3="example3"
></wrapper-component>
`,
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

Using props to set different text on every page in vue.js

I am using laravel + vue. I want to do title of page in navbar, so when you are in index, in navbar is text index. When you are in settings, navbar says settings etc.
I think props is good for it, but when I use that, it works not good. Look here:
blade.php of index:
#extends('layout.app')
#section('content')
<index :msg="msg"></index>
#endsection
index.vue:
props: [
'msg'
],
Now navbar:
<template>
<nav class="navbar">
<a></a>
<p>{{msg}}</p>
</nav>
</template>
<script>
export default {
props: [
],
data() {
return {
}
},
}
</script>
and layout:
<body>
<div id="app">
<navbar></navbar>
#yield('content')
</div>
</body>
How I can change that {{msg}} paragraph in navbar when we are on different pages? My code doesn't work.
[Vue warn]: Property or method "msg" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
If you want to use a prop then you need to define it in the props object of your component. In your NavBar you are referencing to msg, but the props object in NavBar is empty. Define it and pass the prop in your layout.blade.php.
Or you could also define a computed property where you take a look at the current route and return a string fitting your business.
https://v2.vuejs.org/v2/guide/computed.html
If you want to share data between multiple components, then use a store (VUEX) as proposed :)

Vue.js render function in .vue file

I'm new with vue.js so forgive me if what I write does not make sense to you. It's not totally clear to me how to use render function inside a .vue file component.
I got a component in a .vue file like this:
<template>
<transition name="slide-fade">
<div class="drop-list" v-html="items">
</div>
</transition>
</template>
<style>
</style>
<script>
export default{
name: "drop-item",
props:['items'],
data(){
return{}
},
render(createElement) {
// create the list
}
}
</script>
Basically I have 3 component that alternately sends content ("items") to this one, mi goal is to render an unordered list inside it with a "#click='doSomenthing'" directive inside every list-element and "doSomething" depends on which is the component that sent the items to this one.
Any help will be appreciated
Firstly, you do not put render functions inside components, you simply pass the data as a prop. If you need to know which component passed the list of items, then you can simply pass a prop to let your component know what action to take, here's a basic example:
<template id="my-list">
<div>
<ul>
<li v-for="item in items">{{item}}</li>
</ul>
</div>
</template>
<script type="text/javascript">
export default {
props: ['items', 'action'],
methods: {
doSomething() {
switch (this.action) {
case 1:
console.log("I'm doing action 1");
break;
case 2:
console.log("I'm doing action 2");
break;
default:
console.log("I'm doing default action");
}
}
}
}
</script>
You can then set the component up in our parent and pass an action, I'm just passing a number here:
<my-list :items="items" :action="2"></my-list>
Here's a JSFiddle: https://jsfiddle.net/uckgucds/
If you are writing complex actions then you may want to write separate components for each list type, rather than a switch statement, you can then use a mixin to create the duplicate sections.

Categories

Resources