Vue.js - Using parent data in component - javascript

How I can get access to parent's data variable (limitByNumber) in my child component Post?
I tried to use prop but it doesn't work.
Parent:
import Post from './components/Post.vue';
new Vue ({
el: 'body',
components: { Post },
data: {
limitByNumber: 4
}
});
Component Post:
<template>
<div class="Post" v-for="post in list | limitBy limitByNumber">
<!-- Blog Post -->
....
</div>
</template>
<!-- script -->
<script>
export default {
props: ['list', 'limitByNumber'],
created() {
this.list = JSON.parse(this.list);
}
}
</script>

Option 1
Use this.$parent.limitByNumber from child component. So your Component template would be like this
<template>
<div class="Post" v-for="post in list | limitBy this.$parent.limitByNumber" />
</template>
Option 2
If you want to use props, you can also achieve what you want. Like this.
Parent
<template>
<post :limit="limitByNumber" />
</template>
<script>
export default {
data () {
return {
limitByNumber: 4
}
}
}
</script>
Child Pots
<template>
<div class="Post" v-for="post in list | limitBy limit">
<!-- Blog Post -->
....
</div>
</template>
<script>
export default {
props: ['list', 'limit'],
created() {
this.list = JSON.parse(this.list);
}
}
</script>

If you want to access some specific parent, you can name all components like this:
export default {
name: 'LayoutDefault'
And then add some function (maybe like vue.prototype or Mixin if you need it in all your components). Something like this should do it:
getParent(name) {
let p = this.$parent;
while(typeof p !== 'undefined') {
if (p.$options.name == name) {
return p;
} else {
p = p.$parent;
}
}
return false;
}
and usage could be like this:
this.getParent('LayoutDefault').myVariableOrMethod

Related

Can I data bind a function in Vue js?

is it possible to data bind a function in Vue?
In the template I have something like: <title> {{nameofFunction()}}</title>
When I run it, it just says native function on the page.
Thanks.
There is also such thing as "computed property" in Vue, designed to do exactly this:
<template>
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
</template>
<script>
export default {
data:() => ({
message: 'Hello'
}),
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
}
</script>
yes you can. Could you share how are you defining your data options?
Here I have an example that works both in Vue2 and Vue3
<template>
<div id="app">
<h1>{{messageHelloFn()}}</h1>
</div>
</template>
<script>
export default {
data() {
return {
messageHelloFn: (name = 'Lucas') => {
return `Hello ${name}`
}
};
}
};
</script>
Live example: https://codepen.io/LucasFer/pen/abywRMW
a.js
const func = (str) => str
export default fn
<template>
<div id="app">
<div v-for="item in items">
{{ getTime(item) }}
</div>
<div>
{{ fn('a') }}
</div>
<div>
{{ func('b') }}
</div>
</div>
</template>
<script>
import func from './a.js'
export default {
data () {
return {
items: ['123123', '456456'],
fn: (str) => str
}
},
methods: {
getTime (v) {
return v + '123'
}
}
};
</script>

How do I pass data to a component using Props in Vue2?

I have created a .Vue file to feature information on a cafe (Cafe Details Page). However, I would like to take parts of this details page and make it its own component, in order to manage any template updates more efficiently.
Therefore, I have created a Component (CafeHeader.vue) inside a components folder. I am trying to pass down the data from my array (Which is being used on my Cafe Details page) to this component using Props. However, I can't seem to get it to work.
The template for my Cafe Details Page is as below:
<template>
<div>
<div v-for="cafe in activeCafe">
<CafeHeader v-bind:cafes="cafes" />
<div class="content">
<p>{{ cafe.cafeDescription }}</p>
</div>
</div>
</div>
</template>
<script>
import CafeHeader from "./../../components/CafeHeader";
import cafes from "./../../data/cafes"; // THIS IS THE ARRAY
export default {
data() {
return {
cafes: cafes
};
},
components: {
CafeHeader,
},
computed: {
activeCafe: function() {
var activeCards = [];
var cafeTitle = 'Apollo Cafe';
this.cafes.forEach(function(cafe) {
if(cafe.cafeName == cafeTitle){
activeCards.push(cafe);
}
});
return activeCards;
}
}
};
</script>
Then, in a components folder I have a component called CafeHeader where I am wanting to use the data from the array which is previously imported to the Cafe Details page;
<template>
<div>
<div v-for="cafe in cafes">
<h1>Visit: {{cafe.cafeName}} </h1>
</div>
</div>
</template>
<script>
export default {
name: "test",
props: {
cafes: {
type: Array,
required: true
}
},
data() {
return {
isActive: false,
active: false
};
},
methods: {}
};
</script>
If in the CafeHeader component I have cafe in cafes, it does render data from the cafes.js However, it is every cafe in the list and I want just a single cafe.
<template>
<div>
<div v-for="cafe in cafes">
<h1>Visit: {{cafe.cafeName}} </h1>
</div>
</div>
</template>
The component also needed activeCafes on the v-for
<template>
<div>
<div v-for="cafe in activeCafes">
<h1>Visit: {{cafe.cafeName}} </h1>
</div>
</div>
</template>

Vue async component callback

<template>
<div>
<AsyncComponent1></AsyncComponent1>
<!-- Render AsyncComponent2 after AsyncComponent1 -->
<AsyncComponent2></AsyncComponent2>
</div>
</template>
<script>
export default {
name: "My Component"
components: {
AsyncComponent1: () => import("./AsyncComponent1"),
AsyncComponent2: () => import("./AsyncComponent2")
}
};
</script>
I'm loading two components asynchronously within a component but I need one of the components to render after the other. I wonder if thats possible?
Add a v-if to a ref in the other component.
<template>
<div>
<AsyncComponent1 ref="c1"></AsyncComponent1>
<!-- Render AsyncComponent2 after AsyncComponent1 -->
<AsyncComponent2 v-if="$refs.c1"></AsyncComponent2>
</div>
</template>
You could have the first component emit an event, that is listened to by the parent and used to toggle the second component
<template>
<div>
<AsyncComponent1 v-on:loaded="componentLoaded"></AsyncComponent1>
<!-- Render AsyncComponent2 after AsyncComponent1 -->
<AsyncComponent2 v-if="hasComponent"></AsyncComponent2>
</div>
</template>
<script>
export default {
name: "My Component",
components: {
AsyncComponent1: () => import("./AsyncComponent1"),
AsyncComponent2: () => import("./AsyncComponent2")
},
data: {
hasComponent: false
},
methods: {
componentLoaded() {
this.hasComponent = true;
}
}
};
</script>
And then in AsyncComponent1.vue:
...
mounted() {
this.$emit("loaded");
}
...

Change value of parent component variable using $parent but not reflected in interpolation syntax in vuejs

Child component
<template>
<div>
<h3>Child Component</h3>
<div>
<button #click="changeValue()">change Parent </button>
</div>
</div>
</template>
<script>
export default {
data() {
return{}
},
methods: {
changeValue() {
this.$parent.model[somekey] = somevalue
}
}
</script>
<style>
</style>
Parent component
<template>
<div>
<h3>Parent Component</h3>
<div>
{{model}} **<!--value is not refleted here -->**
</div>
</div>
</template>
<script>
export default {
data() {
return{
model: {}
}
}
}
</script>
<style>
</style>
changing value of parent variable using changeValue method of child component but not reflected in parent interpolation syntax ({{model}}). but when i access in parent method i got the updated value.
Vue cannot detect when properties are added or removed from an object. Read Change Detection Caveats.
Define the property upfront:
data: {
model: {
foo: null
}
}
this.$parent.model.foo = somevalue
If you need to add a property dynamically, then you need to use Vue.set.
You should emit event from children and handle in parent instead of changing it directly in children. It will be easier for you to manage the data
For example
Child component
<template>
<div>
<h3>Child Component</h3>
<div>
<button #click="changeValue()">change Parent </button>
</div>
</div>
</template>
<script>
export default {
data() {
return{}
},
methods: {
changeValue() {
this.$emit('changeValue', someValue)
}
}
</script>
Parent component
<template>
<div>
<h3>Parent Component</h3>
<div>
{{model}}
</div>
<child-component #changeValue="changeValue" />
</div>
</template>
<script>
export default {
data() {
return{
model: {}
}
},
methods: {
changeValue (newValue) {
this.model[someKey] = newValue
this.model = JSON.parse(JSON.stringify(this.model))
}
}
}
</script>

pattern to add to array item from child component

I have two components, a parent and child one, the
parent data attribute I've set up it like this...
data () {
return {
users: [],
}
}
the users array is populated by a button click, i share this array with the child component.
The child component is trying to add a user to this list which works(adding value to passed in props), but because the users array is declared under data the parent component refreshes and i lose my users...
is there a pattern to keep the users array values and add to them via a child...
sorry if this is obvious but as i said i'm just starting...
edit : adding code (parent component)
<template>
<div id="app">
<div>
<button v-on:click="display()">Display users</button>
<button v-on:click="displaySingleUserInput =
!displaySingleUserInput">Add user</button>
<div>
</div>
<ul v-if="errors && errors.length">
<li v-for="error of errors">
{{error.message}}
</li>
</ul>
</div>
<add-user v-on:submit_user="addUser" v-show="displaySingleUserInput"></add-user>
<user-list v-bind:users="users"></user-list>
</div>
</template>
<script>
import axios from 'axios';
import UserList from './components/UserList';
import AddUser from './components/AddUser';
export default {
components: {
'user-list': UserList,
'add-user': AddUser
},
name: 'app',
data () {
return {
users: [],
errors: [],
displaySingleUserInput: false
}
},
methods: {
display: function(string)
{
axios.get(`users.json`)
.then(response => {
// JSON responses are automatically parsed.
this.users = response.data.users
})
.catch(e => {
this.errors.push(e)
})
},
addUser: function(id) {
this.users.push({firstname: "john", lastName: 'jones'})
},
}
}
</script>
child component
<template>
<div id="singleUserAdd">
<form id=addUser aria-label="single user add">
<button v-on:click="submit()">Submit</button>
<button>Cancel</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
submit: function() {
this.$emit('submit_user', 1)
}
}
}
</script>
I assume that you have a method called addUser in your child component :
addUser(){
this.$emit("addusr",this.newuser);
}
In the parent one :
<child-comp #addusr="addNewUser" />
...
addNewUser(newuser){
this.users.push(newuser);
}
looks like i was missing
<form v-on:submit.prevent="onSubmit"
to stop my page from refreshing

Categories

Resources