I think I might be missing something obvious here, but if I have an object with a couple of functions, such as:
myFunctions = {
getLastName: function() { return " Bloggs"; },
getName: function(prefix) { return prefix + this.getLastName(); }
};
... how can I ensure 'this' is referencing the object in getName() when I call it with promise syntax, i.e:
q.fapply(myFunctions.getName, ['Mr.'])
.then(function(fullName) {
...
});
Currently, 'this' is just global scope when called via q.fapply()
Use Q.post instead,
var myFunctions = {
getLastName: function() { return " Bloggs"; },
getName: function(prefix) { return prefix + this.getLastName(); }
};
Q.post(myFunctions, 'getName', ['Mr.'])
.then(function(fullName) {
alert(fullName);
});
Related
I am trying to return a random number from the random-number-csprng API and it sends the value to the console, but not outside of the module. How can I compare the value from the module inside another module?
I have tried to return the number parameter from the .then() function but it still does not get outside of the function.
const Promise = require("bluebird");
const randInt = require("random-number-csprng");
class project {
constructor(uname) {
this.uname = uname;
}
randomNumber(lowest, highest)
{
Promise.try(() => {
return randInt(lowest, highest);
}).then(number => {
console.log("Your random number:", number);
}).catch({code: "RandomGenerationError"}, err => {
console.log("Something went wrong!");
});
}
checkRandom()
{
console.log(`This is a test: ${this.randomNumber(1,100)}`);
if(this.randomNumber(1, 100) > 1)
{
console.log(`Works!`);
}
else
{
console.log(`Does not work!`);
}
}
}
Output
This is a test: undefined
Your random number: 65
Your random number: 71
I expected the output to be 65 on the undefined log, but seems like it does not get stored outside of the Promise.try()
I see you followed the example code on their documentation a bit too literally. You need to return the promise from the method, and consume it asynchronously by awaiting it:
const randInt = require('random-number-csprng');
class Project {
constructor(uname) {
this.uname = uname;
}
randomNumber(lowest, highest) {
return randInt(lowest, highest);
}
async checkRandom() {
const randomValue = await this.randomNumber(1,100);
console.log(`This is a test: ${randomValue}`);
if (randomValue > 1) {
console.log('Works!');
} else {
console.log('Does not work!');
}
}
}
in my Node.JS project (a backend for an Angular 5 project) I have created a service that deals with the AWS Authentication... I have called this awsAuthenticationService. All works well but I now need to test it. In my awsAuthenticationService.js I have the following method that has some minor logic and then calls a method provided by the "cognitoIdentityServiceProvider". Here is a snippet of my code (I really have reduced this)
constructor() {
this._cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider(this.cognitoConfig);
}
toggleUserAccess(userName, type) {
const params = {
Username: userName,
UserPoolId: this.cognitoConfig.userPoolId
};
if (type === null) {
return this._cognitoIdentityServiceProvider.adminEnableUser(params).promise();
}
return this._cognitoIdentityServiceProvider.adminDisableUser(params).promise();
}
As you can see from the toggleUserAccess we pass a few parameters, determine what they are then call the appropriate method. I wish to test this by having a unit test that will call the authenticationService.toggleUserAccess, pass some params and spy on the authenticationService._cognitoIdentityServiceProvider methods to see if they were called. I set it up so...
let authenticationService = require('./awsAuthenticationService');
describe('toggleUserAccess', () => {
beforeEach(() => {
authenticationService._cognitoIdentityServiceProvider = {
adminDisableUser(params) {
return {
promise() {
return Promise.resolve(params);
}
};
}
};
authenticationService._cognitoIdentityServiceProvider = {
adminEnableUser(params) {
return {
promise() {
return Promise.resolve(params);
}
};
}
};
});
it('should call adminEnableUser if the type is null', () => {
authenticationService.toggleUserAccess('TheUser', null);
const spyCognito = sinon.spy(authenticationService._cognitoIdentityServiceProvider, 'adminEnableUser');
expect(spyCognito.calledOnce).to.equal(true);
});
it('should call adminDisableUser if the type is null', () => {
authenticationService.toggleUserAccess('TheUser', '0001');
const spyCognito = sinon.spy(authenticationService._cognitoIdentityServiceProvider, 'adminDisableUser');
expect(spyCognito.calledOnce).to.equal(true);
});
});
My tests aren't passing and I think I have set up my sinon.spys incorrectly - can anyone see what I am doing wrong or give advice please
To stub class of AWS.CognitoIdentityServiceProvider, need to stub with its prototype keyword.
// add require statement for your AWS class
const spyCognito = sinon.spy(AWS.CognitoIdentityServiceProvider.prototype, 'adminDisableUser');
expect(spyCognito.calledOnce).to.equal(true);
Hope it helps
How can I call methods asynchronously in sequelize ORM? (because I have to use returned value inside other methods).
user.dao.js:
var User = require('./user.model');
class UserDao {
constructor() {}
insert(user) {
var pk;
User.sync({ force: false }).then(() => {
User.create(user).then(function(user) {
console.log('Entry successful from dao: ' +
JSON.stringify(user));
//return generated pk
pk = user.id;
console.log('ID: ' + pk);
});
});
return pk;
}
user.test.js:
class UserDaoTest {
constructor() {
this.userDao = new UserDao();
this.compare = new UtilsObject();
}
/*
all CRUD method calls
*/
testAll() {
this.testInsert();
this.testUpdate();
//this.testDelete();
//this.testRead();
//this.compare();
}
/*
insert method
*/
testInsert() {
// composite form
var user = {
name: 'nisha',
email: 'nisha#gmail.com',
phoneNo: 8978,
picUrl: 'nisha',
description: 'SI',
status: 'active',
waitingTime: 10,
rating: 7
};
/*
calling insert user with above data
*/
var pk = this.userDao.insert(user);
console.log('pk value: ' + pk);
//var obj1 = this.userDao.readById(pk);
console.log('obj1 value: ' + user);
//this.testReadById(obj1);
}
testReadById(obj1) {
var obj2 = this.userDao.readById(obj1);
this.compare.compare(obj1, obj2);
this.testDelete(obj1);
}
}
export default UserDaoTest;
Here in user.test.js, in testInsert() method want to get the value of pk which is returned from insert() method of user.dao.js, but right now I am getting pk value as undefined.
Use a promise chain.
Suppose you need to get an entry for a particular user & do some operations on it.
Model.User.findById(someId)
.then((user) => {
// Do something with user.
})
You shouldn't be calling methods synchronously, NodeJs is not designed this way. It works with callbacks or promises.
Your code won't work because it is async code.
Watch the famous Youtube video about the event loop
But in short, if you will run the following example, which is like your code but without your logic:
var User = require('./user.model');
class UserDao {
constructor() {}
insert(user) {
var pk;
console.log('1');
User.sync({ force: false }).then(() => {
pk = 123;
console.log('3');
});
console.log('2');
return pk;
}
The variable pk will be undefined and your console will look like this:
1
2
3
If you want it to work, you should "wait" for the async functions like this:
var User = require('./user.model');
class UserDao {
constructor() {}
// #return Promise
insert(user) {
return User.sync({ force: false }).then(() => {
return User.create(user)
}).then((user) => {
console.log('Entry successful from dao: ' + JSON.stringify(user));
return user.id
})
}
And when you use it:
class UserDaoTest {
constructor() {
this.userDao = new UserDao();
this.compare = new UtilsObject();
}
/*
all CRUD method calls
*/
testAll() {
// if testInsert and testUpdate can run simultaneously you can keep it like this.
// Otherwise, use Promise.then as well
this.testInsert();
this.testUpdate();
}
/*
insert method
*/
testInsert() {
var user = {
// ...
};
/*
calling insert user with above data
*/
this.userDao.insert(user).then((userId) => {
// YOUR COMPARE CODE
}).then(done); // Where done is a function to let you test framework that you async code is done
}
}
export default UserDaoTest;
Another way of doing that is using the new async and await. That way you will get a code which is more readable and maintainable.
You can read more here
I am interested, how to pass this to a class variable inside a constructor of a parent, so I could use parents methods and access other variables of the parent and call their methods?
Here is my parent class:
var async = require('async');
var Rater = require('./rater')
var Similars = require('./similars')
var Suggestions = require('./suggestions');
module.exports = class Engine {
constructor() {
this.likes = new Rater(this,'likes');
this.dislikes = new Rater(this,'dislikes');
this.similars = new Similars(this);
this.suggestions = new Suggestions(this);
}
And here is the example of usage and where is get the following error:
Cannot read property 'engine' of undefined
at --\\classes\rater.js:89:19
module.exports = class Rater {
constructor(engine,kind) {
this.type = kind;
this.engine = engine;
if(kind == 'likes') //database schemes
this.db = Likes_db;
else if(kind == 'dislikes')
this.db = Dislikes_db;
else if(kind == 'similars')
this.db = Similars_db;
else if(kind == 'suggestions')
this.db = Suggestions_db;
}
//..
//other methods
//..
remove(user,item,done) {
this.db.remove({user: user,item: item},(err) => {
if(err)
return done(err);
async.series([
function(done) {
this.engine.similars.update(user,done); //error-cant enter the method
},
function(done) {
this.engine.suggestions.update(user,done);
}
],function(done) {
});
});
}
}
It has nothing to do with the constructor.
The problem appears because you are using a regular function as the callback and the context switches (you get another this in there).
Use an arrow function instead to keep the same context.
async.series([
(done) => {
this.engine.similars.update(user,done); //error-cant enter the method
},
(done) => {
this.engine.suggestions.update(user,done);
}
],function(done) {
});
Simply doing this works fine:
class Rather {
constructor(engine: Engine) {
engine.method();
}
}
class Engine {
constructor() {
new Rather(this);
}
method() {
console.log('ENgine');
}
}
new Engine();
You can see a working example here.
Note: As an OOP design decision though this is not very clean, you are introducing a cyclic dependency. Try going injection or at least introduce an interface to separate the 2 classes.
Try to define a _this var and then give it to parameter:
module.exports = class Engine {
var _this = this, _constructor = (<any>this).constructor;
constructor() {
this.likes = new Rater(_this,'likes');
this.dislikes = new Rater(_this,'dislikes');
this.similars = new Similars(_this);
this.suggestions = new Suggestions(_this);
}
I want to override the existing magento2 JS Component in my theme for some more customization.
Magento_Checkout/js/view/minicart.js
Above JS component i want to override and i want to add some more operation on the remove button event.
You can try "map" of require js. I used this and working for me. following is the requirejs-config.js inside my theme.
var config = {
map: {
'*': {
'Magento_Checkout/js/view/minicart':'js/custom/minicart'
}
}
};
Modified minicart.js file is placed inside "web/js/custom" folder inside my theme.
Just Go to your theme Override Magento_Checkout there, then under web folder make path as same as core module then add your js file & do required changes. It will reflect on frontend.
You can also extend an existing Magento JS without overwriting the whole file in your module add the require-config.js
app/code/MyVendor/MyModule/view/frontend/requirejs-config.js
var config = {
config: {
mixins: {
'Magento_Checkout/js/view/minicart': {
'MyVendor_MyModule/js/minicart': true
}
}
}
};
Then add the minicart.js
app/code/MyVendor/MyModule/view/frontend/web/js/minicart.js
define([], function () {
'use strict';
return function (Component) {
return Component.extend({
/**
* #override
*/
initialize: function () {
var self = this;
return this._super();
},
MyCustomFunction: function () {
return "my function";
}
});
}
});
define(['jquery'],function ($) {
'use strict';
var mixin = {
/**
*
* #param {Column} elem
*/
initSidebar: function () {
var sidebarInitialized = false, miniCart;
miniCart = $('[data-block=\'minicart\']');
if (miniCart.data('mageSidebar')) {
miniCart.sidebar('update');
}
if (!$('[data-role=product-item]').length) {
return false;
}
miniCart.trigger('contentUpdated');
if (sidebarInitialized) {
return false;
}
sidebarInitialized = true;
miniCart.sidebar({
'targetElement': 'div.block.block-minicart',
'url': {
'checkout': window.checkout.checkoutUrl,
'update': window.checkout.updateItemQtyUrl,
'remove': window.checkout.removeItemUrl,
'loginUrl': window.checkout.customerLoginUrl,
'isRedirectRequired': window.checkout.isRedirectRequired
},
'button': {
'checkout': '#top-cart-btn-checkout',
'remove': '#mini-cart a.action.delete',
'increacseqty':'#mini-cart a.action.increase-qty',
'decreaseqty':'#mini-cart a.action.decrease-qty',
'close': '#btn-minicart-close'
},
'showcart': {
'parent': 'span.counter',
'qty': 'span.counter-number',
'label': 'span.counter-label'
},
'minicart': {
'list': '#mini-cart',
'content': '#minicart-content-wrapper',
'qty': 'div.items-total',
'subtotal': 'div.subtotal span.price',
'maxItemsVisible': window.checkout.minicartMaxItemsVisible
},
'item': {
'qty': ':input.cart-item-qty',
'button': ':button.update-cart-item'
},
'confirmMessage': $.mage.__('Are you sure you would like to remove this item from the shopping cart??')
});
return this._super();
}
};
return function (minicart) { // target == Result that Magento_Ui/.../columns returns.
return minicart.extend(mixin); // new result that all other modules receive
};
});