Apollo GraphQL: Child Component Re-Runs Parent Query? - apollostack

I've got a parent component with an Apollo query attached:
const withData = graphql(MY_QUERY, {
options({ userID }) {
return {
variables: { _id: userID}
};
},
props({ data: { loading, getOneUser } }) {
return { loading, getOneUser };
},
});
export default compose(
withData,
withApollo
)(NavigatorsList);
export { getOneUser_QUERY };
I've got a child component called userPhoto embedded in the render function:
return (
<div>
<userPhoto />
[.....]
</div>
)
Without the child component, the withData GraphQL function runs twice, once for loading == true, and one more time with the data returned.
With the child component included, the withData GraphQL function runs three times. The third time getOneUser is undefined and my component throws an error.
How can I correct this?
Thanks in advance to all for any info.

Fixed. There was a syntax error in the child component that wasn't throwing an error, but was causing the query to run twice + assorted other anomalies.

Related

trying to store image as base64 and using it

I have a block of code that I found online and it seems to be working and not working at the same time. I think its probably my lack of understanding but I cant seem to get it to work the way I want it.
selectPicture() {
let context = imagepicker.create({
mode: "single" // use "multiple" for multiple selection
});
var imageBase64
context
.authorize()
.then(function() {
return context.present();
})
.then(function(selection) {
selection.forEach(function(selected) {
imageSourceModule.fromAsset(selected).then((imageSource) => {
imageBase64 = imageSource.toBase64String("jpg",60);
console.log("Image saved successfully!")
console.log(imageBase64)
console.log("test test") //runs fine
this.image = "~/assets/images/account/camera.png" //cant seem to run
console.log("test test 2")
}).catch(function (e) {
// process error
console.log("got error 1")
});
})
}).catch(function (e) {
// process error
console.log("got error 2")
});
},
Within the imageSourceModule.fromAsset(selected).then((imageSource), I was trying to save the base64 info in another variable but cant seem to do anything within other than console log a string. When I run this.image = "~/assets/images/account/camera.png" (just a placeholder, even calling a method does not work too) for example it catches an error.
What could the problem be? thank you!
UPDATE
I changed console.log("got error 1") to log the actual update and what i got was:
undefined is not an object (evaluating 'this.image = "~/assets/images/account/camera.png"')*
I now think that theres a problem with my understanding calling variable outside. My variable 'image' is within the script at
data() {
return {
image : ""
}
}
first of all check what this variable is, because you do not use es6 arrow functions, so this is probably not the vue instance.
the second thing: when you change vue-variables asynchronously use the $set method, like: this.$set(this, 'image', '~/assets/images/account/camera.png')

Trying to Script a Search Result into a Netsuite Entity Field

Having two issues with this. One is that I keep getting an error when trying to upload my script. The other is that one version that I did get to upload, didn't load any value into the field (ie. field blank after script ran)
The error I keep getting on upload is "Fail to evaluate script: All SuiteScript API Modules are unavailable while executing your define callback." And although I've made drastic changes to the script, it still won't allow me to upload.
/**
*#NApiVersion 2.x
*#NScriptType ScheduledScript
*/
define(['N/search', "N/record"],
function(search, record) {
function loadAndRunSearch(scriptContext) {
var mySearch = search.load({
id: 'customsearch1088'
});
mySearch.run().each(function (result) {
var countt = result.getValue({
name: 'number'
});
var entity = result.getValue({
name: 'internalid'
});
var objRecord = record.load({
type: record.Type.CUSTOMER,
id: entity,
isDynamic: true,
});
var vfield = objRecord.getField({
fieldId: 'custentity_orders_12m'
});
objRecord.setValue({fieldId: 'custentity_orders_12m', value: countt});
objRecord.save();
});
}
return {
execute: loadAndRunSearch
};
});
That's the script stripped down to the bare bones (FYI still doesn't upload), and the script that uploaded was basically a more complicated version of the same script, except it didn't set the field value. Can anyone see where I've gone wrong?
You haven't returned the entry function.
/**
*#NApiVersion 2.x
*#NScriptType ScheduledScript
*/
define(['N/search', 'N/record'],
function(search, record) {
function loadAndRunSearch(scriptContext) {
var mySearch = search.load({
id: 'customsearch1088'
});
mySearch.run().each(function (result) {
var countt = result.getValue({
name: 'number'
});
var entity = result.getValue({
name: 'internalid'
});
record.submitField({
type: record.Type.CUSTOMER,
id: entity,
values: {
'custentity_orders_12m' :countt
}
});
});
}
return {
execute : loadAndRunSearch
}
});

Firebase database remove() "is not a function"

This code works:
firebase.database().ref($scope.language).orderByChild('word').equalTo($scope.word).once('value')
.then(function(snapshot) {
console.log(snapshot.val());
})
It logs the object and its key.
This code doesn't work:
firebase.database().ref($scope.language).orderByChild('word').equalTo($scope.word).remove()
.then(function(snapshot) {
console.log("Removed!");
})
The error message is:
TypeError: firebase.database(...).ref(...).orderByChild(...).equalTo(...).remove is not a function
The documentation makes remove() look simple. What am I missing?
You can only load data once you know its specific location in the JSON tree. To determine that location, you need to execute the query and loop through the matching results:
firebase.database().ref($scope.language).orderByChild('word').equalTo($scope.word).once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
child.ref.remove();
console.log("Removed!");
})
});
If you only want to log after all have been removed, you can use Promise.all():
firebase.database().ref($scope.language).orderByChild('word').equalTo($scope.word).once("value").then(function(snapshot) {
var promises = [];
snapshot.forEach(function(child) {
promises.push(child.ref.remove());
})
Promise.all(promises).then(function() {
console.log("All removed!");
})
});
This is Frank's first code block with another closure. Without the closure the record is removed from the database but then there's an error message:
Uncaught (in promise) TypeError: snapshot.forEach(...).then is not a function
Adding a closure fixes the error message.
firebase.database().ref($scope.language).orderByChild('word').equalTo($scope.word).once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
child.ref.remove();
}); // a closure is needed here
}).then(function() {
console.log("Removed!");
});

In a GraphQL/Relay mutation that creates a model, is there a way to get back the model ID?

We're using Relay and GraphQL in a new project.
We've got a Relay mutation that creates a new model in the DB:
export default class AddCampaignMutation extends Relay.Mutation {
getMutation() {
return Relay.QL`mutation { addCampaign }`;
}
getVariables() {
return {
type: this.props.campaignType
};
}
getFatQuery() {
return Relay.QL`
fragment on AddCampaignPayload {
campaignEdge
viewer
}
`;
}
getConfigs() {
return [{
type: 'RANGE_ADD',
parentName: 'viewer',
parentID: this.props.viewer.id,
connectionName: 'campaigns',
edgeName: 'campaignEdge',
rangeBehaviors: {
'': 'append',
},
}];
}
static fragments = {
viewer: () => Relay.QL`
fragment on User {
id
}
`,
};
}
However, since none of the components are currently querying for the range specified in RANGE_ADD (viewer { campaigns }), Relay intelligently excludes that query from the AddCampaignPayload.
This results in a console warning:
Warning: writeRelayUpdatePayload(): Expected response payload to include the newly created edge `campaignEdge` and its `node` field. Did you forget to update the `RANGE_ADD` mutation config?
I really want to get back the ID of the newly created model, so that I can navigate the client to it. For example, getting back the new campaignEdge, I want to send the client to /campaigns/${campaignEdge.node.id}.
Is there any way to tell Relay to fetch that edge? Have I configured this mutation correctly?
You can use REQUIRED_CHILDREN in this context. For more details, see https://github.com/facebook/relay/issues/237 and https://github.com/facebook/relay/issues/236.
REQUIRED_CHILDREN lets you specify an extra data dependency for exactly this pattern.

Sorting an array and saving to Mongo doesn't seem to trigger reactivity on my page

I have a template that I am loading from a route like so:
this.route('formEdit', {
path: '/admin/form/:_id',
data: function() { return Forms.findOne({_id: this.params._id}); },
onBeforeAction: function() { AccountUtils.authenticationRequired(this, ['ADMIN']); }
});
In which I have a template defined like:
<template name="formEdit">
<div id="formContainer">
...
{{#each header_fields}}
<div class="sortable">
{{> headerFieldViewRow }}
</div>
{{/each}}
</div>
</template>
And:
<template name="headerFieldViewRow">
{{#with header_field}}
...
{{/with}}
</template>
I then make the container around all the header fields sortable using jQuery UI Sortable:
Template.formEdit.rendered = function() {
$('.sortable').sortable({
axis: "y",
stop: function(event, ui) {
var form = Blaze.getData($('#formContainer')[0]);
var newFormHeaders = [];
$('#headerFieldsTable div.headerField').each(function(idx, headerFieldDiv) {
var header = Blaze.getData(headerFieldDiv);
header.sequence = idx;
Meteor.call('saveHeaderField', header);
newFormHeaders.push({header_field_id: header._id});
});
form.header_fields = newFormHeaders;
Meteor.call('saveForm', form);
}
});
}
Basically, when sorting stops, loop through all the headers, getting the data for each and updating the sequence number, then re-build the array in Forms and save them back. In the server code I have printouts for the two save calls, and the do properly print out the correct order of both the headers and the form.
The problem I am running into is that, after sorting, the visual display of the form and it's headers "snaps" back to the pre-sorted state, even though the data in the DB is correct. If I simply reload the form, either by hitting enter in the Address bar or by simply re-loading it from the menu, everything is displayed correctly. It's as if the reactive piece isn't working.
I have noted that I am getting an error when I update the client code in my server log that reads:
=> Client modified -- refreshing
I20141010-18:25:47.017(-4)? Failed to receive keepalive! Exiting.
=> Exited with code: 1
I don't think this is related as I was getting that error prior to adding this sorting code.
Update: Adding code for saveForm and saveHeader
saveForm:
// Saves the Form to the DB
saveForm: function(params) {
// Structure the data to send
var formEntry = {
title: params.title,
client_id: params.client_id,
header_fields: params.header_fields,
form_fields: params.form_fields,
created_by: Meteor.userId(),
created_on: new Date()
};
if (params._id == null) {
console.log("Saving new Form entry: %j", formEntry);
formEntry._id = Forms.insert(formEntry);
} else {
formEntry._id = params._id;
console.log("Updating Form entry: %j", formEntry);
Forms.update({_id: formEntry._id}, formEntry);
}
return formEntry;
}
saveHeader:
// Saves the HeaderField to the DB
saveHeaderField: function(params) {
// Structure the data to send
var headerFieldEntry = {
label: params.label,
field_type: params.field_type,
field_options: params.field_options,
form_id: params.form_id,
required: params.required,
allows_pictures: params.allows_pictures,
record_geo: params.record_geo
};
if (params._id == null) {
console.log("Saving new HeaderField entry: %j", headerFieldEntry);
headerFieldEntry._id = HeaderFields.insert(headerFieldEntry);
} else {
headerFieldEntry._id = params._id;
console.log("Updating HeaderField entry: %j", headerFieldEntry);
HeaderFields.update({_id: headerFieldEntry._id}, headerFieldEntry);
}
return headerFieldEntry;
}
I think the issue here is that Meteor.call will run on the server - you either need to use a callback or invalidate your template, if you want to return a value Meteor.call. From the docs:
On the client, if you do not pass a callback and you are not inside a stub, call will return undefined, and you will have no way to get the return value of the method. That is because the client doesn't have fibers, so there is not actually any way it can block on the remote execution of a method.
There is more info in this answer and this answer and the Meteor.call docs.
Hope that helps!

Resources