This is a very strange issue and annoying because it's just one of those that's not supposed to not work!
I have this mixin which is simply supposed to delete the password from the response data just like in the documentation:
Model.afterRemote(options.from, function(ctx, modelInstance, next) {
if (ctx.result) {
if (Array.isArray(ctx.result)) {
ctx.result.forEach(function(result) {
delete result.password;
result.more = 'Add more!';
});
} else {
delete ctx.result.password;
}
}
console.log('Deleted password', ctx.result);
next();
});
The result still includes the password and the more property that I've added doesn't exist in the response data.
Interestingly if I set result.password = null; the console shows the password as null!?
So it won't delete it, it won't add a property but it will let me set it to null.
Some bug? Caching the results? Any help please, I'm pulling out my hair!
hi @EmileSpecs I am trying to reproduce your problem, can you send me your model's .json and .js file?
Hi @jannyHou , thanks!
Model:
{
"name": "EmailAccount",
"base": "PersistedModel",
"strict": false,
"idInjection": false,
"options": {
"validateUpsert": true
},
"mixins": {
"Timestamp": true,
"Removepassword": {
"from": "find"
}
},
"properties": {
"archiveConfig": {
"type": "object"
},
"importConfig": {
"type": "object"
},
"tags": {
"type": "object"
},
"user": {
"type": "string",
"required": true
},
"password": {
"type": "string"
},
"host": {
"type": "string",
"required": true
},
"archive": {
"type": "boolean",
"required": true,
"default": false
},
"import": {
"type": "boolean",
"required": true,
"default": false
},
"slug": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"emails": {
"type": "hasMany",
"model": "Postbox",
"foreignKey": ""
}
},
"acls": [],
"methods": []
}
This is the mixin (removepassword.js):
module.exports = function(Model, options) {
options.from = options.from || '**';
Model.afterRemote(options.from, function(ctx, modelInstance, next) {
if (ctx.result) {
if (Array.isArray(ctx.result)) {
ctx.result.forEach(function(result) {
delete result.password;
//result.password = null;
});
} else {
delete ctx.result.password;
}
}
console.log('Delete password', ctx.result);
next();
});
}
And for what it's worth the Model's js:
var fs = require('fs');
module.exports = function(EmailAccount) {
EmailAccount.observe('before save', function(ctx, next) {
var path = null;
var account = ctx.instance || ctx.data;
if (!account.archive && account.archiveConfig && Object.getOwnPropertyNames(account.archiveConfig).length === 0) delete account.archiveConfig;
if (!account.import && account.importConfig && Object.getOwnPropertyNames(account.importConfig).length === 0) delete account.importConfig;
if (account.archive) {
path = account.archiveConfig && account.archiveConfig.path ? account.archiveConfig.path : null;
if (!path) return next(new Error('The archive path has not been provided.'));
}
if (!ctx.isNewInstance && !account.password) delete account.password;
if (path) {
fs.access(path, next);
} else {
next();
}
});
};
The relation to Postbox I assume isn't relevant? Can probably just leave that out, since the issue arises when I do a simple find without any inclusions etc.
Hi @EmileSpecs, I created the emailaccount model as you provided and copied removepassword.js into server/mixins/. Since I have nothing in front-end, I did everything from the explorer. What I did is creating some sample emailaccounts and then clicking endpoint GET /emailaccount.
Right the mixin doesn't work, but I am not sure whether my process reproduced your problem in a right way, so I need to confirm with you first then I can move to the next step to fix it.
Thanks.
@EmileSpecs well I think I find the solution, hope it's not too late for you :) Please check this issue:
https://github.com/strongloop/loopback/issues/1162
I tried and it works. The solution is to use unsetAttribute instead of delete, so in your case, it should be result.unsetAttribute('password')
And for adding property, you can use result.newPropertyName = new String('myNewProperty').
For more detailed explanation, please check docs here: https://docs.strongloop.com/display/public/LB/Operation+hooks#Operationhooks-Operationhookcontextobject
@jannyHou thanks! I saw that in the documentation but didn't think the resulting array of objects would be instances of the model and thus have that function so I just ignored it.
Also because of the example in the documentation... I suggest that the documentation be updated, since it's obviously not correct.
I'm not sure when the unsetAttribute function wouldn't be be available but I'm now using:
if (typeof result.unsetAttribute === 'function') result.unsetAttribute('password');
else delete result.password;
...just to be sure that the job gets done either way.
Thanks for the help!
Most helpful comment
@EmileSpecs well I think I find the solution, hope it's not too late for you :) Please check this issue:
https://github.com/strongloop/loopback/issues/1162
I tried and it works. The solution is to use
unsetAttributeinstead ofdelete, so in your case, it should beresult.unsetAttribute('password')And for adding property, you can use
result.newPropertyName = new String('myNewProperty').For more detailed explanation, please check docs here: https://docs.strongloop.com/display/public/LB/Operation+hooks#Operationhooks-Operationhookcontextobject