How to store multiple api's data with VueX and add properties to the response - vue.js

Suppose i want to store data from multile Api requests - when the App is instantiated,
and i also want to add properties to each response
Here is the url of the api 'http://api.open-notify.org/iss-pass.json?lat=LAT&lon=LON'
Updated
I want to instantiated the app with all the data from a couple of get requests - so i'm looping all the requests - that part is works fine , but i also want to be able to add to response.data.response object properties from the cities array, so the finale result will be :
cities: [{
id: 0,
cityName: 'Select a city',
stuff from response.data...
},......
Here is the main part of the Api call
const store = new Vuex.Store({
state: {
satelliteData: [],
dataObj:[],
loading: true,
cities: [{
id: 0,
cityName: 'Select a city',
cityLocation: null
},
{
id: 1,
cityName: 'Tel Aviv',
cityLat: '32.0853',
cityLon: '34.7818'
},
{
id: 2,
cityName: 'London',
cityLat: '51.5074',
cityLon: '-0.1278'
},
{
id: 3,
cityName: 'New York',
cityLat: '40.7128',
cityLon: '-74.0060'
},
],
},
actions: {
loadData({commit}) {
for(var i=0; i<this.state.cities.length; i++){
var currData = this.state.cities[i];
if(!!this.state.cities[i].hasOwnProperty('cityLat'))
axios.get(URL, {
params: {
lat: this.state.cities[i].cityLat,
lon: this.state.cities[i].cityLon,
},
}).then((response) => {
Here is where i want to be able to access the Cities array
/* var cities = this.$store.state.cities;
console.log(cities) */
commit('updateSatelliteData', response.data.response)
commit('changeLoadingState', false)
})
}
}
},
Fiddle
Since i'm new to Vue - i'm sure that there are a couple of mistakes here. Thanks

Related

react native redux toolkit how can I pass data to array?

How can I pass data to array (redux toolkit) ?
I tried this but not working.
I have an array of shippers:
const shipper = [
{
type: 'NORMAL',
item: {
id: 1,
name: 'SHIPPER1',
}
},
{
type: 'NORMAL',
item: {
id: 2,
name: 'SHIPPER2',
}
},
{
type: 'NORMAL',
item: {
id: 3,
name: 'SHIPPER3',
}
},
{
type: 'NORMAL',
item: {
id: 4,
name: 'SHIPPER4',
}
},
{
type: 'NORMAL',
item: {
id: 5,
name: 'SHIPPER5',
}
},
];
I want to add each item to the reducer array. Like this without redux.
setShippers(prevState => {
return [...prevState, shipper];
});
But I want it in Redux Toolkit:
slice/shipper.js
import { createSlice } from "#reduxjs/toolkit";
const createProductShipper = createSlice({
name: "createProductShipper",
initialState: {
shippers: []
},
reducers: {
AddProductShipper(state, action) {
state.shippers = [...state.shippers, action.payload];
},
}
});
export const { AddProductShipper } = createProductShipper.actions;
export default createProductShipper.reducer;
...
dispatch(AddProductShippers({id, shipper});
...
..................................................................................................................................................................................................................
I’m a bit confused about whether the shipper variable is an array or a single shipper — and I suspect that you are too.
Your “without redux” example would be the correct way to add a single shipper to the array. If shipper is an array then you’ll want to spread both prevState and shipper:
setShippers(prevState => [...prevState, …shipper]);
The same goes for the redux reducer.
But the way that you are calling the dispatch seems strange:
dispatch(AddProductShippers({id, shipper}));
This will dispatch an action whose payload has properties id and shipper. Is that what you want? What is the id property: the product id or the shipper id?
Assuming that the product id is irrelevant (it appears nowhere in your slice) and that you want to add an array of shippers, your code might look something like this:
dispatch(AddProductShippers(arrayOfShippers));
AddProductShipper(state, action) {
state.shippers = [...state.shippers, …action.payload];
}
Or
AddProductShipper(state, action) {
state.shippers.push(…action.payload);
}

Add object to array in nested json object - Redux

I'm getting a hard time adding an object to an array inside a JSON object.
This is my state:
const DATA =
{
data: [
{
id: 1,
routeName: 'my 2 route',
origin: 'Tel Aviv',
destination: 'Netanya',
date: '25-01-2021',
km: '60',
stops: [
{
id: 0,
address: 'test',
lat: '32.0853',
lon: '34.7818',
customerName: 'test',
tel: '00000',
},
{
id: 1,
address: 'adddress',
lat: '32.0853',
lon: '34.7818',
customerName: 'test',
tel: '00000',
}
],
},
{
id: 2,
routeName: 'my second route',
origin: 'Holon',
destination: 'Hadera',
date: '12-02-2021',
km: '70',
stops: [
{
id: 0,
address: 'address0',
lat: '32.0853',
lon: '34.7818',
customerName: 'customer0',
tel: '00000000',
},
{
id: 1,
address: 'address1',
lat: '32.0853',
lon: '34.7818',
customerName: 'customer1',
tel: '00000000',
},
],
},
],
}
I don't know how to write the reducer, tried few ways but the state doesn't change.
My reducer gets the route id + stop to add this route.
I will be happy for some help here :)
You'll need to find the parent route using the route's id, and then you'll need to create a new stops array by spreading, and adding the new stop.
You can use Array.findIndex() to find the actual route, and the slice the array, and update the route. However, another simple option is to map the data's routes, and update the route with the matching id.
const routeReducer = (state, { type, payload: { routeId, stop } }) => {
switch (type) {
case 'ADD_STOP':
return {
...state,
data: state.data.map(route => route.id === routeId ? {
...route,
stops: [...route.stops, stop]
} : route)
}
}
}
Usually in redux it's better to normalize the state, which makes it easier to update single items.
You could have a reducer that did something like this:
const updateItemInArray = (array, itemId, updateItemCallback) => {
return array.map(item => {
if (item.id !== itemId) return item;
// Use the provided callback to create an updated item
return updateItemCallback(item);
});
};
const data = (state = [], action) => {
switch (action.type) {
case 'ADD_STOP_SUCCESS':
return updateItemInArray(state, action.payload.routeId, (item) => ({...item, stops: [...item.stops, action.payload.stop]}))
default: return state;
}
}
When the action.type 'ADD_STOP_SUCCESS' is called the payload of the action would contain the new stop object you are wanting to add to the state.

Issue with passing the data in Vue / EventBus

I have an issue that I do not understand regarding passing data in Vue.
In store I have the following data (six categories - wine, beer, whiskey, gin, vodka and rum):
state: {
shopItems: [
{
id: 1,
category: "wine",
price: 20,
image:
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD//Z",
items: [
{
id: 1,
name: "Ruby",
price: 17,
image:
"https://images.freshop.com/1564405684707189696/e52a7445e17de485c0ae890de8762d57_medium.png"
},
{
id: 2,
name: "Sauvignon Blanc",
price: 23,
image:
"https://ipcdn.freshop.com/resize?url=https://images.freshop.com/00898322593368/2e0ad0dbe0ef46eded5590acdf43cae5_large.png&width=256&type=webp&quality=40"
},
{
id: 3,
name: "Dark Horse",
price: 25,
image:
"https://ipcdn.freshop.com/resize?url=https://images.freshop.com/00085000024218/680b13803f3203f3117eb69082f95cc2_large.png&width=256&type=webp&quality=40"
},
{
id: 4,
name: "Andree",
price: 35,
image:
"https://ipcdn.freshop.com/resize?url=https://images.freshop.com/00085000008287/17d49b2b92223defb638ca7b535dbab3_large.png&width=256&type=webp&quality=40"
}
]
},
{
id: 2,
category: "beer",
price: 3,
image:
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhAQEg8TFhEXExYSGRcVFRYSEhYVGBUYGBUVFRYcAAEAAgIDAQAAAAAAAAAAAAAABgcEBQEDCAL/",
items: [
{
id: 1,
name: "Banana",
price: 5,
image:
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxAQDxIPEhIPFRAPEhcPEBYSEBgSDw8QFRIS0tLS0uLi0tLS8tLS8tLi0tLS0tLi0tLS8tLS0wLS0tLS0tLS0tLSstLf/AABEIAOEA4QMBEQACEQEDEQH/xAAcAAEAAgIDAQAAAAAAAAAAAAAABQYEBwECCAP/"
},
{
id: 2,
name: "Franziskaner Weissbier",
price: 6,
image:
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEhAQEg8TFhEXExYSGRcVFRYSEhYVGBUDEQH/xAAcAAEAAgIDAQAAAAAAAAAAAAAABgcEBQEDCAL/xABIEAACAgECAgcEBwQFCgcAAAAAAQIDEQQhBRIGBxMiMUFRYXGBwRQjMnKRobFCUpLCJDNigtE0Q1 "
},
{
id: 3,
name: "Birra Moretti",
price: 5,
image:
"data:image/jpeg; QQFEiExBgcTIkFRYXGBFCMycpGhsdEkM0JSYsE1Q1OCkhUWJTREVIOTotLh8PH/xAAaAQEAAwEBAQAAAAAAAAAAAAAAAgMEAQUG/8QANBEBAAICAAQDBQcEAgMAAAAAAAECAxEEEiExE0FRBSIyYXGBkaGxwdHwFEJS4SPxFTOC/9oADAMBAAIRAxEAPwDuMBAQEBAQEBAQEBAQNHau1adKoe59wE7q91mLN5BVBJ+ "
}
]
},
.
.
.
In my application I am passing the data related to the index of the chosen category from ToBeBought component to ShowDetails component – using EventBus.
showDetails(item) {
console.log("#item.category");
console.log(item.category);
const chosenCategoryIndex = this.shopItems.findIndex(
i => i.category === item.category
);
// const chosenCategoryItems = this.shopItems[chosenCategoryIndex]
// .items;
console.log("#chosenCategoryIndex");
console.log(chosenCategoryIndex);
EventBus.$emit("chosenCategory", chosenCategoryIndex);
this.$router.push("/details");
I pass the index of the chosen category - e.g. for wine index is 0.
I run chosenCategoryItems method on mounted
(I tried running it on created as well but it did not help)
to get the data in ShowDetails component. In console.log from this method I get an array with detailed data e.g. wines but after that method in mounted I have another console log to show the array (console.log(this.detailedItemsToBeBought);) - I get undefined from it.
It looks like the data was cleared in the meantime - I do not get what is going on here.
I tried to add watcher on detailedItemsToBeBought data but it is not being triggered.
data() {
return {
itemsToBeBought: [],
detailedItemsToBeBought: []
};
},
mounted() {
this.chosenCategoryItems();
console.log("#detailedItemsToBeBought mounted");
console.log(this.detailedItemsToBeBought);
console.log("#this.shopItems[0].items");
console.log(this.shopItems[0].items);
},
methods: {
chosenCategoryItems() {
EventBus.$on("chosenCategory", data => {
const chosenCategoryIndex = data;
console.log("#chosenCategoryIndex");
console.log(chosenCategoryIndex);
this.detailedItemsToBeBought = this.shopItems[
chosenCategoryIndex
].items;
console.log("#detailedItemsToBeBought event bus");
console.log(this.detailedItemsToBeBought);
});
return this.detailedItemsToBeBought;
}
When I try to display the data I do not see anything but when hardcode this.shopItems[0].items I get the data I need - e.g. for wine category the array with wines;
I know it is not an easy issue but is anyone able and willing to take the challenge to explain me whot might had gone wrong here. Why I get the data from this.shopItems[0].items but when I pass index to this.detailedItemsToBeBought = this.shopItems[chosenCategoryIndex].items; - it works fine in the method chosenCategoryItems but after that the data this.detailedItemsToBeBought are undefined on mounted?
I attach screenshot from console.
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/30rk7.png
and the whole repository:
https://github.com/agnesliszka/alcohol_shop
It looks like your component needs to register for the listener BEFORE you emit the event.
You might want to simply store the chosen category in the store, instead of using an event.
If you really want to use an event (not recommended), you can delay the emit until after the component is ready, using nextTick or setTimer.
You will also want to register the listener in created or mounted.
this.$nextTick(()=>{
EventBus.$emit("chosenCategory", chosenCategoryIndex);
})
this.$router.push("/details");

Vue - how to add reactive properties to objects in an array of objects?

I have an array of objects coming from the backend. I need to add additional data onto each object, to send.
My data coming in looks like this:
let arr = [
{
id: 1,
city: 'Orlando',
},
{
id: 2,
city: 'Miami',
},
{
id: 3,
city: 'Portland',
}
]
When the data comes loaded in through Vue, I need to have those properties be reactive. Meaning vue can see when those values change and call the appropiate lifecycle methods. See https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats
let newArr = [
{
id: 1,
city: 'Orlando',
state: 'Fl',
country: 'USA',
},
{
id: 2,
city: 'Miami',
state: 'Fl',
country: 'USA',
},
{
id: 3,
city: 'Portland',
state: 'OR',
country: 'USA',
}
]
You can't just loop through and append properties to each object normally in vanillaJS, so how would you do this?
The vue docs suggests to use Object.assign when appending properties to make them reactive
// instead of `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
But, this is only if you have to append one object.
For a list of objects, this is how you would initialize the data
newArr = arr.map(item => {
let newItem = Object.assign({}, item, {
state: undefined,
country: undefined,
});
return newItem;
});
Now all your objects properties in the array of objects are reactive
Vue also intercepts calls to Array.push, so you may like this better:
arr.forEach(item => newArr.push(item))
Quite late but thought of providing the answer as it can be useful to someone else in the future:
If you would like to add an additional property to a certain object within an array of objects then you can use something like this:
var searchId = 1
const cityInfo = arr.find(ele => ele.id === searchId)
Vue.set(identifiersNode, 'state', "Karnataka")
Vue.set(identifiersNode, 'country', "India")

How to get filtered rows from GridX?

I'm using Dojo GridX with many modules, including filter:
grid = new Grid({
cacheClass : Cache,
structure: structure,
store: store,
modules : [ Sort, ColumnResizer, Pagination, PaginationBar, CellWidget, GridEdit,
Filter, FilterBar, QuickFilter, HiddenColumns, HScroller ],
autoHeight : true, autoWidth: false,
paginationBarSizes: [25, 50, 100],
paginationBarPosition: 'top,bottom',
}, gridNode);
grid.filterBar.applyFilter({type: 'all', conditions: [
{colId: 'type', condition: 'equal', type: 'Text', value: 'car'}
]})
I've wanted to access the items, that are matching the filter that was set. I've travelled through grid property in DOM explorer, I've found many store references in many modules, but all of them contained all items.
Is it possible to find out what items are visible in grid because they are matching filter, or at least those that are visible on current page? If so, how to do that?
My solution is:
try {
var filterData = [];
var ids = grid.model._exts.clientFilter._ids;
for ( var i = 0; i < ids.length; ++i) {
var id = ids[i];
var item = grid.model.store.get(id);
filterData.push(item);
}
var store = new MemoryStore({
data : filterData
});
} catch (error) {
console.log("Filter is not set.");
}
I was able to obtain filtered gridX data rows using gridX Exporter. Add this Exporter module to your grid. This module does exports the filtered data. Then, convert CSV to Json. There are many CSV to Json conversion javasripts out there.
this.navResult.grid.exporter.toCSV(args).then(this.showResult, this.onError, null)
Based on AirG answer I have designed the following solution. Take into account that there are two cases, with or without filter and that you must be aware of the order of rows if you have applied some sort. At least this works for me.
var store = new Store({
idProperty: "idPeople", data: [
{ idPeople: 1, name: 'John', score: 130, city: 'New York', birthday: '31/02/1980' },
{ idPeople: 2, name: 'Alice', score: 123, city: 'Wáshington', birthday: '07/12/1984' },
{ idPeople: 3, name: 'Lee', score: 149, city: 'Shanghai', birthday: '8/10/1986' },
...
]
});
gridx = new GridX({
id: 'mygridx',
cacheClass: Cache,
store: store,
...
modules: [
...
{
moduleClass: Dod,
defaultShow: false,
useAnimation: true,
showExpando: true,
detailProvider: gridXDetailProvider
},
...
],
...
}, 'gridNode');
function gridXDetailProvider (grid, rowId, detailNode, rendered) {
gridXGetDetailContent(grid, rowId, detailNode);
rendered.callback();
return rendered;
}
function gridXGetDetailContent(grid, rowId, detailNode) {
if (grid.model._exts.clientFilter._ids === undefined || grid.model._exts.clientFilter._ids === 0) {
// No filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._cache._priority.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._cache._priority.indexOf(rowId)).item().idPeople;
} else {
// With filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().idPeople;
}
}
Hope that helps,
Santiago Horcajo
function getFilteredData() {
var filteredIds = grid.model._exts.clientFilter._ids;
return grid.store.data.filter(function(item) {
return filteredIds.indexOf(item.id) > -1;
});
}