Vue: Functional component doesn't receive props - vue.js

The component smart-list does it's job and is rendering the correct component.
It just doesn't pass on the props. I'd expect them to be in a context.data but it is undefined.
SmartList.vue
import EmptyList from "./EmptyList";
import FullList from "./FullList";
export default {
functional: true,
props: {
items: {
type: Array
}
},
render(h, { props, data, children }) {
if (props.items.length > 0) {
return h(FullList, data, children);
} else {
return h(EmptyList, data, children);
}
}
};
I have prepared a codesandbox example
What do I miss?

I have found the solution. In the smart-list component I've changed one line:
import EmptyList from "./EmptyList";
import FullList from "./FullList";
export default {
functional: true,
props: {
items: {
type: Array
}
},
render(h, { props, data, children }) {
if (props.items.length > 0) {
- return h(FullList, data, children);
+ return h(FullList, { attrs: props }, children);
} else {
return h(EmptyList, data, children);
}
}
};
Now it works.
Can someone point me why passing the full data object doesn't work? 🤔

Related

Pass component reactive value to parent

I have this component with a slider, I have a submit button outside this component, can I somehow pass this timeAnswer value to a parent component, so I can submit the data?
div(v-if="timeConstraint")
VueSlider(
v-model="timeAnswer.duration",
v-bind="sliderOptionsEnd()"
)
const timeAnswer = reactive({ start: 0, duration: 900 });
You can use a computed property with getter/setter:
<vue-slider v-model="sliderValue" />
export default
{
props:
{
modelValue:
{
type: Number,
default: 0
}
},
computed:
{
sliderValue:
{
get()
{
return this.modelValue
},
set(val)
{
this.$emit('update:modelValue', val)
}
}
}
}

How do I make Vue 2 Provide / Inject API reactive?

I set up my code as follows, and I was able to update checkout_info in App.vue from the setter in SomeComponent.vue, but the getter in SomeComponent.vue is not reactive.
// App.vue
export default {
provide() {
return {
checkout_info: this.checkout_info,
updateCheckoutInfo: this.updateCheckoutInfo
}
},
data() {
return {
checkout_info: {},
}
},
methods: {
updateCheckoutInfo(key, value) {
this.checkout_info[key] = value
}
}
}
// SomeComponent.vue
export default {
inject: ['checkout_info', 'updateCheckoutInfo']
computed: {
deliveryAddress: {
get() { return this.checkout_info.delivery_address }, // <---- Not reactive??
set(value) { return this.updateCheckoutInfo('delivery_address', value) }
}
}
}
I found the answer after many hours of searching. You have to use Object.defineProperty to make it reactive. I'm not sure if this is the best approach, but this is a working example.
export default {
data() {
return {
checkout_info: {},
}
},
provide() {
const appData = {}
Object.defineProperty(appData, "checkout_info", {
enumerable: true,
get: () => this.checkout_info,
})
return {
updateCheckoutInfo: this.updateCheckoutInfo,
appData,
}
}
}
You can later access it via this.appData.checkout_info
This note from official documentation.
Note: the provide and inject bindings are NOT reactive. This is
intentional. However, if you pass down an observed object, properties
on that object do remain reactive.
I think this is the answer to your question.
source:
https://v2.vuejs.org/v2/api/#provide-inject
I would put the values in an object:
var Provider = {
provide() {
return {
my_data: this.my_data
};
},
data(){
const my_data = {
foo: '1',
fuu: '2'
};
return {
my_data;
}
}
}
var Child = {
inject: ['my_data'],
data(){
console.log(my_data.foo);
return {};
},
}
When are object properties they are reactive. I don't know if this is the correct solution but it works in my case.

Vuex action payload is undefined

I have a component that looks like this(simplified):
<script>
import { mapActions } from 'vuex';
import router from '#/router';
import { bindingService } from '#/_services/binding.service';
export default {
props: {
serialNumber: { type: String, default: ' ' }
},
data: () => ({
subscriptions: ['Loading...'],
vin: null,
}),
computed: {
splittedSerialNumber() {
return this.serialNumber.split(' ')[0];
}
},
created() {
//fetch some data
bindingService.fetchSomeData('xxx').then((data) => {
this.vin = data;
});
},
methods: {
...mapActions('binding', ['setDeviceSerialNumber', 'setVehicleIdentificationNumber']),
cancel() {
router.push('/home');
},
ok() {
console.log(this.vin); //this console.log outputs valid data
this.setVehicleIdentificationNumber(this.vin);
},
},
};
</script>
Then I have my store that look like this(simplified):
const state = {
vehicleIdentificationNumber: null,
};
const actions = {
setVehicleIdentificationNumber({ commit }, { vin }) {
console.log(vin); // this console.log outputs undefined
commit('SET_VEHICLE_IDENTIFICATION_NUMBER', vin);
}
};
const mutations = {
SET_VEHICLE_IDENTIFICATION_NUMBER(state, vin) {
state.vehicleIdentificationNumber = vin;
},
};
const binding = {
namespaced: true,
state,
actions,
mutations,
};
export default binding;
I'm even more confused because I've been using pretty much the same format of actions and mutations in this project and they work.
I'm out of ideas and looking forward to any kind of input :)
In your setVehicleIdentificationNumber method on the component, you are passing in the vin as an integer argument.
In the action, the param is an object: { vin }.
Change the action param to vin, or pass in an object in the component: { vin: this.vin }
I think the problem here is that your vin property isn't reactive because you initialized it with a null value, but you're changing it to an object. Try this:
bindingService.fetchSomeData('xxx').then((data) => {
Vue.set(this, 'vin', data)
});
Of course, you'll need to import Vue from 'vue'
You should pass the data to the action like this:
actions: {
myAction( store, payload = {myCustomKey: 'my value 1'} ){
store.commit('myCustomMutation', payload.myCustomKey);
}
}
And later уоu can call the action with or without the data:
this.$store.dispatch('myAction');
this.$store.dispatch('myAction', 'my value 2');

Unknow error in vuejs2

I am new in vuejs2. I am getting below error. Could anyone say why this error is coming ? Could you please provide any sample solution for this ?
ModalBody.vue
<script>
import SemanticModal from 'vue-ya-semantic-modal'
export default {
components: { SemanticModal: SemanticModal() },
name: 'ModalBody',
props: {
active1: {
required: true
}
},
}
</script>
DataTable.vue
<script>
import ModalBody from './ModalBody'
export default {
components: { ModalBody },
data: function () {
return {
active1: false
}
},
props: {
columns: {
required: true
},
gdata: {
required: true
}
},
methods: {
show () {
this.active1 = true
}
},
}
Use computed Property(eg.isActive) for passing to children component
import ModalBody from './ModalBody'
export default {
components: { ModalBody },
data: function () {
return {
active1: false
}
},
props: {
columns: {
required: true
},
gdata: {
required: true
}
},
computed:{
isActive (){
return this.active1;
},
methods: {
show () {
this.active1 = true
}
},
}
And Pass this computed property to child component in template
<modal-body :active1='isActive'></modal-body>
By doing this it avoid mutation
Finally I got the solution. I added child component to parent component as like below
<modal-body :active1="active1" #sendValue="active1 = $event"></modal-body>
I added methods like below in Parent Component
methods: {
close() {
this.$emit('sendValue', false);
}
}
In vue prop mutating is anti pattern look here

How to re-render vue js using emit event

I have a global.js and I'm emitting an event to global.js What I want to achieve is whenever the value of my global.js re-render the vue.
global.js
export let globalStore = new Vue({
data: {
translateBool: 0,
about: [`About Us`,`フィリピンのマニラに 2015年9月に設立。`]
},
methods: {
changeLanguage(){
if(this.translateBool == 0){
this.translateBool= 1
}else{
this.translateBool= 0
}
}
}
})
globalStore.$on('changeLanguage',globalStore.changeLanguage)
click.vue
import { globalStore } from '../../global.js';
export default{
name: "sample",
data(){
return{
language: globalStore.translate
}
},
methods : {
changeLanguage(){
globalStore.$emit('changeLanguage')
},
}
}
}
</script>
{{language}}
Even though translateBool is = 1, the output doesn't change
The data properties set in the data method are only set once during the Vue instance's initialization.
If you want the language property to update based on the current state of the globalStore.language value, you should make it a computed property:
export default {
name: "sample",
computed: {
language() {
return globalStore.translate
}
},
methods: {
changeLanguage() {
globalStore.$emit('changeLanguage')
}
}
}