I have a Meteor back-end connected to a Chrome Extension through a DDP client.
On Meteor, I defined a method; on the Extension, I am calling it.
The call itself works, but the callback is not executed. I read through different posts discussing callback errors but couldn’t find a solution to this on any of them.
We have developed a Chrome app (a bit different than extension) and are able to debug the JS. I don’t have experience with extensions so can’t really speak.
The docs of meteor-ddp specifies that the call method does not accept a callback, instead it returns a jQuery deferred style promise:
call(methodName, [params, …]) - Does a Remote Procedure Call on any method exposed through Meteor.methods on the server. Returns -> Promise which resolves with any returned data.
And their example usage:
var createPlayer = ddp.call('createPlayer');
createPlayer.done(function(playerId) {
var joinGame = ddp.call('joinGame', [playerId]);
joinGame.done(function(gameId) {
console.log("We joined a game, here's the game id: ", gameId);
});
});
So your extension code would look like this (assuming you’ve already connected to the server):
(function($){
$('#testButton').click(function(){
var call = ddp.call('testMethod');
call.done(function(result) {
console.log('I am here');
console.log(result);
$("h1").text(result);
});
});
})(jQuery);
However, I am having trouble with it - my results are being returned as undefined. Here is my code:
meteor/imports/api/methods.js
Meteor.methods({
'runScrape': function(currentUrl){
console.log(currentUrl);
opengraph.getSiteInfo(currentUrl) //this is just an API that scrapes the current website
.then(function(result){
const textTitle = result.hybridGraph.title; //this extracts the title of the website
console.log(textTitle);
return textTitle;
})
.catch(function(error){
console.log('Error');
});
}
})
The result for this is that the method works (the console.log on Meteor prints the correct textTitle) and the call works correctly for the first action (printing the string ‘Test’), but doesn’t print the result variable.
I ran a few tests and discovered that result is undefined. I checked the type of result on the server side, and it is a string.
Why is this happening, despite using promises to cope with the asyncronous behaviour of the call? Any idea?
Your return textTitle is inside the context of that specific then in the Promise chain. It’s not returning from the method, but passing the result on to the next step of the chain.
Quite honestly, you’ll find it so much easier to work with Promises if you use async / await syntax:
Meteor.methods({
async runScrape(currentUrl) {
try {
console.log(currentUrl);
const result = await opengraph.getSiteInfo(currentUrl); //this is just an API that scrapes the current website
const textTitle = result.hybridGraph.title; //this extracts the title of the website
console.log(textTitle);
return textTitle;
} catch (error) {
console.log('Error');
}
}
});
You can refactor your client code similarly (just remember the nearest outer function needs to be declared async).
@robfallows It seems like opengraph does not have support for async/await… only callbacks and promises. Any thoughts on how I could refactor that code using promises? Thanks!
I changed the method to the async/await you wrote:
Meteor.methods({
async runScrape(currentUrl) {
try {
console.log(currentUrl);
const result = await opengraph.getSiteInfo(currentUrl); //this is just an API that scrapes the current website
const textTitle = result.hybridGraph.title; //this extracts the title of the website
console.log(textTitle);
return textTitle;
} catch (error) {
console.log('Error');
}
}
});
And refactored my client code to:
$("#testButton").click(function(){
async function runScrape(){
try {
const result = await server.call('runScrape',[currentTabUrl]);
$("#url").text(result);
} catch (error) {
$("#error").text("Error");
}
}
});
But nothing happens…
Before I refactored the client code (while the method was already async/await), the method itself worked, but with no output on the client side. It looks like it is still returning undefined.
That’s a real anti-pattern when using async / await. I’m not actually sure what you’d end up with as the result. The correct syntax is as @patrickcneuhaus used.
I’ve tested your code as far as I can and it works correctly for me.
I have not tested your opengraph call: I don’t know which package you used, and I don’t have a FB account (if that matters). However, I tested against a different call which returns an asynchronous Promise and everything worked as expected.