Vue data variable not updating after language change - vue.js

I have a data variable as follows:
data(){
return {
amount: {
active: false,
name: this.$i18n.t('key_name'),
value: this.$i18n.t('key_value')
}
}
}
The data variable is using localized string. The issue is that, when I change the language from a dropdown, the amount variable is not updating until any other event occurs. I believe this has something to do with the $nextTick().
But not sure how to handle this properly as to have the changes reflected immediately in the amount variable.
I can't make it as a computed property as I've to assign values to this variable at a later point.
like this:
this.amount.active = true
How can I solve this?

It's hard to tell how you use Vue i18n, but you can use a watcher as it is stated in the docs and watch for the global i18n.locale object, something like:
<script>
export default {
name: 'app',
data () {
return {
amount: {
active: false,
name: this.$i18n.t('key_name'),
value: this.$i18n.t('key_value')
}
}
},
watch: {
this.$i18n.locale (val) {
this.amount.active = true
}
}
}
</script>
Depends how it's configured in your project.

Related

How to have an if/else statement in a computed/methods property block for VueX?

I have a variable passed into a component called "store". This will store the name of the store that needs to be used in the component. This component just needs to make sure to get the data from the proper store.
computed: {
if (this.store === "storeNumber1")
...mapGetters(this.store, ["thing1", "thing2"]),
else if(this.store === "storeNumber2")
...mapGetters(this.store, ["thing1", "thing2"]),
}
props: {
store
}
This does not work. What would I need to make this concept work? And what about for Vue Mutations? Thank you.
mapGetters isn't meant to be used in a reactive way based on a prop.
Instead, you should use the longhand syntax to access the namespaced getter from the this.$store.getters object:
this.$store.getters[__MODULE_NAME__ + '/' + __GETTER_NAME]
Use that syntax in a computed property for each getter:
export default {
props: {
store: {
type: String,
required: true,
},
},
computed: {
thing1() {
return this.$store.getters[this.store + '/thing1']
},
thing2() {
return this.$store.getters[this.store + '/thing2']
},
},
}
demo
Yes, this does not work. computed properties need to be functions with a simple return. What you want need to be compined between computed and methods:
methods: {
myFunction() {
if (this.store === "storeNumber1") {
return ...mapGetters(this.store, ["thing1", "thing2"])
}
else if(this.store === "storeNumber2") {
return ...mapGetters(this.store, ["thing1", "thing2"])
}
}
}
computed: {
myComputedProperty() {
return this.myFunction()
}
}
props: {
store
}

Use Vue instance inside data() function

First I know its not best practice and not recommended at all, but there are really some rare cases when it might be useful. As an example I am using an external js library to display JSON content and seems the component accepts an options attribute. In this property there are couple of callback function I can use to validate the JSON content.
Here is the implementation:
<v-jsoneditor ref="editor"
v-bind:plus="true"
v-bind:options="options"
height="500px"
v-model="value"
v-on:error="onError">
</v-jsoneditor>
Below is the data function.
data() {
return {
value: "",
options: {
mode: 'code',
onValidate(value) { //this is the function I am talking about
if (Vue.isRequired) {//need the Vue instance here because I can not say this.isRequered
console.log("required");
}
console.log(value);
return null;
}
}
}
}
I know I can have a create method like below and use closure on the vue instance:
async created() {
let vue = this;
this.options.onValidate = function (value) {
if (vue.isRequired) {
console.log("required");
}
console.log(value);
return null;
}
await this.loadRules();
}
but was hoping there is a better way to do it, because create method will look very convoluted if I keep adding more and more callback function like this one.
Is there any better way to access current Vue instance in the data() function ?
The lib I am using is this one.
Seems it much easier than I thought, completely forgot about changing data() to use array function notation like below:
data: (vue) => ({
value: "",
state: null,
errorMessage: "",
showRulesModal: false,
rules: [],
options: {
mode: 'code',
onValidate(json) {
let errors = [];
if (Object.keys(json).length === 0 && vue.isRequired) {
vue.$emit("on-value-validation-failed");
errors.push({
path: [''],
message: 'Value is required to continue'
})
return errors;
}
return null;
}
}
}),
Thanks #Antoly for pointing me to the right direction :)

local storage data not being bound to data

i have a component, which calls a footer component. inside the footer component, i have a modal that shows on click. i want the title of that modal to be a data variable, and i want to set that data variable with data from local storage. for some reason, its not appearing.
I know that the data is in local storage. Any idea's?
export default {
name: "FooterComponent",
data: () => {
return {
privacy_modal: false,
privacy_title: '',
privacy_content: ''
};
},
methods: {
beforeMount() {
this.privacy_title = localStorage.getItem("privacy_title");
}
}
};
beforeMount is a lifecycle hook, not a method. It must be defined directly within options, not inside methods:
export default {
name: "FooterComponent",
data() {
return {
privacy_modal: false,
privacy_title: '',
privacy_content: ''
};
},
beforeMount() {
this.privacy_title = localStorage.getItem("privacy_title"); // || "some default value"
},
methods: {
// custom methods
}
};
Also, don't forget to update local storage, as demanded by your app logic.

How to compute a property based on an object with fallback

I have a component that receives an object as prop, like this:
props: ['propObject']
Then, there's a default object defined (I use VueX, so it's actually defined as a $store getter, but to make it simpler, let's say it's defined in the data method) in the data:
data() {
return {
dataObject: {defaultValueA: 1, defaultValueB: 2}
}
}
And I'd like to have a computed property that would behavior like this:
computed: {
computedObject() {
return Object.values(this.propObject).length > 0 ? this.propObject : this.dataObject;
}
}
However, I know this is not possible because Vue watchers don't watch for changes in the key/value pairs of an object.
I have tried to go with a watched property, like this:
props: ['propObject'],
data() {
return {
object: {},
defaultObject: {}
}
},
watch: {
propObject: {
handler: function() {
this.setComputedObject();
},
deep: true
}
},
methods: {
setComputedObject() {
this.object = Object.values(this.propObject).length > 0 ? this.propObject : this.defaultObject;
}
},
mounted() {
this.setComputedObject();
}
However, the watcher handler is not being called at all when the propObject changes, but if I call it directly via console, it works. Is there any way that I can make the computedObject become reactive?
you need to use Vue.set/vm.$set where you change the props (in source component)
for example
changeProp(){
this.$set(propObject,'newprop','newval');
}
and then just you regualr compouted in the target component (the component which receive the prop)
source : https://v2.vuejs.org/v2/guide/list.html#Object-Change-Detection-Caveats

vue.js two way data-binding between components

Please take a look at this not-working pseudo code:
Vue.component('child', {
props: [],
template: '<div><input v-model="text"></div>',
data: function() {
return {child-text: ""}
}
})
Vue.component('parent', {
template: '<h1> {{text}} </h1>'
data: function() {
return {parent-text: ""}
}
})
What is the most elegant way to fix this code that whenever the user changes the content of input box in child component, then the variable child-text in child component and the variable parent-text in parent component will change automatically? I also want that if the variable child-text and/or parent-text change then the content of input box will change respectively?
I solved this with my own little data store, its a very simple approach but works good enough for me without the necessity to dive into Vuex.
First, I create my data store somewhere before initializing anything else.
window.globalData = new Vue({
data: {
$store: {}
},
});
After that, I add a global Mixin that allows to get and set data to the global storage.
Vue.mixin({
computed: {
$store: {
get: function () { return window.globalData.$data.$store },
set: function (newData) { window.globalData.$data.$store = newData; }
}
}
});
Then, every component can access the data storage by this.$store. You can check a working example here:
https://codesandbox.io/s/62wvro7083