Buefy field does not react on :message param change - javascript

I have a Nuxt project with Buefy components. There is a form with some field component which should react on error according the message parameter for this component. But does not. I can see the correct value in debuger but component does not show the message. :message property should work like the in first email example from documentation
The code looks like:
<template #company>
<h2 class="title">{{ $t('general.login.create_company') }}</h2>
<b-field
:type="loginErrors.company_name ? 'is-danger' : ''"
:message="loginErrors.company_name ? loginErrors.company_name : ''"
>
<b-input
v-model="companyName"
name="company_name"
type="text"
autocomplete="off"
:placeholder="$t('general.login.create_company')"
></b-input>
</b-field>
<div class="buttons is-centered">
<b-button type="is-primary is-light" #click="createCompany">Save</b-button>
</div>
</template>
...
data() {
return {
...
loginErrors: {},
error: 'aaaaaa',
};
},
...
async createCompany() {
const result = await this.$api.users.createCompany({company_name: this.companyName});
if( result.error ) {
this.loginErrors.company_name = result.error; // This does not work although the variable has correct value set
this.error = result.error; // This works fine
return false;
}
},
I use this pattern in other components and it works. I dont understand it. thaks for any help.

change detection of data objects in Vue is shallow (top level only)
In vue.js, Dynamically added property to an object is not reactive. Instead we can assign a whole object so that change detection happen.
For a better understanding please go through this official documentation of Vue.
Demo :
new Vue({
el: '#app',
data() {
return {
loginErrors: {}
}
},
mounted() {
this.loginErrors = {
company_name: 'some value'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>{{ loginErrors.company_name ? 'is-danger' : 'no-danger' }}</p>
</div>

I don't think Vue components react to object property changed in a direct way, you could try this.$set(this.loginErrors, 'company_name', result.error); instead of this.loginErrors.company_name = result.error;
FYI: https://v2.vuejs.org/v2/guide/reactivity.html?redirect=true#Change-Detection-Caveats

The solution in this case was to update Buefy version from 0.4.11 to 0.4.21. This fix the issue. Another thing is that is causes new issue with :type in combination with grouped param.

Related

how can I deal with null errors in axios and vue

Axios and Vuejs
I am receiving data from the api,
but some items are null,
and I get a message on the console,
how can I deal with these errors
I tried to make a filter but it didn't work.
link: App
It would help if you could post some of your code from your Vue component, but there are many ways to deal with this. In general, you need to check for the value before displaying. Below are a couple of ways you could do this with Vue.
One way is using v-if. If the network is not null, show the network
<div v-if="show.network">{{ show.network }}</div>
You could also use a v-else directive to display something else
<div v-if="show.network">{{ show.network }}</div>
<div v-else>network unavailable</div>
Another way is to use a computed property.
<template>
<div>
<div>{{ network }}</div>
</div>
</template>
<script>
export default {
data: function() {
return {
show: {
network: null
}
}
},
computed: {
network() {
return ( this.show.network ) ? this.show.network : "not available";
}
}
};
</script>
The list goes on... As the developer, you will need to check the value to determine if it can be shown before displaying it.
From your template, you can use this code:
<p><span>Network: </span>{{ result.show?.network?.name || '' }}</p>
All browsers dont support ? so below will always works:
<p><span>Network: </span>{{ result.show && result.show.network && result.show.network.name }}</p>

Vue component not updating when data changes without :key

I have this simple breadcrumbs component inside my app. There is a data property pickedTable but when it changes the component doesn't re-render. But when I add the :key="pickedTable" then it re-renders. Why is this happening?
Has anyone else experienced this issue?
export default {
template: `
<div class="cr-snackbar">
<div class="cr-snackbar-selection">
Table {{ pickedTable }}
</div>
</div>
`,
data()
{
return {
pickedTable: '2',
}
},
mounted()
{
setInterval(() => {
this.pickedTable = '3'
}, 3000)
}
}
My solution was to add the key
<div class="cr-snackbar-selection" :key="pickedTable">
Table {{ pickedTable }}
</div>
This is not an issue but a feature.
Vue uses an algorithm that minimizes element movement and tries to patch/reuse elements of the same type in-place as much as possible. With keys, it will reorder elements based on the order change of keys, and elements with keys that are no longer present will always be removed/destroyed.
Here is the official doc : https://v2.vuejs.org/v2/api/#key
And here is a nice article on component re-rendering : https://michaelnthiessen.com/force-re-render/

Unable to set VueJs Component data values from component prop

For some reason, the value for customer_data.customerReference is never available yet I can see using Chrome debugging tools that the data exists in the prop and is successfully passed from my app down to the component.
Vue.component("mycomponent", {
template: '#my-component-template',
props: ["customer_data"],
data() {
return {
myData: 'This works fine!',
form_data: {
customerRef: this.customer_data.customerReference
}
}
}
});
new Vue({
el: "#app",
data() {
return {
customer: {
customerReference: 007
}
};
}
});
Here is my markup including the template:
<div id="app">
<mycomponent customer_data="customer" />
</div>
<script type="x-template" id="my-component-template">
<div>
<p>{{form_data.customerRef}}</p>
<p>{{myData}}</p>
</div>
</script>
Please see the following JsFiddle with a simplified example:
https://jsfiddle.net/ProNotion/a8c6nqsg/20/
What is that I am missing here or implementing incorrectly?
You should bind it using v-bind: or just :
<div id="app">
<mycomponent :customer_data="customer" />
</div>
https://v2.vuejs.org/v2/guide/components-props.html
You're passing in a string that says 'customer' and not the actual customer object. All you need to do is change customer_data="customer" to v-bind:customer_data="customer"

Props are somehow getting mixed between components

I'm passing two different arrays to the same component but two different instances of it. Then inside those instances I do a v-for and send a single item of array to another component using props. The problem is that when I inspect the Vue tools for the last component, I see that the prop is good but when I try to assign it to data it returns the prop from previous array(the one that was sent to another component).
Laravel:
<co-notifications class-name="writable" nots="{{ $notifications[0] }}"></co-notifications>
<co-notifications class-name="writable extended" nots="{{ $notifications[1] }}"></co-notifications>
CoNotifications:
<template>
<div>
<div v-for="notification in notifications">
<co-notification-item :class-name="className" :not="notification"></co-notification-item>
</div>
</div>
</template>
<script>
import notificationComponent from './NotificationComponent.vue';
export default {
props: ['className', 'nots'],
components: {
'co-notification-item': notificationComponent
},
// data() {
// return {
// notifications: JSON.parse(this.nots),
// }
// },
computed: {
notifications(){
return JSON.parse(this.nots)
}
},
}
</script>
CoNotificationItem
<template>
<div :class="['tableItem',className]">
<div class="textareaWrapper">
<input type="text" class="form-control" placeholder="Title" v-model="notification.title" v-if="notification.type === 'main'">
<textarea class="form-control" rows="6" placeholder="Some text..."
v-model="notification.text"></textarea>
</div>
<div class="buttonWrapper">
<button type="button" class="btn btn-success" #click="updateNotification"><i
class="fe fe-check mr-2"></i>Save
</button>
<button type="button" class="btn btn-danger" #click="deleteNotification"><i
class="fe fe-check mr-2"></i>Delete
</button>
</div>
</div>
</template>
<script>
import notificationComponent from './NotificationComponent.vue';
export default {
props: ['className', 'not'],
components:{
'co-notification-item': notificationComponent
},
data(){
return {
notification: this.not
}
},
methods: {
updateNotification(){
this.notification.text = "test";
},
deleteNotification(){
}
}
}
</script>
As for the data in arrays, I have 2 in the arr(0) and 2 in arr(1).
When I open Vue tools on the FIRST notifications I see this (THIS IS GOOD)
However, when I open other notifications that read from arr(1) I see this (this is obviously not how it's supposed to be)
As you can see I used computed for the CoNotification but if I remove it and use only data() both nots recieve the same array, but if I use computed it is okay. However, I can't use computed in CoNotificationItem beacuse I need to have it in data() so I can bind it with v-model.
So, my question is, how to make notification on the CoNotificationItem be the same as not (variable) but be accessible in data() so I can put v-model to it - why am I getting mixed values?
Note: I also tried with computed and watch and created/mounted.
I've been stuck at this problem for half the day and I searched my as* off both in official docs and tutorials/questions on stackoverflow and whatnot.
Some searches that I tried :
Vue.js passing props to data
Passing data from Props to data in vue.js
https://forum.vuejs.org/t/update-data-when-prop-changes-data-derived-from-prop/1517
Adding unique key property to each v-for item will solve the problem
<div v-for="notification in notifications" :key="someUniqueKey">
<co-notification-item :class-name="className" :not="notification"></co-notification-item>
</div>
I can not explain it clearly. But as i understand, Vue tracking elements by key property. Give these elements unique key will tell Vue that they are different elements. So it will prevent Vue re-using prop and data.
If anyone can explain more detail and refer document please add comment or new answer. I will delete my answer.

Binding Input in Vue not working

I would like to call a function with a value when a user starts typing in an input box. I have tried two approaches.
The first approach is trying to use two-way binding to a model. However, after following the documentation I get an error.
Here is the example from the official docs:
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
And here's my example:
<template lang="html">
<input
type="text"
v-model="handle"
/>
</template>
<script>
export default {
data: {
handle: 'model',
}
};
</script>
I am writing this as part of an application so I chose not to recreate the Vue instance and I declared that elsewhere. However, I get this error:
Property or method "handle" is not defined on the instance but referenced during render. Make sure to declare reactive data properties in the data option.
A second approach I've tried is this calling a function directly from the view via an event handler. I'm coming from React so this is my preferable approach. However, the function has undefined as an input value meaning it's not picking up the value of the input.
<template lang="html">
<input
type="text"
v-on:keyup="handleInput()"
/>
</template>
<script>
export default {
methods: {
handleInput(input) {
// input -> undefined
},
},
};
</script>
I really can't see why neither of these works. Wouldn't the expected behavior of an input listener would be to pass the value?
Where am I going wrong?
It seems like you might have to do something like this: How to fire an event when v-model changes ? (vue js). What I don't understand is why you have to manually attach a watcher when you have assigned a v-model? Isn't that what a v-model is supposed to do?
What finally worked was this:
<template lang="html">
<input
type="text"
v-model="searchTerm"
#keyup.enter="handleInput"
/>
</template>
<script>
export default {
data() {
return { searchTerm: '' }
},
methods: {
handleInput(event) {/* handle input */},
},
};
</script>
Shouldn't data be a function on your first example? I think this is how it works for vue components.
<script>
export default {
data: function () {
return { handle: 'model' }
}
};
</script>
I think this was explained somewhere on vuecasts.com, but I might be wrong. :)

Categories