I am using a observer on loopback model to store the model data in before save event. However i am getting error ,
(node:10760) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Callback was already called
Following is implementation of callback
async function eventSelObserver(ctx, next) {
console.log("eventSelObserver");
if ( ! (ctx.isNewInstance) && ctx.currentInstance) {
ctx.hookState.SelhistoryData = [ctx.currentInstance.toObject()];
}
console.log("before calling next");
return next();
}
Following is the way used to register the callback
obsModels.observe("before save", eventSelObserver);
Here the callback inside the eventSelObserver is called only once.
Any pointers for the error ?
I believe it has to do with the way you're handling asynchronicity, if you were to use async/await syntax then you don't need to pass next. Also, you need to await the value you're assigning.
async function eventSelObserver(ctx) {
console.log('eventSelObserver');
if (!ctx.isNewInstance && ctx.currentInstance) {
ctx.hookState.SelhistoryData = await ctx.currentInstance.toObject();
}
return;
}
obsModels.observe('before save', await eventSelObserver);
Ref: https://loopback.io/doc/en/lb3/Operation-hooks.html#using-asyncawait
Related
In my folder pre request I have written the following
sending = {
requestSimple : function(pm = pm){
pm.sendRequest(getBetEntryRequestBody, (err, res)=>{
pm.environment.set("c", true);
})
return pm.environment.get("c");
}
}
then in my actual request I am calling this method.
pm.test("Test 4",function()
{
let a = sending.requestSimple(pm);
pm.expect(a).to.equal(false);
})
When I execute this test, I get the following result
Test 4 | AssertionError: expected undefined to equal false
It seems like within the sendRequest() function it will not execute any logic. How do I write logic inside the sendRequest function to return a boolean value? Would appreciate some help. thanks
When someone makes a transfer from my account, an event gets trigger name
event Transfer(address indexed from, address indexed to, uint to)
Now I want to get notified when this event occurs on smart contract. I tried with difference things like filter, watch, subscription and etc. But nothing works as per need.
I also have an another query
What does filter, subscribe, and watch exactly do. I am always getting confuse between these terms. Can someone give a clear idea.
Note: I am using WEB3JS 1.0.0.26 version.
Here's a simple example for web3js 1.0.0.beta*:
function handler (event) {
console.log(event.returnValues);
}
function errorCallback (err) {
console.error(err);
}
let subscription = contractObj.events.TestEvent().subscription;
subscription.on('data', handler).on('error', errorCallback);
To unsubscribe:
subscription.unsubscribe(function (result) {
console.log(result)
});
Example of usage in class:
class Listener {
constructor(event, handler) {
this.subscription = event;
this.subscription.on('data', handler).on('error', this.errorCallback);
}
errorCallback(err) {
console.log(err);
}
}
class Test {
constructor(contractObj) {
this.contractObj = contractObj;
this.createListener();
}
createListener() {
let self = this;
this.listener = new Listener(this.contractObj.events.TestEvent(), function (event) {
self.returnValues = event.returnValues;
});
}
}
As the documentation says
resolve is
The Promise.resolve(value) method returns a Promise object that is
resolved with the given value.
reject is
The Promise.reject(reason) method returns a Promise object that is
rejected with the given reason.
I understand the uses of resolve but what will be the uses of reject and when to use it ?
Promise.reject is promise's way of throwing errors. Usually you would have a condition inside of your promise:
const user = {
name: 'John',
age: 17
}
const p = new Promise((resolve, reject) => {
if (user.age > 18) {
resolve('Welcome!');
} else {
reject(new Error('Too young!'));
}
});
You can then chain then and catch methods to handle the results of resolve and reject respectively.
p.then(message => {
console.log(message); // 'Welcome!', if promise resolves, won't work with age of 17
})
.catch(err => {
console.error(err); // 'Too young!', because promise was rejected
});
Here are few examples this statement can be used for:
Function defined to return a Promise, however you perform some sync checks and would like to return an error:
function request(data) {
if (!data) return Promise.reject("Empty data!");
// other logic
}
Unit tests, for example you would like to test that default data is used if service returns error (rejected promise):
const mockService = mock(Service);
// mock request method to return rejected promise
when(mockService.performRequest()).thenReturn(Promise.reject("Failed!"));
// inject mock instance and check that default data used if service failed
const sut = new ClassUnderTest(mockService);
expect(sut.getData()).to.eq("Default data");
If I have a remote method like this:
Command.remoteMethod('invoke', {
http: {verb: 'post', status: 200, source: 'body'},
returns: {arg: "text", type: "string"}
});
Sometimes we need to respond with the text argument and sometimes with a completely empty body. In the remote method code, I have something like this:
Command.invoke = callback => {
// ...
if (error) {
callback(null, 'There was an error');
} else {
callback(null);
}
}
The problem is, in the else branch, the body is never empty. I've also tried: callback(null, null) and callback(null, '').
Is there a way to achieve this? Or do I need to implement a remote hook to manually modify the response to get what I'm after?
Best way is to use the after remote function
if no content then you can add
ctx.res.statusCode = 204
ctx.res.end(null);
When you define a returns block in model.js, it means your remote method has a response body.
For your situation you can remove result in remote hooks.
Command.afterRemote("invoke", function(ctx, instance, next){
//check if you want return text or nothing
//if nothing so set result to null, otherwise just call next()
ctx.result = null;
next();
});
I am talking about loopback push component. I am trying to intercept the "create" method of "Installation" model. My code looks like this -
server/boot/installationex.js
module.exports = function (app) {
var Installation = app.models.Installation;
var create = Installation.create;
Installation.create = function (data, cb) {
//reinitializing old implementation
this.create = create;
console.log("Received data: "+JSON.stringify(data));
if (!data || !data.imei) {
console.log("No data or imei was provided, creating new");
this.create(data, cb);
return;
}
//saving 'this' reference
var that = this;
//search by imei filter
var filter = {where: {imei: data.imei}};
this.findOne(filter, function (err, result) {
if (err) {
console.log("Error occurred while looking for installation by IMEI");
cb(err);
return;
}
if (!result) {
console.log("No installation found by IMEI, will create a new installation");
that.create(data, cb);
return;
}
console.log("Found existing installation with id: " + JSON.stringify(result));
result.deviceToken = result.gpsLocation = result.osVersion = result.vendor = result.phoneNumbers = null;
if (data.deviceToken) {
result.deviceToken = data.deviceToken;
}
if (data.gpsLocation) {
result.gpsLocation = data.gpsLocation;
}
if (data.osVersion) {
result.osVersion = data.osVersion;
}
if (data.vendor) {
//result.vendor=data.vendor;
result.vendor = 'jahid';
}
if (data.phoneNumbers) {
result.phoneNumbers = data.phoneNumbers;
}
that.upsert(result, cb);
});
}
}
Unfortunately this code is invoked only once, I mean the first time. After that this code is never invoked. I became sure by looking at the log. It only prints the log first time. After that it does not print any log.
Any idea why this glue code is only invoked once? My intention is to intercept all create method invocation for Installation model. And check if there is already an entry for supplied "IMEI", if so then reuse that. Otherwise create new.
Thanks in advance.
Best regards,
Jahid
What I would start here with is:
instead of implementing your own intercepting mechanism use Model Hooks
check out findOrCreate() method
boot scripts are only run once during application startup. if you want a function that triggers every time a function is called, use a remote hook or model hook. probably something along the lines of:
...
Installation.beforeRemote('create', ...
...
see http://docs.strongloop.com/display/LB/Adding+logic+to+models for more info