I was able to write subscription in meteor and it is working fine. now i need to set state inside the Meteor getMeteorData() method. here is my implemented working method
getMeteorData() {
Meteor.subscribe('Posts', Meteor.userId());
return {
Posts: Posts.find({}, {
sort: {
createdAt: -1
}
}).fetch(),
};
}
also i want it to be something like this. mean i want to set the state inside function. but when i code like below it return exception on the console.
getMeteorData() {
Meteor.subscribe('Posts', Meteor.userId());
let medias = [];
Posts.map(post => {
post.images.map(image => {
medias.push({image: image, post: post})
})
});
this.setState({medias: medias});
return {
Posts: Posts.find({}, {
sort: {
createdAt: -1
}
}).fetch(),
};
}
below is the snap of error error snap
Related
I am using Nuxt in SPA mode and have a page structure like this:
pages
...
- users/
- - index
- - new
- - update/
- - - _id
...
I have a page of users with a list of them and 'subpage' - new.
On my users/index page I am fetching my users in asyncData Hook like this:
async asyncData({ app: { apolloProvider }, store: { commit, dispatch } }) {
const {
data: { getAllUsers: { success, users, message } },
} = await apolloProvider.defaultClient.query({
query: getAllUsersGQL,
})
if(success) {
await commit('user/setUsers', users, { root: true })
} else {
dispatch('snackbar/notify', { message: message, type: 'error' }, { root: true })
}
},
It seems to work as it should. But when I go to my page users/new, fill up the form and send it, update the store and redirect to my users/index page, I encounter kinda interesting behaviour.
The problem here is that I don't have a newly updated state but some kinda cached one or previous state. I can so far make it working with location.replace. When the page reloads I have an accurate and updated state.
That's how I'm handling redirect on users/new page:
async save() {
if(this.$refs.create.validate()) {
this.loading = true
delete this.form.confirm
await this.createUserStore(this.form)
this.$router.push(
this.localeLocation({
name: 'users',
})
)
this.loading = false
this.$refs.create.reset()
}
},
and that's how I am refreshing my state in Vuex:
export const mutations = {
updateUsers: (state, payload) => {
state.users = [...state.users, payload].sort((a,b) => a.createdAt - b.createdAt)
},
}
That's how I'm passing data:
computed: {
...mapGetters({
storeUsers: 'user/getUsers',
storeGetMe: 'auth/getMe',
}),
},
<v-data-table
:headers="headers"
:items="storeUsers"
:search="search"
item-key="id"
class="elevation-1"
dense
>
</v-data-table>
I already tried to list items using v-for and it doesn't work either.
And when I console.log state I get all items. It works as it should.
What can be the problem that it's not updating the view?
If anyone has ever faced such kind of behaviour I'd appreciate any hints.
This is probably coming from the fact that Apollo does have it's own cache and that it reaches for the cache first as cache-first is the default value.
Give this one a try
await apolloProvider.defaultClient.query({
query: getAllUsersGQL,
fetchPolicy: 'network-only',
})
Additional answer
This is an example of a dynamic GQL query that I previously wrote
test.gql.js
import { gql } from 'graphql-tag'
import { constantCase, pascalCase } from 'change-case'
export const queryCompanyBenefitInfo = ({
benefitType,
needCifEligibility = false,
needActiveOnWeekend = false,
needCompanyContribution = false,
needAutoRenewed = false,
needUnitValue = false,
}) => {
return gql`
query {
CompanyBenefit {
oneOfType(benefitType: ${constantCase(benefitType)}) {
... on Company${pascalCase(benefitType)}Benefit {
${needCifEligibility ? 'cifEligibility' : ''}
${needActiveOnWeekend ? 'activeOnWeekend' : ''}
${needCompanyContribution ? 'companyContribution' : ''}
${needAutoRenewed ? 'autoRenewed' : ''}
${
needUnitValue
? `unitValue {
value
}`
: ''
}
}
}
}
}
`
}
And call it this way
import { testQuery } from '~/apollo/queries/test.gql.js'
...
await this.app.apolloProvider.defaultClient.query({
query: testQuery({ benefitType: 'care', needCifEligibility: true }),
fetchPolicy: 'network-only',
errorPolicy: 'all',
})
im trying to push to an array inside a subscrive method of rxjs using => but the variable that is an array outside changes into an object inside so i cannot use .push
#Component({
selector: 'devices_status-panel',
templateUrl: './devices.component.html',
styleUrls: ['./devices.component.scss']
})
export class DevicesComponent implements OnInit {
public rows = Array<any>();
public columns = [
{ date: 'Fecha' },
{ deviceId: 'Equipo' },
{ error: 'Estado' },
{ statusType: 'Evento'},
{ location: 'Localidad'},
{ ip: 'Ip' },
{ version: 'Version' },
{ unencriptedMessage: 'Mensaje'}
];
constructor(private devicesData: DevicesData) {
console.log("0")
console.log(this.rows)
this.getDeviceState();
}
getDeviceState(){
this.devicesData.getStatePipe()
.subscribe(([deviceState, info]) => {
console.log("1")
console.log(this.rows)
Object.keys(deviceState).forEach((key1) => {
const thisState: DeviceState = deviceState[key1];
console.log("2")
console.log(this.rows)
Object.keys(thisState.status).forEach((key2) => {
console.log("3")
console.log(this.rows)
const status: Status = thisState.status[key2];
if (status){
const eventGroupArray: Array<Array<DeviceEvent>> = status.deviceStatus;
eventGroupArray.forEach((eventArray) => {
eventArray.forEach((event) => {
const state: StateArray = {
date: event.date,
deviceId: event.deviceId,
error: status.error,
ip: event.ip,
statusType: event.statusType,
unencriptedMessage: event.unencriptedMessage,
version: event.version,
location: null
};
if (info.info[thisState.id]){
state.location = info.info[thisState.id];
}else{
state.location = "Desconocida"
}
console.log(this.rows)
console.log(typeof this.rows)
this.rows.push(state);
});
});
}
});
});
});
console.log(this.rows)
}
}
As you can see i added logs inside subscribe and just before the function call, this is an array outside and an object inside
I tried to solve it myself but i cant find where is the problem, any help is appreciated
Thanks
You haven't shown us what the log statements reveal, but if they show something different, the only reason that will happen is that something is assigning to this.rows between the time you log it prior to subscribing and the time the subscription happens, like this example using setTimeout:
const foo = {
example() {
this.rows = [];
console.log(1, this.rows);
setTimeout(() => {
console.log(2, this.rows);
}, 100);
}
};
foo.example();
foo.rows = {};
this inside the arrow function will be the same as it was outside, because that's how arrow functions work. So if this.rows is changing, it's because something is changing it.
It might be a closure problem. Try to add
getDeviceState(){
const _that = this;
.
.
.code...
_that.rows.push(state);
}
I am doing a query and have already logged the result. Everything works as it should, however when I want to continue working with the result it always is "undefined" (see 2nd logging).
I am sure I am missing out on something obvious here but would really love to get your help :)
render() {
let saved;
this.props.apolloClient
.watchQuery<Query>({
query: gql`
query($id: ID!) {
element(id: $id) {
children {
... on TextNote {
name
description
type
}
}
}
}
`,
variables: { id: 0 }
})
.subscribe(({ data: { element: { children } } }) => {
console.log(children); // this is the wanted result
saved = children;
});
console.log("save");
console.log(saved); // this is undefined for some reason
If children gives you the correct result, can you not just assign your variable saved to your this.props.apolloClient function and return children inside the subscribe call?
Something like:
render() {
const saved = this.props.apolloClient
.watchQuery<Query>({
query: gql`
query($id: ID!) {
element(id: $id) {
children {
... on TextNote {
name
description
type
}
}
}
}
`,
variables: { id: 0 }
})
.subscribe(({ data: { element: { children } } }) => {
console.log(children); // this is the wanted result
return children; // <-- return the value here
});
console.log("save");
console.log(saved); // <-- should have children assigned to saved
When I click a profile (of an author) component, I can't figure out how it should render a scoped sub-component, listing the main entities of the app, so-called fabmoments (containers for 3D print information).
My current solution looks like this:
export default {
name: 'Multipe',
props: [
'author'
],
data () {
return {
// search: '',
localAuthor: '',
fabmoments: []
}
},
created () {
this.localAuthor = this.author
if (typeof localAuthor !== 'undefined') {
this.$http.get(`/users/${this.$route.params.id}/fabmoments`)
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
} else {
this.$http.get('/fabmoments')
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
}
},
methods: {
buildFabmomentList (data) {
this.fabmoments = data
}
},
components: {
// Box
}
}
This renders all in the profile, where it should render a list scoped to the current profile's author.
And it renders nothing in the home (without receiving the prop), where it should render all.
I am not much of star in JavaScript. What am I doing wrong?
UPDATE
This works as a solution, though not very elegant.
export default {
name: 'Multipe',
props: [
'author'
],
data () {
return {
fabmoments: []
}
},
created () {
if (this.author.id >= 0) {
this.$http.get(`/users/${this.$route.params.id}/fabmoments`)
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
} else {
this.$http.get('/fabmoments')
.then(request => this.buildFabmomentList(request.data))
.catch(() => { alert('Couldn\'t fetch faboments!') })
}
},
methods: {
buildFabmomentList (data) {
this.fabmoments = data
}
},
components: {
// Box
}
}
Not sure which part is wrong, but you may definitely debug your code to find out why fabmoments is empty array assuming there is no error occurred yet.
There are three parts to debug:
http response -- to check if data is properly returned
this -- to check if this pointer still points at the component
template -- to check if fabmoments are correctly bind to the element
At last, it would be better to separate your http request logics from your components.
Good luck!
I have been working on the feature of comment deleting and came across a question regarding a mutation for an action.
Here is my client:
delete_post_comment({post_id, comment_id} = {}) {
// DELETE /api/posts/:post_id/comments/:id
return this._delete_request({
path: document.apiBasicUrl + '/posts/' + post_id + '/comments/' + comment_id,
});
}
Here is my store:
import Client from '../client/client';
import ClientAlert from '../client/client_alert';
import S_Helper from '../helpers/store_helper';
const state = {
comment: {
id: 0,
body: '',
deleted: false,
},
comments: [],
};
const actions = {
deletePostComment({ params }) {
// DELETE /api/posts/:post_id/comments/:id
document.client
.delete_post_comment({ params })
.then(ca => {
S_Helper.cmt_data(ca, 'delete_comment', this);
})
.catch(error => {
ClientAlert.std_fail_with_err(error);
});
},
};
delete_comment(context, id) {
context.comment = comment.map(comment => {
if (!!comment.id && comment.id === id) {
comment.deleted = true;
comment.body = '';
}
});
},
};
export default {
state,
actions,
mutations,
getters,
};
I am not quite sure if I wrote my mutation correctly. So far, when I am calling the action via on-click inside the component, nothing is happening.
Guessing you are using vuex the flow should be:
according to this flow, on the component template
#click="buttonAction(someParams)"
vm instance, methods object:
buttonAction(someParams) {
this.$store.dispatch('triggerActionMethod', { 'something_else': someParams })
}
vuex actions - Use actions for the logic, ajax call ecc.
triggerActionMethod: ({commit}, params) => {
commit('SOME_TRANSATION_NAME', params)
}
vuex mutations - Use mutation to make the changes into your state
'SOME_TRANSATION_NAME' (state, data) { state.SOME_ARG = data }