I have a field defined as follows:
<Field
class="form-control form-control-solid"
:value="tradeSizeFactor"
name="tradeSizeFactor"
:v-model="tradeSizeFactor"
/>
In my setup I watch if the value of property changed and if so I get the new value for for example the tradeSizeFactor:
setup(props)
{
const copyAccountId = ref(props.copyAccountId);
const copyAccountName = ref(props.copyAccountName);
let tradeSizeFactor = ref(0);
watchEffect(() => {
console.log(`watch Effect id: ${props.copyAccountId}`);
console.log(`watch Effect name: ${props.copyAccountName}`);
copyAccountId.value = props.copyAccountId;
if (props.copyAccountId !== 0) {
getSettings(props.copyAccountId);
}
});
async function getSettings(copyAccountId) {
store
.dispatch(Actions.GET_COPYACCOUNTSETTINGS, copyAccountId)
.then((data) => {
console.log(
`data: ${JSON.stringify(data.data.settings.tradeSizeFactor)}`
);
Object.assign(copyAccountSettings.value, data.data.settings);
tradeSizeFactor = data.data.settings.tradeSizeFactor;
});
}
return {
tradeSizeFactor,
};
}
Whatever I try however, the value of tradeSizeFactor is not updating in the Field. It keeps showing 0...
In the following line, you're incorrectly overwriting the ref with a literal:
tradeSizeFactor = data.data.settings.tradeSizeFactor;
^^^^^^^^^^^^^^^
tradeSizeFactor is a ref, so the value must be changed via its value property:
tradeSizeFactor.value = data.data.settings.tradeSizeFactor;
👆
Related
I have this watcher, where I am changing value of the activeTable - this value is stored inside Pinia store:
const { tables, freeTables, usedTables, activeTable, selectedTable } = storeToRefs(useTableStore())
watch([tables, urlPath], (newValue, oldValue) =>
{
if(urlPath.value[0] === 'tables' && Number.isInteger(+urlPath.value[1]))
{
let tableIndex = tables.value.findIndex(table =>
+table.id === +urlPath.value[1]
)
if(tableIndex > -1)
{
let table = tables.value[tableIndex]
if(+table.userID === +userData.id || +table.waiterID === +userData.id)
{
mineButton.click();
}
else
{
document.getElementById('other-tables').click()
}
activeTable.value = table
}
}
})
In another component I am watching activeTable
const {showTableOrder, activeTable, selectedTable} = storeToRefs(useTableStore())
watch(
() => activeTable.value,
async (newValue, oldValue) => {
console.log(newValue);
console.log(oldValue);
},
{ deep: true }
)
If you refresh the page, the first watcher is working as expected, and activeTable is set properly, but the second watcher is never activated. What am I doing wrong here?
I have 1 component to which I pass a computed as a prop in this way:
<Datatable :extraParams="extraParams" />
the computed is in the attached image.
I'm having trouble with the value of this property: coverageSelected:coverageData
Coverage data is filled by a select multiple
The problem I have is that when selecting an element of the select, first the component function is executed, then the coverageSelected property is empty, then the computed is executed and until this moment the coverageSelected array is filled, then until the second attempt It already has a full array.
This is my computed
props: [
"status_selected",
"rows",
"totals",
"dateRangeValue",
"coverageSelected",
"coverageList",
"showAll",
"dateFilterSelected",
],
computed(){
extraParams() {
let coverageData = this.coverageList.filter((m) => this.coverageSelected.includes(m.variable));
return {
status: this.status_selected,
dateRange: this.dateRangeValue,
dateFilterSelected: this.dateFilterSelected,
coverageSelected: coverageData, //This is the property that is not late.
showAll: this.showAll,
};
},
}
Another detail to mention that this.coverageSelected is a prop
The method that is executed first in the computed is this:
async getList(params) {
this.loading = true;
try {
if (params) {
this.query = { ...this.query, ...params, ...this.extraParams, filters: this.filters };
} else {
this.query = { ...this.query, ...this.extraParams, filters: this.filters };
}
const { data } = await this.$axios.post(`${this.$config.routePrefix}${this.action}`, this.query);
if (data.code == 200) {
this.rows = data.rows;
this.total = data.total;
this.$emit("listed", data);
}
} finally {
this.loading = false;
}
},
I am attempting to persist a Window object in Local Storage in my Vue project via JSON.stringify with a replacer.
Since Window has a circular structure, I can't use JSON.stringify by itself.
So I've researched the usage of the replacer.
I came across this implementation:
const getCircularReplacer = () => {
console.log("replacer called...");
const seen = new WeakSet();
return (key, value) => {
if (typeof value === window && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
The following replacer implementations didn't work for me....meaning that the getCircularReplacer() method doesn't get called.
const winClean = JSON.stringify(win, getCircularReplacer());
but wrapping the replacer in a function seems to do the trick and it calls the getCircularReplacer method
const winClean = JSON.stringify(win, function () { getCircularReplacer(); });
Another issue is that the winClean returns 'undefined'.
I tested the getCircularReplacer with the following modifications:
if (typeof value === 'object' && value !== null)
and
if (typeof value === window && value !== null) {
and
if (typeof value === Window && value !== null) {
to no avail.
Here's the full code in HellowWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<div>
Google |
Bing |
Yahoo |
BBC
</div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
methods: {
openWindow(url, name) {
console.log(url + " | " + name);
const win = window.open(url, name);
console.log("window name: " + win.name);
console.log(win);
const getCircularReplacer = () => {
console.log("replacer called...");
const seen = new WeakSet();
return (key, value) => {
if (typeof value === window && value !== null) {
if (seen.has(value)) {
return;
}
seen.add(value);
}
return value;
};
};
const winClean = JSON.stringify(win, function () {
getCircularReplacer();
});
console.log(winClean);
},
},
};
</script>
Could anybody please clarify why my winClean is undefined and how to correctly stringify my window object to avoid the "Converting circular structure to JSON" error.
Thank you!
I'm using Pinia as Store for my Vue 3 application. The problem is that the store reacts on some changes, but ignores others.
The store looks like that:
state: () => {
return {
roles: [],
currentRole: 'Administrator',
elements: []
}
},
getters: {
getElementsForCurrentRole: (state) => {
let role = state.roles.find((role) => role.label == state.currentRole);
if (role) {
return role.permissions.elements;
}
}
},
In the template file, I communicate with the store like this:
<template>
<div>
<draggable
v-model="getElementsForCurrentRole"
group="elements"
#end="onDragEnd"
item-key="name">
<template #item="{element}">
<n-card :title="formatElementName(element.name)" size="small" header-style="{titleFontSizeSmall: 8px}" hoverable>
<n-switch v-model:value="element.active" size="small" />
</n-card>
</template>
</draggable>
</div>
</template>
<script setup>
import { NCard, NSwitch } from 'naive-ui';
import draggable from 'vuedraggable'
import { usePermissionsStore } from '#/stores/permissions';
import { storeToRefs } from 'pinia';
const props = defineProps({
selectedRole: {
type: String
}
})
const permissionsStore = usePermissionsStore();
const { getElementsForCurrentRole, roles } = storeToRefs(permissionsStore);
const onDragEnd = () => {
permissionsStore.save();
}
const formatElementName = (element) => {
let title = element.charAt(0).toUpperCase() + element.slice(1);
title = title.replace('-', ' ');
title = title.split(' ');
if (title[1]) {
title = title[0] + ' ' + title[1].charAt(0).toUpperCase() + title[1].slice(1);
}
if (typeof title == 'object') {
return title[0];
}
return title;
}
</script>
My problem is the v-model="getElementsForCurrentRole". When making changes, for example changing the value for the switch, the store is reactive and the changes are made successfully. But: If I try to change the Array order by dragging, the store does not update the order. I'm confused, because the store reacts on other value changes, but not on the order change.
What can be the issue here? Do I something wrong?
-Edit- I see the following warning on drag: Write operation failed: computed value is readonly
Workaround
As workaround I work with the drag event and write the new index directly to the store variable. But...its just a workaround. I would really appreciate a cleaner solution.
Here is the workaround code:
onDrag = (event) => {
if (event && event.type == 'end') {
// Is Drag Event. Save the new order manually directly in the store
let current = permissionsStore.roles.find((role) => role.value == permissionsStore.currentRole);
var element = current.permissions.elements[event.oldIndex];
current.permissions.elements.splice(event.oldIndex, 1);
current.permissions.elements.splice(event.newIndex, 0, element);
}
}
You should put reactive value on v-model.
getElementsForCurrentRole is from getters, so it is treated as computed value.
Similar to toRefs() but specifically designed for Pinia stores so
methods and non reactive properties are completely ignored.
https://pinia.vuejs.org/api/modules/pinia.html#storetorefs
I think this should work for you.
// template
v-model="elementsForCurrentRole"
// script
const { getElementsForCurrentRole, roles } = storeToRefs(permissionsStore);
const elementsForCurrentRole = ref(getElementsForCurrentRole.value);
I am trying to get products, then check if the product pId is in an array, and filter if it is.
I get an error when i soft refresh of 'TypeError: Cannot read properties of undefined' (reading 'products'), almost like my 'this.products' isnt populated yet when computed is trying to get the data. Tried adding some if statements to check data is there but no luck.
<script>
export default {
data() {
return {
popular_products: [],
products: [],
}
},
computed: {
bestsellers() {
const keywords = this.popular_products
let array = []
for (var index = 0; index < keywords.length; index++) {
const keyword = this.products.data.products.product.filter(
(product) => product.pId == keywords[index].ProductNumber
)
array = array.concat(keyword)
}
return array
},
},
mounted() {
axios
.get(
'https://myurl/admin/api/collections/get/popularproducts?token=account-9306f9192049d3c442e565f2de5372'
)
.then((response) => (this.popular_products = response.data.entries))
axios
.get('https://myurl/products.json')
.then((response) => (this.products = response))
},
}
</script>
The problem is with this line:
let keyword = this.products.data.products.product.filter(product => product.pId == keywords[index].ProductNumber);
more specific with this read: data.products.
You see, computed property bestsellers is evaluated before your axios calls are finished.
Because of that, Vue can't find products in data because your this.products doesn't have data key.
The best solution would be to change this assignment:
- .then(response => (this.products = response)); // delete this line
+ .then(response => (this.products = response.data.products)); // add this line
Update After comment.
if (this.products.product) {
return this.products.product.filter(...)
} else {
return []
}