How to reset X-editable fields after save event - meteor

This is a follow-up question to this answer in https://stackoverflow.com/a/15121394/2247553 on which I cannot comment yet due to the reward system at StackOverflow.
My question is, after the collection update has been requested with Meteor, how do I reset the editable back to its original state in case the server rejects the update?
Template.editableTable.rendered = function() {
$('#myParentTable').editable({
selector: '.editable-click'
});
$('a.editable-click').unbind('save').on('save', function(e, params) {
MyCollection.update({_id: 'myid'}, {$set: {key: 'val'}}, function(error, docs) {
if (error) {
// how do I reset X-editable here?
}
});
});
};

According to the FAQ, if the server side validation fails, you should return a non 200 status.
I know this doesn't exactly answer your question. I'm trying to do the same thing, return a success:false status. It does act like an API in a way, so sending back a 200 suggests that everything worked ok, so it updates the value. The request is to update the value, 200 status is for success.
Hope that makes sense. Please comment if you would like clarification.
My code for the error param of the editable function is below...
error: function(response, newValue) {
var json = false;
try {
json = JSON.parse(response.responseText);
} catch (e) {
json = false;
}
//Bootstrap message is my own thing.
bootstrapMessage.init('#search_results');
if(response.status === 500) {
bootstrapMessage.show_message('There is a server error. Please contact our supoprt team.', 'danger');
} else {
if(json){
bootstrapMessage.show_message(json.message, 'danger');
}else{
bootstrapMessage.show_message('Problem saving your change. Please refresh the page and try again or contact our support team', 'danger');
}
}
}

Related

Meteor wrapAsync

I'm trying to implement the following scenario:
1. Client calls a meteor-method.
2. Inside the meteor-method i make an HTTP-Post to a different server.
3. When the HTTP-Call is responded, the meteor method should return true and in the case an error occurs it should return false.
Here is what my meteor method looks like:
uploadUserImage: function(data_url,userid) {
asyncfnc =function(data,uid){
HTTP.post("http://localhost:2000/upload", {
data: {
"data_url": data,
"user_id": uid
}
},function(err,res){
console.log(res);
if (err){
console.log("error");
throw new Error(err.message);
}
else{
console.log("return true");
return true;
}
});
};
var waitForResult = Meteor.wrapAsync(asyncfnc);
var result = waitForResult(data_url,userid);
return result;
}
The HTTP-Call works and I also get into the Callback of the HTTP.post-function.
But on the clientside where I called the meteor-method i don't get into my callback-function. It looks like this:
Meteor.call("uploadUserImage",data_url,Session.get("newUserID"),function (err, res) {
if(err){
console.log(err);
} else {
console.log('response: ', res);
}
});
What am I doing wrong? Why is my meteor-method not returning anything?
Is everything correct with my Meteor.wrapAsync()?
Thanks for your help!
I found a solution, which does not require Meteor.wrapAsync().
var url = "http://localhost:2000/upload";
//synchronous GET
var result = Meteor.http.post(url,{
data: {
"title": "i want to upload a picture",
"data_url": data_url,
"user_id": userid
},timeout:30000});
if(result.statusCode==200) {
console.log(result);
console.log("response received.");
return result;
} else {
console.log("Response issue: ", result.statusCode);
var errorJson = JSON.parse(result.content);
throw new Meteor.Error(result.statusCode, errorJson.error);
}
This makes the HTTP-Post-Call synchronous, so there is no need to wrap async.
You are asking too much in this situation.
Meteor methods can be called synchronously, but it's not advisable if the method is doing a remote call like this.
My feeling is that you are hanging on to a procedural programming model where you want a synchronous result to 1) a call to your server, and 2) a request sent to another remote server. And you want to get a return value from your call. It doesn't work like that.
Meteor protects you to a large degree from dealing with asynchronicity, but sometimes you have to accept that a little more work is required to deal with it correctly.
So my recommendation is to use callbacks for notification.

meteorjs get data returned from server callback

In meteor im trying to insert a new document by making a Meteor.call from the client. Everything is working ok, except that I want to return the id of create document to the client, so that i can redirect to the proper url.
I have something similar to this (client):
Meteor.call('scenarioCreate', scenarioObj, function(err, response) {
if(err) {
console.warn(err);
return;
}
console.info(response);
});
On server:
Meteor.methods({
'scenarioCreate': function(scenarioObj) {
Scenarios.insert( scenarioObj, function(err, id) {
console.info("new id: "+id);
if (err) {
console.warn(err);
throw new Meteor.Error(404, 'Something went wrong');
}
return id;
});
}
});
From the server side i get the console log "new id: DDaq4aWsGf3fxG7RP", but I should get that same value on the client on the "response" value, but I always get undefined.
Can anybody explain to me why or what I am doing wrong.
Meteor.methods doesn't wait for your callback. Try this:
On server:
Meteor.methods({
'scenarioCreate': function(scenarioObj) {
var newId = Scenarios.insert(scenarioObj);
return newId;
}
});
To catch any error, use try/catch
Note: If you still want to use callback, checkout fibers/future.
Your first error is that you are returning id inside the callback for insert. That doesn't do anything. Then your second is not knowing that methods are synchronously executed. That would mean that you could only use the information available inside the callback using Meteor.wrapAsync. But that's besides the point. The insert function returns the new _id. Meaning you can do this:
Meteor.methods({
'scenarioCreate': function(scenarioObj) {
return Scenarios.insert( scenarioObj );
}
});

Get Meteor Method Return Value Inside Helper Function

I have the following in server/functions.js file:
Meteor.methods({
checkIfVoted: function (postId) {
if (postId) {
...
if (condition is met) {
return true;
} else {
return false;
}
}
}
});
And then the following in client/showPost.js:
Template.showPost.helpers({
alreadyVotedByUser: function () {
var answer = false;
if(this) {
Meteor.call("checkIfVoted", this._id, function(err, response) {
if (response) { console.log(response); }
answer = response;
});
}
console.log(answer);
return answer;
}
});
When I am doing the console.log for response I get the value to be true when the condition is met, but the answer variable does not take it, and still shows as having false as its value.
(I am aware that I put the Meteor methods in the server directory and not in a common directory to be shared between client and server to provide latency compensation)
Please if some one could help me with this, it will be highly appreciated.
On the client, Meteor.call is asynchronous - it returns undefined and its return value can only be accesses via a callback. Helpers, on the other hand, execute synchronously. See the answers to this question for how you can call methods from helpers. Here's a quick solution:
$ meteor add simple:reactive-method
Template.showPost.helpers({
alreadyVotedByUser: function () {
return ReactiveMethod.call('checkIfVoted', this._id);
}
});
The problem with this package is that it can encourage bad behavior, but it should be fine for method calls which don't change state.
Also see the section about helpers in this post.

Meteor template updates before result of Meteor.users.update

I'm trying to figure out how to prevent a template from updating until Meteor.users.update() finishes.
First I'm trying to make sense of the documentation and the use of an optional callback argument in order to sort out what is happening.
Here is what I have:
Meteor.users.update(Meteor.userId(),
{$set:{'profile.reviewList': []}},
[],
function(err, result){
if (err){
console.log('oh no!');
} else {
console.log('Result achieved: '+this.profile.reviewList);
}
});
Currently the console.log('Result achieved: '+this.profile.reviewList); always returns something like ...TypeError: Cannot read property 'reviewList' of undefined... the first time though which tells me its firing before the result comes back.
I'm sure I'm not implementing the callback properly, but I was attempting to model this answer: How do you ensure an update has finished in meteor before running a find?
I'd really just like to delay the re-rendering of the associated template until the property gets created.
Any help will be greatly appreciated.
You assume that scope (this) in callback function return user object, which is wrong.
If you want to get user object in that callback simply query it there:
var user = Meteor.users.find(Meteor.userId()).fetch()
Another thing, you passed empty array as 2nd argument which is not needed.
Meteor.users.update(
Meteor.userId(),
{
$set: {
'profile.reviewList': 'testData'
}
},
function(err, result) {
if (err) {
console.log('oh no!');
} else {
var user = Meteor.users.find(Meteor.userId()).fetch();
console.log('Result achieved: ' , user && user.profile && user.profile.reviewList);
}
}
);

Dealing with context of server responses in realtime web applications

Finding it hard to describe this issue - so please edit if you know more relevant terms.
I'm building a web application which essentially uses Redis (PubSub) + Node.js + Socket.IO as a distribution server.
I have two-way communication working with no issues - but I need to be able to make a request to the server from the client (asynchronously) and deal with the response while still processing other irrelevant responses that might come in before it.
This is what I have so far, but I'm not particularly happy with this approach:
Server
// Lots of other code
redis.psubscribe('*');
redis.on("pmessage", function(pattern, channel, message) {
// broadcast
});
io.on('connection', function(client) {
client.on('message', function(message) {
switch(message.method) {
// call relevant function
}
});
});
function object_exists(object_id) {
// do stuff to check object exists
client.send({method: 'object_exists', value: object_exists});
}
Client
var call = Array();
$(document).ready(function() {
socket.connect();
socket.on("message", function(obj){
console.log(obj);
call[obj.method](obj.value);
});
});
function object_exists(object_id) {
socket.send({method: 'object_exists', value: object_id});
// Set a function to be called when the next server message with the 'object_exists' method is received.
call['object_exists'] = function(value) {
if(value) {
// object does exist
}
}
}
tl;dr: I need to 'ask' the server something and then deal with the response using Socket.IO.
You don't specifically say why you are unhappy with your approach, but it looks to me like you are almost there. I am not really sure what you are trying to do with the call array, so I just took it out for clarity.
Basically, you just need to set up a switch statement to act as a message router on each side of the socket connection and fire off the appropriate methods based in incoming messages. Send enough state with the message itself so you can handle the work without any additional context. In your reworked code, I send the object_id to the server and back again to the client.
///SERVER
// Lots of other code
redis.psubscribe('*');
redis.on("pmessage", function(pattern, channel, message) {
// broadcast
});
io.on('connection', function(client) {
client.on('message', function(message) {
switch(message.method) {
case 'object_exists':
object_exists(message.objectId);
break;
}
});
});
//Takes an id an returns true if the object exists
function object_exists(object_id) {
// do stuff to check object exists
client.send({method: 'object_exists', objectId: object_id, value: object_exists});
}
///CLIENT
$(document).ready(function() {
//setup the message event handler for any messages coming back from the server
//This won't fire right away
socket.on("message", function(message){
switch(message.method) {
case 'object_exists':
object_exists(message.objectId, message.value);
break;
}
});
//When we connect, send the server the message asking if object_exists
socket.on("connect", function() {
socket.send({method: 'object_exists', objectId: object_id});
});
//Initiate the connection
socket.connect();
});
//Get's called with with objectId and a true if it exists, false if it does not
function object_exists(objectId, value) {
if(value) {
// object does exist, do something with objectId
}
else {
// object does not exist
}
}
If you want to see a bunch more code in the same stack doing work similar to what you are trying to accomplish, check out my nodechat.js project.

Resources