Redux - Filterable category with products - Actions & Filter - api

My state looks exactly like this:
{
categories: {
"unique-category-id" {
"data": {
// All kind of data (name, description ,etc )
"products": [
{
// Products that belong to this category with the current filter
}
]
},
"readyState": "CATEGORY_FETCHED",
"query": { // This object holds all the params that the filter allows to choose from
"brands": [],
"options": {
"usb": true
"minPrice": 200
}
}
}
}
}
This works and fetches data correctly. Now it's time to implement the filtering funcionality. I am trying to make it work like this, not sure if this is the "redux" way of doing things.
1.- On each filter on the category page we assign a click handler:
<li onClick={this.toggleFilterField} key={item.VALUE}>{item.NAME}</li>
toggleFilterField is passed into the container via mapDispatchToProps:
const mapDispatchToProps = (dispatch) => {
return {
toggleFilterField: (category, filter) => {
dispatch(toggleFilterField(category, filter))
}
}
}
export { CustomTagFilter };
export default connect(null, mapDispatchToProps)(CustomTagFilter);
2.- My toogleFilterField should just return an action like this one:
return {
type: CHANGE_FILTER,
category,
filter
}
Then my category_reducer.js should handle this action and update the following state key
state.categories[unique-category-id].query
Now this is OK, but now, after applying the filter to the state I would have to refetch the data from the category.
How and where do I fire a new action based on a previous action success?
Is this the correct way of handling filtered elements in redux that come from a paginated API?

Related

Retrieve config value from sales channel in plugin settings

How can I retrieve values from the plugin config for a specific sales channel? I need to validate an API-Token, but can only retrieve the value stored for all sales channels and don't know how my custom admin component could even know about its current sales channel.
Currently, I am retrieving values via the following code, which follows the example plugin from Shopware, but they too only retrieve the global value.
Component.register('my-component', {
computed: {
getMyKey() {
return this.pluginConfig['MyPlugin.config.myKey'];
},
pluginConfig() {
let $parent = this.$parent;
while ($parent.actualConfigData === undefined) {
$parent = $parent.$parent;
}
return $parent.actualConfigData.null;
}
}
}
You may want to inject systemConfigApiService and use it to retrieve the config values. getValues takes a second argument for the sales channel id.
Component.register('my-component', {
inject: ['systemConfigApiService'],
methods: {
getConfig(salesChannelId) {
const values = this.systemConfigApiService
.getValues('MyPlugin.config', salesChannelId);
return values.myKey;
},
},
}

Calling function in VueApollo after API response

I am using Vue and Apollo and I am making a querie that looks just like the box below.
After I get the API response, I would like to call a method from my methods object. However Vue, doesn't give me acess to it within apollo object.
I would like to know how can I call one of my methods, but only after I am sure I got that response, without having to manually trigger it with a button or something else.
apollo: {
materials: {
query: gql`
query allMaterials($tenantId: ID, $name: String) {
tenantMaterials(tenantId: $tenantId, name: $name) {
edges {
node {
name
materialType {
name
id
}
brand
vendor
size
unit
inventory
createdAt
updatedAt
isActive
updatedBy
id
}
}
totalCount
}
}
`,
variables() {
return {
name: null
};
},
fetchPolicy: "cache-and-network",
update: response => {
return response.tenantMaterials.edges;
//I want to call a function/method after this response
},
skip: false
},
}
Use update(data) or result(result, key)
update(data) {return ...} to customize the value that is set in the
vue property, for example if the field names don't match.
result(ApolloQueryResult, key) is a hook called when a result is
received (see documentation for ApolloQueryResult (opens new window)).
key is the query key in the apollo option.
https://apollo.vuejs.org/api/smart-query.html

VueJS/vuex application design question - how to initialize local data with getters

Context:
I have a reports application that contains a report editor. This Report Editor is used to edit the contents of the report, such as the title, the criteria for filtering the results, the time range of results, etc..
The Problem:
There is something wrong with the way I have used Vuex/Vuejs in my components I believe. My store contains getters for each aspect of this report editor. Like this:
const getters = {
activeReportTitle: state => {
return state.activeReport.title;
},
activeReportID: state => {
return state.activeReport.id;
},
timeframe: state => {
return state.activeReport.timeframe;
},
includePreviousData: state => {
return state.activeReport.includePreviousData;
},
reportCriteria: state => {
return state.activeReport.reportCriteria;
},
emailableList: state => {
return state.activeReport.emailableList;
},
dataPoints: state => {
return state.activeReport.configuration?.dataPoints;
},
...
Each getter is used in a separate component. This component uses the getter only to initialize the local data, and uses actions to modify the state. The way I have done this is by adding a local data property and a watcher on the getter that changes the local data property. The component is using the local data property and that data property is sent to the action and the getter is updated.
ReportSearchCriteria.vue
...
data() {
return {
localReportCriteria: [],
currentCriteria: "",
};
},
watch: {
reportCriteria: {
immediate: true,
handler(val) {
this.localReportCriteria = [...val];
}
}
},
computed:{
...reportStore.mapGetters(['reportCriteria'])
},
methods: {
...reportStore.mapActions(["updateReportCriteria"]),
addSearchCriteria() {
if (this.currentCriteria) {
this.localReportCriteria.push(this.currentCriteria);
this.updateReportCqriteria(this.localReportCriteria);
}
this.currentCriteria = "";
this.$refs['reportCriteriaField'].reset();
},
...
The hierarchy of the components is set up like this
Reports.Vue
GraphEditor.vue
ReportSearchCriteria.vue
Could you clarify what the problem is? Does the 'reportCriteria' not get updated when it's supposed to? How does the function 'updatedReportCriteria' look like? You use mutations to update a state in the store. Also, you have a typo when you're calling the action.

Vue.js reactivity of complex objects in a store

My Problem
I am trying to store a list of complex items in a store and access these items from a component. I have a mqtt interface which receives data for these items and updates their values in the store. However, the ui does not react to updating the properties of these items.
Structure
In my store, i have two mutations:
state: {
itemList:{}
},
mutations: {
/// adds a new item to itemList
[ADD_ITEM](state, item) {
if (item&& !state.itemList[item.itemId])
{
Vue.set(state.itemList, item.itemId, item);
}
},
/// updates an existing item with data from payload
[SET_ITEM_STAT](state, { itemId, payload }) {
var item= state.itemList[itemId];
if (item) {
item.prop1 = payload.prop1;
item.prop2 = payload.prop2;
}
}
},
actions: {
/// is called from outside once when connection to mqtt (re-)established
initializeMqttSubscriptions({ commit, dispatch }, mqtt){
mqtt.subscribeItem("items/stat", async function(itemId, topic, payload) {
commit(SET_ITEM_STAT, { itemId, payload });
});
},
...
}
I also tried:
setting the item properties using Vue.set(state.itemList, itemId, item);
setting the item properties using Vue.set(state.itemList[itemId], 'prop1', payload.prop1);
I also want to show how i built the Component which accesses and displays these items (Item.vue). It is one component, that gets passed the itemId to show via the route params. I've got the following computed properties:
<template>
<div class="grid-page">
<h1 class="page-title">Item- <span class="fw-semi-bold">{{ id }}</span></h1>
<div>
<Widget v-if="item">
{{ item.prop1 }}
...
...
computed: {
id(){
return this.$route.params.itemId;
},
item(){
return this.$store.state.items.itemList[this.id];
}
}
So when the route parameter itemIdchanges, i successfully can see the item data, everything is fine. But if i update the properties of an item with the mutation shown above, no update in view is triggered.
I would be very happy if someone could give me a hint what i am doing wrong here. Thanks in advance!
Since i can't comment to ask for some clarifications,
If you're itemlist is an nested object, try out with Object.assign
[SET_ITEM_STAT](state, { itemId, payload }) {
var item= state.itemList[itemId];
if (item) {
this.state.itemList[itemId] = Object.assign({}, this.state.itemList[itemId].prop1, {payload.prop1})
this.state.itemList[itemId] = Object.assign({}, this.state.itemList[itemId].prop2, {payload.prop2})
// or
this.state.itemList[itemId] = Object.assign({}, this.state.itemList[itemId], {prop1: payload.prop1, prop2: payload.prop2})
}
}
Let me know how it goes
https://v2.vuejs.org/v2/guide/reactivity.html#For-Objects

Custom Searchbox for vue-table-2

Using Vue Table 2, I do not want to use the default search/filter input and the Records drop down. I.e. I do not want to use controls in the image below:
Instead, I want to create my own input box outside the table. I am able to hide the default row containing the image above. However, after adding my own input box - example:
<input type="text" v-model="searchTerm" v-on:keyup='filterResult()' />,
How can I trigger the filter event to process my filter request in the filterResult() method?
data(){
return {
searchTerm:'',
customFilters: [{
name: 'mysearch',
callback: function (row, query) {
return row.name[0] == query;
}
}],
},
},
methods:{
filterResult(){
//how to trigger event to filter result using the searchTerm
}
}
Given a table definition like this, where tableoptions its an object containing the options you are applying to your table(these have to match their documentation), in this case i'm only adding customFilters, but you might have columns, headings or others
<v-client-table :options="tableoptions">
</v-client-table>
In their documentation it says that you should use this to trigger the custom filter
Event.$emit('vue-tables.filter::alphabet', query);
But it fails to say that Event it's VueTables.Event, so you will need to update your js to the following:
data() {
return {
searchTerm: '',
tableoptions: {
customFilters: [{
name: 'mysearch',
callback: function(row, query) {
//this should be updated to match your data objects
return row.name[0] == query;
}
}]
},
},
},
methods: {
filterResult() {
VueTables.Event.$emit('vue-tables.filter::mysearch', query);
}
}