Updating an array of Data in Vue JS - vue.js

i'm trying to make a little DataTable in VueJS 2.0, and i've hit a bit of a roadblock, i'm making a call to a backend route to get some JSON from records in the Database, so far so good.
I want those records to populate an Array of GridData that i will later iterate through and display on my table.
The problem here is that it's not working...
Vue.http.post('/getData', data).then((response) => {
this.gridData = response.body;
});
I have my data setup as follows
data: () => {
return {
searchQuery: "",
columns: ['ID', 'Name', 'Campaign', 'Method', 'Limit Per Connection', 'Limit Per Day', 'Active', 'Successes', 'Failures', 'Last Ran'],
lastId: 0,
rowsPerPage: 10,
gridData: []
}
}
And my function that gets the data is called on the mounted hook
mounted() {
this.fetchData(this.lastId, this.rowsPerPage);
},
Am i doing anything wrong here?

You are using POST HTTP Request, instead of GET.POST is for creating new records in API/DB.
I think this should work for you
data() {
return {
searchQuery: "",
columns: ['ID', 'Name', 'Campaign', 'Method', 'Limit Per Connection', 'Limit Per Day', 'Active', 'Successes', 'Failures', 'Last Ran'],
lastId: 0,
rowsPerPage: 10,
gridData: []
}
},
created() {
this.fetchData()
},
methods: {
fetchData() {
this.$http.get('/getData')
.then(result => {
this.gridData = result.data
// or this.gridData = result.json()
})
}
}

Related

How to store array of object in react nativr async storage

I'm trying to set an array of objects in React Native AsyncStorage.
However, just the 1st item will store in it.
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify({
data: totalSet,
name: props.index,
date: today.toISOString().substring(0, 10),
})
the first item (data) is an array
Update
In my workout tracker app,
I try to create nested object. in the child component, I have following data:
weight: number
reps: number
result: also number (combination of weight and reps)
setIndex :number, which indicate the index of each sets
I have sent above data to parent component like this:
Child component
onPress={() =>
childToParent({
setDetails: [
{
setIndex: setIndex,
result: result,
weight: weight,
reps: reps,
},
],
}) + buttonStatus()
in the parent, I have given data, and trying to add into exsiting array and also adding 2 more item, date and index of each workout
parent component
const [totalSet, settotalSet] = useState([{ today }, { index }]);
useEffect(() => {
if (data != 0) {
settotalSet((current) => [...current, data]);
}
}, [data]);
then I store it into asyncstorage
const storeData = async () => {
try {
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify(totalSet)
).then((res) => console.log(res));
} catch (e) {
// saving error
}
};
and get it into another component like this
getMyObject = async () => {
try {
await AsyncStorage.getItem('1512').then((res) => {
setData(JSON.parse(res));
});
} catch (e) {
// read error
}
};
Finally as a result, I have below array:
Array [
Object {
"today": "2022-09-04",
},
Object {
"index": "1512",
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 13.200000000000001,
"setIndex": 0,
"weight": "12",
},
],
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 26.400000000000002,
"setIndex": 1,
"weight": "24",
},
],
},
]
everything is fine, except I need a nested object and this is an array.
How to create such an nested object at the first place?

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.

Sequelize query with a where clause on an include of an include

I'm struggling to create a query with sequelize.
Some context
I have the following models:
A Manifestation can have [0..n] Event
An Event belongs to one Manifestation (an Event cannot exist without a Manifestation)
A Place can have [0..n] Event
An Event belongs to one Place (an Event cannot exist without a Place)
A Manifestation can have [1..n] Place
A Place can have [0..n] Manifestation
I model the relations as the following:
Manifestation.hasMany(Event, { onDelete: 'CASCADE', hooks: true })
Event.belongsTo(Manifestation)
Place.hasMany(Event, { onDelete: 'CASCADE', hooks: true })
Event.belongsTo(Place)
Manifestation.belongsToMany(Place, { through: 'manifestation_place' })
Place.belongsToMany(Manifestation, { through: 'manifestation_place' })
For me it seems rather correct, but don't hesitate if you have remarks.
The question
I'm trying to query the Place in order to get all Manifestation and Event happening in a given Place. But for the Event ones, I want to include them within their Manifestation even if the Manifestation doesn't happen in the given Place.
Below is the "JSON" structure I'm trying to achieve:
{
id: 1,
name: "Place Name",
address: "Place address",
latitude: 47.00000,
longitude: -1.540000,
manifestations: [
{
id: 10,
title: "Manifestation one",
placeId: 1,
events: []
},
{
id: 11,
title: "Manifestation two",
placeId: 3,
events: [
id: 5,
title: "3333",
manifestationId: 11,
placeId: 1
]
}
]
}
So I want to include the Manifestation with id: 11, because one of its Event occurs in the given Place (with id: 1)
Update (04/06/20): For now I rely on javascript to get the expected result
I figured out it would be nice if I posted my current solution before asking.
router.get('/test', async (req, res) => {
try {
const placesPromise = place.findAll()
const manifestationsPromise = manifestation.findAll({
include: [
{ model: event },
{
model: place,
attributes: ['id'],
},
],
})
const [places, untransformedManifestations] = await Promise.all([
placesPromise,
manifestationsPromise,
])
const manifestations = untransformedManifestations.map(m => {
const values = m.toJSON()
const places = values.places.map(p => p.id)
return { ...values, places }
})
const result = places
.map(p => {
const values = p.toJSON()
const relatedManifestations = manifestations
.filter(m => {
const eventsPlaceId = m.events.map(e => e.placeId)
return (
m.places.includes(values.id) ||
eventsPlaceId.includes(values.id)
)
})
.map(m => {
const filteredEvents = m.events.filter(
e => e.placeId === values.id
)
return { ...m, events: filteredEvents }
})
return { ...values, manifestations: relatedManifestations }
})
.filter(p => p.manifestations.length)
return res.status(200).json(result)
} catch (err) {
console.log(err)
return res.status(500).send()
}
})
But I'm pretty sure I could do that directly with sequelize. Any ideas or recommendations ?
Thanks
This is not optimum. But you can try it out:
const findPlace = (id) => {
return new Promise(resolve => {
db.Place.findOne({
where: {
id: id
}
}).then(place => {
db.Manefestation.findAll({
include: [{
model: db.Event,
where: {
placeId: id
}
}]
}).then(manifestations => {
const out = Object.assign({}, {
id: place.id,
name: place.name,
address: place.address,
latitude: place.latitude,
longitude: place.longitude,
manifestations: manifestations.reduce((res, manifestation) => {
if (manifestation.placeId === place.id || manifestation.Event.length > 0) {
res.push({
id: manifestation.id,
title: manifestation.id,
placeId: manifestation.placeId,
events: manifestation.Event
})
}
return res;
}, [])
})
})
resolve(out);
})
})
}
From this, you get all manifestations that assigned to place or have any event that assigns. All included events in the manefestations are assigned to the place.
Edit :
You will be able to use the following one too:
const findPlace = (id) => {
return new Promise(resolve => {
db.Place.findOne({
include: [{
model: db.Manefestation,
include: [{
model: db.Event,
where: {
placeId: id
}
}]
}],
where: {
id: id
}
}).then(place => {
db.Manefestation.findAll({
include: [{
model: db.Event,
where: {
placeId: id
}
}],
where: {
placeId: {
$not: id
}
}
}).then(manifestations => {
place.Manefestation = place.Manefestation.concat(manifestations.filter(m=>m.Event.length>0))
resolve(place);// or you can rename, reassign keys here
})
})
})
}
Here I take only direct manifestations in the first query. Then, manifestations that not included and concatenate.
I do not know if you figure it out by now. But the solution is provided below.
Search with Sequelize could get funny :). You have to include inside another include. If the query gets slow use separate:true.
Place.findAll({
include: [
{
model: Manifestation,
attributes: ['id'],
include: [{
model: Event ,
attributes: ['id']
}]
},
],
})
I tried to complete it in a single query but you will still need JavaScript to be able to get the type of output that you want.
(Note: 💡 You need manifestation which is not connected to places but should be included if a event is present of that place. The only SQL way to get that starts by doing a CROSS JOIN between all tables and then filtering out the results which will be a very hefty query)
I came up with this code(tried & executed) which doesn't need you to execute 2 findAll that fetches all data as what you are currently using. Instead it fetched only the data needed for final output in 1 query.
const places = await Place.findAll({
include: [{
model: Manifestation,
// attributes: ['id']
through: {
attributes: [], // this helps not get keys/data of join table
},
}, {
model: Event,
include: [{
model: Manifestation,
// attributes: ['id']
}],
}
],
});
console.log('original output places:', JSON.stringify(places, null, 2));
const result = places.map(p => {
// destructuring to separate out place, manifestation, event object keys
const {
manifestations,
events,
...placeData
} = p.toJSON();
// building modified manifestation with events array
const _manifestations = manifestations.map(m => {
return ({ ...m, events: [] })
});
// going through places->events to push them to respective manifestation events array
// + add manifestation which is not directly associated to place but event is of that manifestation
events.map(e => {
const {
manifestation: e_manifestation, // renaming variable
...eventData
} = e;
const mIndex = _manifestations.findIndex(m1 => m1.id === e.manifestationId)
if (mIndex === -1) { // if manifestation not found add it with the events array
_manifestations.push({ ...e_manifestation, events: [eventData] });
} else { // if found push it into events array
_manifestations[mIndex].events.push(eventData);
}
});
// returning a place object with manifestations array that contains events array
return ({ ...placeData, manifestations: _manifestations });
})
// filter `.filter(p => p.manifestations.length)` as used in your question
console.log('modified places', JSON.stringify(result, null, 2));

FullCalendar 4.0 within a Vue application

I am using fullCalendar v4.0 with no jquery. I have initialized it like this
<div id="calendar"></div>
In data object I have this.
calendar: null,
config: {
plugins: [ interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin, momentPlugin],
axisFormat: 'HH',
defaultView: 'timeGridWeek',
allDaySlot: false,
slotDuration: '00:60:00',
columnFormat: 'dddd',
titleFormat: 'dddd, MMMM D, YYYY',
defaultDate: '1970-01-01',
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
eventLimit: true,
eventOverlap: false,
eventColor: '#458CC7',
firstDay: 1,
height: 'auto',
selectHelper: true,
selectable: true,
timezone: 'local',
header: {
left: '',
center: '',
right: '',
},
select: (event) => {
this.selectCalendar(event)
},
header: false,
events: null
}
}
while having a calendar in data variable, Now I can render() and destroy() it from anywhere.
But I am having an issue for handling Calendar events:
Such as
select: (event) => {
this.selectCalendar(event)
}
I have defined another method in methods: {} as selectCalendar() to call it in select but I am getting an error as
Uncaught TypeError: Cannot read property 'selectCalendar' of undefined
I want to do few operations on select, eventClick, eventDrop, eventResize, but I am unable to call a method within the config.
Also is there any way possible to define select or any method as
select: this.selectCalendar
So that it will just straight send an event to the defined method?
I have tried vue-fullcalendar but it doesn't work for my cause. Any help will be thankful.
Vue v.2.5.21
I am using vue full calendar, you can handle event of fullcalendar like code below
<full-calendar :event-sources="eventSources" #event-selected="myEventSelected"></full-calendar>
export default{
methods:{
caculateSomething(event){
//do st here
},
myEventSelected(event){
//do st here
this.caculateSomething(event)
console.log(event)
}
}
}
This is how I sorted this out.
in html <div id="calendar"></div>
in your data() => {}
calendar: null,
config: {
plugins: [ interactionPlugin, dayGridPlugin, timeGridPlugin, listPlugin, momentPlugin],
axisFormat: 'HH',
defaultView: 'timeGridWeek',
allDaySlot: false,
slotDuration: '00:60:00',
columnFormat: 'dddd',
columnHeaderFormat: { weekday: 'short' },
defaultDate: '1970-01-01',
dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
eventLimit: true,
eventOverlap: false,
eventColor: '#458CC7',
firstDay: 1,
height: 'auto',
selectHelper: true,
selectable: true,
timezone: 'UTC',
header: {
left: '',
center: '',
right: '',
},
header: false,
editable: true,
events: null
}
Don't define any select, resize or dropEvent in config for the first time, but then the part where you are going to render the calendar do something like this
if (this.calendar == null) {
console.log(this.schedule)
let calendarEl = document.getElementById('calendar');
let calendarConfig = this.config
let select = (event) => {
this.selectCalendar(event)
}
let eventClick = (event) => {
this.clickCalendar(event)
}
let eventDrop = (event) => {
this.dropCalendar(event)
}
let eventResize = (event) => {
this.resizeCalendar(event)
}
calendarConfig.select = select;
calendarConfig.eventClick = eventClick;
calendarConfig.eventDrop = eventDrop;
calendarConfig.eventResize = eventResize;
this.calendar = new Calendar(calendarEl, calendarConfig);
this.calendar.render();
this.renderEvents()
}
Now you can handle those events of FullCalendar in your own methods.
Also having the calendar in this.calendar gives you the power to destroy it from anywhere, in the methods: {}
In FullCalendar 4.0 things have been changes but quite simpler.
these are the methods attached to FullCalendar Events
selectCalendar(event) {
this.calendar.addEvent(event)
},
clickCalendar(event) {
if (window.confirm("Are you sure you want to delete this event?")) {
let findingID = null
if (event.event.id === "") {
findingID = event.el
} else {
findingID = event.event.id
}
let removeEvent = this.calendar.getEventById( findingID )
removeEvent.remove()
}
},
dropCalendar(event) {
},
resizeCalendar(event) {
},
destroyCalendar() {
if (this.calendar != null) {
this.calendar.destroy();
this.calendar = null
}
}
when an event is added by you. You can find it through el in an event, but the custom events should have a unique ID. through which you will find and delete it.

Vue.js - Element UI - HTML message in MessageBox

I'm using vue-js 2.3 and element-ui. This question is more specific to the MessageBox component for which you can find the documentation here
Problem
I'd like to be able to enter html message in the MessageBox
More specifically I would like to display the data contained in dataForMessage by using a v-for loop.
Apparently, we can insert vnode in the message but I have no idea where to find some information about the syntax.
https://jsfiddle.net/7ugahcfz/
var Main = {
data:function () {
return {
dataForMessage: [
{
name:'Paul',
gender:'Male',
},
{
name:'Anna',
gender:'Female',
},
],
}
},
methods: {
open() {
const h = this.$createElement;
this.$msgbox({
title: 'Message',
message: h('p', null, [
h('span', null, 'Message can be '),
h('i', { style: 'color: teal' }, 'VNode '),
h('span', null, 'but I would like to see the data from '),
h('i', { style: 'color: teal' }, 'dataForMessage'),
])
}).then(action => {
});
},
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
I think this is what you want.
methods: {
open() {
const h = this.$createElement;
let people = this.dataForMessage.map(p => h('li', `${p.name} ${p.gender}`))
const message = h('div', null, [
h('h1', "Model wished"),
h('div', "The data contained in dataForMessage are:"),
h('ul', people)
])
this.$msgbox({
title: 'Message',
message
}).then(action => {
});
},
}
Example.
You can also use html directly and convert to vnodes by using domProps:
const html = '<div><h1>Model wished</h1><div>The data contained in dataForMessage are:</div><ul><li>Paul Male</li><li>Anna Female</li></ul></div>'
const message = h("div", {domProps:{innerHTML: html}})
(The above is simplified without the loop. Just to get the idea)
Fiddle