Using props how to update the data in Vuejs? - javascript

component
<template>
<div>
<b>Vuejs dynamic routing</b>
<div v-for="item in items" :key="item.id">
<b>{{ item.id }}.</b>
<router-link
#update="updateValue"
:to="{ name: 'UserWithID', params: { id: item.id, items: items } }"
>
{{ item.val }}{{ item.kk }}
</router-link>
</div>
<br /><br /><br />
{{ $route.params.id }}
</div>
</template>
Using props how to update the data in Vuejs?
I have two components called, helloworld, User. And i have mocked the data inside of helloworld.vue. Now using the props the want to get he data inside of the User component and preform the update operation . When trying to preform the logic.
Where onclick of button. it is going to method, But not updating the logic
I have kept console. inside method. and its printing. but logic not updating

As mentioned in the comments you are getting errors in the console as you are not passing the items as props to the User component and it is a required field in the User component.
And for the second point, you should store data in a separate file not in the main component so the items array doesn't get initialized again when the parent component is rendered again. The best option would be a global store(vuex) for sake of simplicity, it is done a separate file for now just as an example.
Here is a sample sandbox hope it helps:
https://codesandbox.io/s/exciting-ptolemy-35bsb?file=/src/components/User.vue

Related

How to render VueJS Slot in a another component

VueJS slot could be placed anywhere inside a parent component.
However, I have a use case where I need to show a slot in another (foreign) component outside the parent component.
For example, I have component Student:
<template>
<slot name="detail" />
<slot name="status" /> <!-- I don't want to render this slot inside this component, but somewhere else -->
</template>
I want to display the student's status in a header section outside the student component as below:
<div class="Header">
<!-- student status slot should go here-->
<student-status-slot></student-status-slot>
</div>
<div class="InputForm">
<student>
<template #detail>This the detail information about student</template>
<template #status>Grade A</template>
</student>
</div>
You may suggest to create a new "student-status-slot" component. However, the idea is to have all student related information, including "status" declared under the component, but render some of the slot somewhere else.
I have tried another approach creating a separate component and pass the status data via prop. But That is not what I wanted to achieve. I don't want to pass data, but re-use the student status component, which can be dynamic.
In a parent component you can access child's slots by adding ref attribute to child, and then render the VNode obtained. See the demo here https://codesandbox.io/s/happy-einstein-9f5rke?file=/src/components/StudentPage.vue
But actually I wouldn't recommend this way such it's not conventional and slots were not designed for this. I think you should rather consider using portals (Vue 3 portals or https://www.npmjs.com/package/portal-vue if you use Vue 2) to achieve your goal

Cannot dynamically pass a prop to a component within a v-for loop in Vue js

I have an array sheets initialised in data, has an item pushed to it when a button is pressed
data() {
return {
sheets: []
};
}
And in the html I'm trying to add a Card component for each element in this array and pass the data as a prop, but none of the components get rendered and there is no error message. I also tried putting the v-for directly on the component but it has the same result
<div id="sheets">
<template v-for="c in sheets">
<Card :info="c"/>
</template>
</div>
Meanwhile if I do something like this, it displays all the data in the array correctly, so I dont understand whats going wrong here
<div id="sheets">
<template v-for="c in sheets">
<span>{{c}}</span>
</template>
</div>
--
Solution
In my component the data from prop was being manipulated in the created() function, it works after I did this in the mounted() function instead
Make sure you have following things done correctly:
Imported your Card component
Passing and accessing the props
There are no conflicts in the variable names and id names
Next thing you need to know and is a must while using v-for is adding :key to the element which acts as unique id and lets Vue detect that each element is unique inside the v-for. One thing to be noted while using :key is that, you cannot use :key on the <template> tag.
Adding a validation using v-if would be a good idea, so v-for only executes if the array is not empty.
<div id="sheets">
<template v-if="sheets.length">
<Card v-for="(sheet,index) in sheets" :key="index" :info="sheet" />
</template>
</div>
Edit 1: As mentioned by Michal in the comments section that using index can lead to difficulties while debugging issues. You can use either :key="sheet" or if sheet is object including some unique id in it, then use :key="sheet.id" and get rid of the index
// use this if sheet is not an object
<div id="sheets">
<template v-if="sheets.length">
<Card v-for="sheet in sheets" :key="sheet" :info="sheet" />
</template>
</div>
OR
// use this if sheet is an object having some unique id in it
<div id="sheets">
<template v-if="sheets.length">
<Card v-for="sheet in sheets" :key="sheet.id" :info="sheet" />
</template>
</div>
As :key is not mandatory, It should work without that as well. I just created a working fiddle below. Please have a look and try to find out the root cause.
Vue.component('card', {
props: ['info'],
template: '<span>{{ info }}</span>',
});
var app = new Vue({
el: '#app',
data: {
sheets: [],
count: 0
},
methods: {
create() {
this.count++;
this.sheets.push('Sheet' + this.count);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="create">Create a Card!</button>
<template v-for="c in sheets">
<Card :info="c"></Card>
</template>
</div>

how can I pass props to child props? (vue.js)

Hi I'm making vue application and What I want to do is there's parentsComponent which has ChildOne and ChildTwo, the data is getting from same dataArray but childTwo has multiple data. and childTwo has childOneComponent inside. but I want to passed the data to ChildTwo from ParentsComponent and give it to ChildOne again.
is it possible?
ParentsComponent.vue
<template>
<ChildOneComponent :data="NewsData">
<ChildTwoComponent :data="NewsData.sports">
</template>
ChildOneComponent.vue
<div>
{{data.title}}
</div>
ChildTwoComponent.vue
<ChildOneComponent></ChildOneComponent>
It should be as below. You will have to pass the whole Newsdata object to your ChildTwoComponent as you are rendering ChildOneComponent from it.
You can update your template rendering of ChildTwoComponent accordingly.
ParentsComponent.vue
<template>
<div>
<ChildOneComponent :data="NewsData">
<ChildTwoComponent :data="NewsData">
</div>
</template>
ChildTwoComponent.vue
<ChildOneComponent :data="NewsData"></ChildOneComponent>

Vue add one component before a component inside v-for loop dynamically

I have a question on how to add an unread component before a dynamic component (message, can be of a different type, which requires different rendering) inside a v-for loop.
Here is my sample code without the unread panel.
<template>
<div>
<Message v-for="(message, index) in messages" :key="index" :message="message></Message>
</div>
</template>
AIM:
I want to add an unread panel before the message that is unread. And clearly, it will be added once in the template. So I would like another developer when viewing the template, can easily know that it does the job.
How to add Unread Panel
Method 1:
Add it in template directly.
<template>
<div>
<template v-for="(message, index) in messages" :key="index">
<Unread v-if="message.getId() === firstUnreadId"></Unread>
<Message :message="message"></Message>
</template>
</div>
</template>
Problem:
There are lots of unnecessary checking to see if unread is needed to place to the DOM, not to mention, it is difficult for the developer to know that the unread component will only be loaded once.
Method 2:
Put unread component inside messages, and add one more message into messages, so that the v-for loop will mark it work.
<template>
<div>
<template v-for="(message, index) in messages" :key="index">
<Message :message="message"></Message>
</template>
</div>
</template>
<template>
<message :is="currentComponent"></message>
</template>
<script>
export default {
props: {
message
},
computed: {
currentComponent: function() {
switch (this.message.getType()) {
case "unread":
return "Unread";
// ...
}
}
}
}
</script>
Problem:
Unread is definitely not a message, it seems a trick to make it work well.
I don't think any of the methods suggested above is a good one, does anyone have any solution for this? Thanks in advance.
Method 1 looks fine to me. Method 2, as you say, might be tricky to understand later. Otherwise, you could set a firstUnread property directly on the appropriate message in the array, then test that. You could do this when you load the array, or you could make the array a computed property, so that firstUnread is recalculated whenever the array is changed. Does that help?

Slot: access scope variables

As a simplified example suppose you have this in a component called "my-buttons":
<button v-for='item in items' v-on:click="this.$emit('activate', item)">
<slot>{{ item.name }}</slot>
</button>
If I use the component somewhere else, is there any way to override the slot and access the item.name value? For example:
<my-component items="myItems">
<span class="myspecialstuff">{{ item.name }}</span>
</my-component>
Obviously as it stands now, vue will complain that it can not find item in the scope.
UPDATE2:
the following code does not work due to https://github.com/vuejs/vue/issues/2511. I can't think of anything else. sorry.
UPDATE:
To achieve specific slot overriding, define slots as
<button v-for='item in items' v-on:click="this.$emit('activate', item)">
<slot v-bind:name="'item-'+item.name">{{ item.name }}</slot>
</button>
and override as
<my-component items="myItems">
//you have access to items so you can do this
//specialItems is an array of items which are to be overriden
<span class="myspecialstuff" v-for="item in specialItems" v-bind:slot="'item-'+item.name" >
{{ item.name }}
</span>
</my-component>
Original answer:
that will be very convoluted imho.
there are 2 ways to achieve what you want depending on where <my-component is getting items.
items is passed to my-component as props. (most common case). In that case, you already have access to items and do not need to jump through hoops for it.
<my-component> is getting items through some external sources like a form or api.(less likely) in this case, you can either raise events to pass data or use 2-way bindings through .sync

Categories

Resources