Passing callback function in NodeJS turns into Object - javascript

I am making an Alexa skill with AWS Lambda functions in NodeJS.
The app is throwing error when I call an Intent:
"errorMessage": "Exception: TypeError: object is not a function"
First, my app gets an event. If it's an Intent, it calls:
exports.handler = function (event, context) {
try {
...
else if (event.request.type === "IntentRequest") {
onIntent(
event.request,
event.session,
function intent_callback(sessionAttributes, speechletResponse) {
context.succeed(buildResponse(sessionAttributes, speechletResponse));
}
);
You can see the above passes a callback to onIntent(). It checks which Intent it is. Console.logging here shows the passed through callback as a function:
function onIntent(intentRequest, session, callback) {
if ("ItemIntent" === intentName) {
console.log(callback); // This is a function
getOrderResponse(intent, session, callback);
Yet, the type of the callback in getOrderResponse() somehow turns into an object? This would be why I'm getting that error, but I don't see how it's not a function type here. Why is it an object?
function getOrderResponse(callback) {
console.log('getOrderResponse', callback); // type = Object: { name: 'ItemIntent', slots: { Item: { name: 'Item' } } }
var card_title = config.data().CARD_TITLE;
var sessionAttributes = {},
speechOutput = 'So you want quick order',
shouldEndSession = false,
repromptText = 'Hello';
sessionAttributes = {
'speechOutput': repromptText,
'repromptText': repromptText,
'questions': 'some questions'
};
callback(sessionAttributes, buildSpeechletResponse(card_title, speechOutput, repromptText, shouldEndSession));
}

The callback will have to be the third parameter.
getOrderResponse(intent, session, callback); The first parameter you are sending is the the intent object.
function getOrderResponse(callback) {
should be
function getOrderResponse(intent, session, callback) {

Related

Is there any possible way to avoid repetitive code?

How to remove the repetitive code by providing method as parameter in javascript? Below is the code.
var toastrService = function (toastr) {
var _toastrService = this;
_toastrService.success =function(message,title) {
toastr.success(message,title);
}
_toastrService.info =function(message,title) {
toastr.info(message,title);
}
_toastrService.error =function(message,title) {
toastr.error(message,title);
}
_toastrService.warning =function(message,title) {
toastr.warning(message,title);
}
_toastrService.success =function(message,title) {
toastr.success(message,title);
}
}
Just iterate over an array of property strings:
['success', 'info', 'error', 'warning', 'success'].forEach((prop) => {
_toastrService[prop] = function(message, title) {
toastr[prop](message, title);
};
});
If you don't need to strip excess function arguments, you can trim it down to:
['success', 'info', 'error', 'warning', 'success'].forEach((prop) => {
_toastrService[prop] = toastr[prop].bind(toastr);
});
If the functions don't need a this of toastr, then you can leave out the .bind and just assign the plain function:
_toastrService[prop] = toastr[prop]
To make a global property injectable, simply declare it as an AngularJS value:
angular.module("app",[]).value("toastrService", toastr);
Then inject it where needed:
app.controller("ctrl", function (toastrService) {
toastrService.info("Title","Message");
});
For more information, see
AngularJS module type Reference - value

Is it possible to modify defined getter function?

Working on a performance reviewing tool on wechat mini apps platform (javascript + native hybrid based on wechat app), I am trying to inject codes into its prototypes, for example the wx.request function.
This is how you would use a wx.request function:
wx.request({
url: 'test.php',
data: {
x: '' ,
y: ''
},
header: {
'content-type': 'application/json'
},
success: function(res) {
console.log(res.data)
}
})
So in order to know how long the request has taken without manually writing adding all the anchors, I tried to inject code by:
var owxrequest = wx.request
wx.request = function() {
console.log('test', Date.now())
return owxrequest.apply(owxrequest, arguments)
}
This failed and I got an Cannot set property "prop" of #<Object> which has only a getter error.
So I realized the the object must have been defined similar to:
wx = {
request: get function(){
...
}
...
}
So I tried:
var owxrequest = wx.request
Object.defineProperty(wx, 'request', {
get: function() {
console.log('test', Date.now())
return owxrequest.apply(owxrequest, arguments)
}
})
This failed with an error (request: fail parameter error: parameter.url should be String instead of Undefined). Then I tried:
var owxrequest = wx.request
Object.defineProperty(wx, 'request', {
set: function() {
console.log('test', Date.now())
return owxrequest.apply(owxrequest, arguments)
}
})
This wouldn't throw an error but it also has no effect when calling wx.request()...
You can implement this by re-define the getter. The point is: the re-defined getter should return a function object, as wx.request is a function:
Object.defineProperty(wx, 'request', {
get: function() {
return function() {
//...
};
}
});
Why I get the error: request: fail parameter error: parameter.url should be String instead of Undefined?
You are trying to access the arguments of the getter itself (the arguments of function in get: function(){...}). This arguments is an empty object and it can be verified by console.log() statement. As it is empty, arguments.url is undefined, that's why wx complains about the parameter.
Here is an working example:
let wx = {
get request(){
return function() {
console.log(10);
return 88;
};
}
};
let oldF = wx.request;
Object.defineProperty(wx, 'request', {
get: function() {
return function() {
console.log(new Date());
return oldF.apply(wx, arguments);
};
}
});
console.log(wx.request());
The above code would print:
2017-08-28T06:14:15.583Z // timestamp
10
88
You could just shadowing the request function.
Simple example:
Shadowing the getter:
// original getter latest
let base = {
num: 1,
get latest() {
return this.num;
}
}
console.log(base.latest);
// shadowing getter latest
Object.defineProperty(base, 'latest', {
get: function() {
return this.num + 1;
}
});
console.log(base.latest);
Simple shadowing a object property
// your original object
let base = {
request(){
console.log('request original');
}
};
base.request()
base.request = () => {
console.log('request new implementation');
};
// now shadow the original request implementation
base.request()

How to store data from Pubnub history and make it available to all controllers?

I'm trying to get a history data from Pubnub.history(), store that data and update the views by using different controllers.
I've tried creating a service:
(function(){
'use strict';
angular.module('app')
.service('pubnubService', ['Pubnub',
pubnubService
]);
function pubnubService(Pubnub){
var history;
Pubnub.history({
channel : 'ParkFriend',
limit : 1,
callback : function(historyData) {
console.log("callback called");
history = historyData;
}
});
return {
getHistory : function() {
console.log("return from getHistory called");
return history;
}
};
}
})();
The problem is, getHistory() returns the data before Pubnub.history(). I need to make sure that history data is stored on history before returning it.
Since Pubnub.history is async, your getHistory function have to be an async function too.
Try the following:
function pubnubService(Pubnub) {
return {
getHistory: function(cb) { // cb is a callback function
Pubnub.history({
channel: 'ParkFriend',
limit: 1,
callback: function(historyData) {
console.log("callback called");
cb(historyData);
}
});
}
};
}
To use this service, you can't use it as a synchronous function (i.e., like var history = Pubnub.getHistory()), you need to pass a function as parameter to act like a callback.
Correct usage:
Pubnub.getHistory(function(history) { // here you have defined an anonym func as callback
console.log(history);
});

openSettings plugin cordova

I installed the plugin OpenSettings via node.js with this command in my project:
cordova plugin add https://github.com/erikhuisman/cordova-plugin-opensettings.git
But when I use method OpenSettings.setting() logcat return me an error:
OpenSettings.settings error at
file:///android_asset/www/plugins/nl.tapme.cordova.opensettings/www/OpenSettings.js:23
This is OpenSettings.js:
cordova.define("nl.tapme.cordova.opensettings.OpenSettings", function(require, exports, module) { module.exports = OpenSettings = {};
OpenSettings.settings = function(app, callback) {
cordova.exec(
// Success callback
callback,
// Failure callback
function(err) { console.log('OpenSettins.settings error'); },
// Native Class Name
"OpenSettings",
// Name of method in native class.
"settings",
// array of args to pass to method.
[]
);
};
OpenSettings.bluetooth = function (app, callback) {
cordova.exec(
// Success callback
callback,
// Failure callback
function(err) { console.log('OpenSettings.bluetooth error'); },
// Native Class Name
"OpenSettings",
// Name of method in native class.
"bluetooth",
// array of args to pass to method.
[]
);
};
OpenSettings.bluetoothStatus = function (app, callback) {
cordova.exec(
// Success callback
callback,
// Failure callback
function(err) { console.log('OpenSettins.bluetoothStatus error'); },
// Native Class Name
"OpenSettings",
// Name of method in native class.
"bluetoothStatus",
// array of args to pass to method.
[]
);
};
OpenSettings.bluetoothChange = function (callback) {
cordova.exec(
// Success callback
callback,
// Failure callback
function(err) { console.log('OpenSettins.bluetoothChange error'); },
// Native Class Name
"OpenSettings",
// Name of method in native class.
"bluetoothChange",
// array of args to pass to method.
[]
);
};
return OpenSettings;
});
Anyone can help me?
I would suggest you to test this plugin -> https://github.com/selahssea/Cordova-open-native-settings the first one you posted already did not work for me too.
Install it like this:
cordova plugin add https://github.com/selahssea/Cordova-open-native-settings.git
and use it like this:
cordova.plugins.settings.open(settingsSuccess,settingsFail);
Full snippet:
function settingsSuccess() {
console.log('settings opened');
}
function settingsFail() {
console.log('open settings failed');
}
function openSettingsNow() {
cordova.plugins.settings.open(settingsSuccess,settingsFail);
}
The plugin will open this overview:

Scope of a callback function

I want to implement a function which performs ajax requests (response is json) until there will be no "next" property in response. After that i need to perform some callback function. What is the best way for this? My code below doesn't work because of the wrong callback's scope, and i cannot imagine how to pass it correctly.
_requestPhotos = function(url, callback) {
getYFContent(url, function(data) {
// some actions
if (!!data.next) {
_requestPhotos(data.next, callback);
} else {
callback(smth);
}
});
};
There are no obvious errors from the script you've posted. For example, an equivalent test could look like this:
alertResult = function(text) {
console.log("Result is: " + text);
}
doRecursive = function(data, callback) {
if(!!data.next) {
doRecursive(data.next, callback);
} else {
callback(data.value);
}
}
var d = { value: 1, next: { value: 2, next: { value: 3 }}};
doRecursive(d, alertResult);
The log result is "Result is: 3", which is what you'd expect.
The error is elsewhere. How are you calling this the first time, what is the callback you're passing to it (and how is it defined) and what exactly does getYFContent do?

Categories