javascript promise inside object - javascript

I can get to work a promise inside the object "addable:". after saving the new client the id added to the slimselect need to wait for the new _id.
Thanks
Pay to*
var Datastore = require('nedb');
var dclipro = new Datastore({filename: '/data/clipro.db', autoload: true});
var selectclipro = new SlimSelect({
select: '#bcofid_clipro',
valuesUseText: false,
addable: function (value) {
var newid = "";
var agrabar = {
name: value,
last_idcuenta: "null",
email: "notdefined#gmail.com",
memo: "not available",
auditlog: moment().format('MMMM Do YYYY, h:mm:ss a')
}
dclipro.update({name: value}, agrabar, options, function (err, numReplaced, upsert) {
if (err) {
console.error(err);
}
newid = upsert._id;
})
iziToast.show({
title: 'Bank',
message: 'New Payee has been saved successfully',
position: 'topRight'
});
return { text: value, value: newid }
},
onChange: (info) => {
console.log('elegido : value ' +info.value);
console.log('elegido : text ' +info.text);
}
})

SlimSelect, wow is this thing dated. From the documentation, it looks like your return object is optional, and that you should be able to do something like selectclipro.setData(myNewValue) inside your promise callback, as long as addable can actually see selectclipro. (Make sure you read the rest of my comments above)

Related

Netlify CMS custom widget not working with Map?

I've been trying to create a custom widget for Netlify CMS to allow for key-value pairs to be inserted. However there are a few things going wrong, I'm thinking they might be related so I'm making a single question about them.
This is my first custom widget, and I’m mostly basing this on the official tutorial: https://www.netlifycms.org/docs/custom-widgets/
I’m using a Map as the value, but when I add a new element to the map, and then call the onChange(value) callback, nothing seems to happen. However, if I change it to onChange(new Map(value)) it does update. It seems that the onChange callback requires a new object?
Secondly, the value doesn’t seem to be actually saved. When I fill in other widgets and refresh the page, it then asks to restore the previous values. However it doesn’t restore the map, while restores the other values just fine.
And lastly, I get uncaught exception: Object like a second after I change anything to the map. My guess is that Netlify CMS is trying to save the map (debouncing it for a second so it doesn’t save every letter I type), but fails and throws that exception. That would explain the previous problem (the non-saving one).
My complete code for the custom widget currently is:
var IngredientsControl = createClass({
getDefaultProps: function () {
return {
value: new Map()
};
},
addElement: function (e) {
var value = this.props.value;
value.set("id", "Description");
//is.props.onChange(value);
this.props.onChange(new Map(value));
},
handleIdChange: function (oldId, newId) {
console.log(oldId, newId);
var value = this.props.value;
var description = value.get(oldId);
value.delete(oldId);
value.set(newId, description);
//this.props.onChange(value);
this.props.onChange(new Map(value));
},
handleDescriptionChange: function (id, description) {
console.log(id, description);
var value = this.props.value;
value.set(id.toLowerCase(), description);
//this.props.onChange(value);
this.props.onChange(new Map(value));
},
render: function () {
var value = this.props.value;
var handleIdChange = this.handleIdChange;
var handleDescriptionChange = this.handleDescriptionChange;
var items = [];
for (var [id, description] of value) {
var li = h('li', {},
h('input', { type: 'text', value: id, onChange: function (e) { handleIdChange(id, e.target.value); } }),
h('input', { type: 'text', value: description, onChange: function (e) { handleDescriptionChange(id, e.target.value); } })
);
items.push(li);
}
return h('div', { className: this.props.classNameWrapper },
h('input', {
type: 'button',
value: "Add element",
onClick: this.addElement
}),
h('ul', {}, items)
)
}
});
var IngredientsPreview = createClass({
render: function () {
var value = this.props.value;
var items = [];
for (var [id, description] of value) {
var li = h('li', {},
h('span', {}, id),
h('span', {}, ": "),
h('span', {}, description)
);
items.push(li);
}
return h('ul', {}, items);
}
});
CMS.registerWidget('ingredients', IngredientsControl, IngredientsPreview);
What am I doing wrong?
Thanks!
I solved this by using immutable-js's map: https://github.com/immutable-js/immutable-js

How to pass the user name in Scheduled script to PDF template using SS 2.0?

I have made a scheduled script which is sending PDF though email.send()
I have get the filters as params from Suitelet. I want to get the name of the user (from runtime.getCurrentUser) and pass it to my PDF. I m just confused how to pass them and will that API be used in Suitelet or Sched script.
Can anyone help me with the code?
Here is my Scheduled script code:
/**
* #NApiVersion 2.x
* #NScriptType scheduledscript
*/
define(['N/ui/serverWidget', 'N/search', 'N/render', 'N/runtime', 'N/file', 'N/email'],
function (ui, search, render, runtime, file, email) {
function execute() {
try {
generateReport();
}
catch (e) {
log.error('generateReport ERROR', e);
}
}
function generateReport() {
var slfilters = runtime.getCurrentScript().getParameter({ name: 'custscript_searchfilter_report' });
log.debug('slfilters', slfilters);
if (!!slfilters) {
slfilters = JSON.parse(slfilters);
}
log.debug('slfilters2', slfilters);
var user = runtime.getCurrentUser();//Need this user to be passed to my xml template
var gender = slfilters.gender;//getting this from Suitelet
log.debug('gender', gender);
var item = slfilters.item;//getting this from Suitelet
log.debug('item', item);
var item_ = getItems(item, gender);
log.debug('getItems(item, gender)', item_);
//return item;
var xmlTemplateFile = file.load(3918);
//var template = script.getParameter({ name: 'custscript_template' });
var renderer = render.create();
renderer.templateContent = xmlTemplateFile.getContents();
var customSources = {
alias: 'searchdata',
format: render.DataSource.JSON,
data: JSON.stringify({
value: item_,
})
};
renderer.addCustomDataSource(customSources);
var xml = renderer.renderAsString();
var pdf = render.xmlToPdf({
"xmlString": xml
});
email.send({
author: 317,
recipients: 'aniswtf#gmail.com',
subject: 'Item Report',
body: 'Report Generated: ',
attachments: [pdf]
});
}
//
// ─── GET RESULTS ───────────────────────────────────────────────────
//
const getResults = function (set) {
var results = [];
var i = 0;
while (true) {
var result = set.getRange({
"start": i,
"end": i + 1000
});
if (!result) break;
results = results.concat(result);
if (result.length < 1000) break;
i += 1000;
}
return results;
};
//
// ─── GET ITEMS ───────────────────────────────────────────────────
//
function getItems(item, gender,user) {
try {
log.error('getItems Function started');
var itemSearch = search.load({
id: 'customsearch_mx_itemsearch'
});
var defaultFilters = itemSearch.filters;
itemSearch.filters.push(
search.createFilter({
name: "custitem5",
operator: 'anyof',
values: gender
}),
search.createFilter({
name: "internalid",
operator: 'anyof',
values: item
})
);
//defaultFilters = arrFilters;
//defaultFilters = defaultFilters.concat(arrFilters);
//log.error('Updated Filters', defaultFilters)
log.error('itemSearch', itemSearch);
//return defaultFilters;
var results = itemSearch.run().getRange({
start: 0,
end: 150
});
var result2 = results.map(function (x) {
// var results = getResults(itemSearch.run()).map(function (x) {
return {
'category': x.getText({
name: "custitem10",
join: "parent"
}),
'season': x.getValue({
name: "custitem11",
join: "parent"
}),
'riselabel': x.getText({
name: "custitem_itemriselabel",
join: "parent"
}),
'fit': x.getText({
name: "custitem9",
join: "parent"
}),
'name': x.getText({ //sku
name: "itemid",
join: "parent"
}),
'style': x.getText({
name: "custitem8",
join: "parent"
}),
'inseam': x.getText({
name: "custitem7",
join: "parent"
}),
'wash': x.getText({
name: "custitem_washname",
join: "parent"
}),
};
});
log.debug('Results', results.length);
log.debug('results', results);
log.debug('result2', result2);
// return results;//nabeeel's
return result2;//mine
} catch (e) {
log.error('error in getItems', e)
}
}
return {
execute: execute
};
});
There is no User in a Scheduled Script, so runtime.getCurrentUser() there will not return a value. You will need to retrieve the User via that method in the Suitelet (assuming it is not an anonymous external Suitelet).
From there you can add a Script Parameter to the Scheduled Script to hold the User, and then your Scheduled Script can read the Parameter and add the value as another Data Source on your template.

How to retrieve a specific object with Parse.Query

I am using Parse to create a WebApp and I am trying to get an instance of an object Productwith this code:
getProduct: function() {
var productClass = Parse.Object.extend("Product");
var query = new Parse.Query(productClass);
var result = query.get(productId, {
success: function(object) {
console.log(object.get("productName"));
},
error: function(object, error) {
...
}
});
return result;
}
I get a:
result.get is not a function
Printing the object only, I realized that I do not get a Product, I get this in the console (Safari):
[Log] Object (views.js, line 269)
_rejected: false
_rejectedCallbacks: Array[0]
_resolved: true
_resolvedCallbacks: Array[0]
_result: Arguments[1]
__proto__: Object
I tried many ways, but I am not able to retrieve a Product object and its attributes. What am I doing wrong?
EDIT
I am adding my Products View:
window.app.Products = Parse.View.extend({
template: _.template($('#products-template').html()),
el: $('body'),
content: $('#content'),
...
initialize: function() {
_.bindAll(this, 'render');
this.render();
},
render: function () {
$(this.content).html(this.template);
return this;
},
...
getUser: function() {
return Parse.User.current();
},
getUserProduct: function() {
var promise = new Parse.Promise();
var productClass = Parse.Object.extend("Product");
var query = new Parse.Query(productClass);
query.equalTo("objectId", this.getUser().get("product").id);
query.first().then(function(result) {
if(result){
// If result was defined, the object with this objectID was found
promise.resolve(result);
} else {
console.log("Product was not found");
promise.resolve(null);
}
}, function(error){
console.error("Error searching for Product. Error: " + error);
promise.error(error);
});
return promise;
},
setProduct: function() {
this.getUserProduct().then(function(result) {
if(result){
console.log(result.get("productName"));
var productName = result.get("productName");
} else {
console.log("Could not set Product");
}
}, function(error){
console.log("Error: " + error);
});
}
});
I was trying by having a list of parameters and updating them like:
info: {
user: '...',
product: '...'
}
Then passing it to the template:
$(this.content).html(this.template(this.info));
But I am not able to update product.
As I wrote this, I realised that you really aren't saving all that much code by pulling the product search into it's own method. My hope is that it will at least demonstrate to you how to create and call your own custom async methods. For example you may have a query which is much more complex than the current query, or it may perform multiple queries before finding the desired response, in which case it would make sense to pull it into it's own method.
Get Product Async Method
This method retrieves the Product with the given objectID
var getProduct = function(productId) {
var promise = new Parse.Promise();
var Product = Parse.Object.extend("Product");
var query = new Parse.Query(Product);
query.equalTo("objectId",productId);
query.first().then(function(result){
if(result){
// If result was defined, the object with this objectID was found
promise.resolve(result);
} else {
console.log("Product ID: " + productId + " was not found");
promise.resolve(null);
}
}, function(error){
console.error("Error searching for Product with id: " + productId + " Error: " + error);
promise.error(error);
});
return promise;
}
Calling Method
An example of a simple method which calls the above method.
var myMethod = function(){
var productID = "12345678";
getProduct(productID).then(function(result){
if(result){
console.log(result.get("productName"));
var productName = result.get("productName");
var productPrice = result.get("productPrice");
// Now that you have some relevant information about your product
// you could render it out to an Express template, or use this
// value in a calculation etc.
} else {
console.log("Product with objectId: " + productID + " was not found");
}
}, function(error){
console.log("Error: " + error);
});
}
Notes
As these methods are asynchronous, there is no real data being
returned in the 'return value' (the method returns a promise).
Instead we return the relevant data as a result of the promise (where
you see promise.resolve(XXX))
It doesn't make any sense to have a
mutable global variable in this Node.js style architecture.

Meteor JS: How do I assign the results of Meteor.call to a variable?

I am trying to insert a documents into collections which are all related to each other: Posts, Comments, and Categories. Each document in Comments and Categories must have a PostId field.
I have created a method named insertSamplePost, which should return the id of the post after inserting a document into Posts. I have assigned this method call to a variable like so:
var postId = Meteor.call('insertSamplePost', samplePost, function(error, id) {
if (error) {
console.log(error);
} else {
return id;
}
});
However, when I try to use postId later to insert related comments and categories, it appears to be undefined! Does anyone know what is happening?
Here is my full code:
if (Meteor.isClient) {
Template.post.events({
'click .new-sample-post' : function (e) {
var samplePost = {
title: "This is a title",
description: "This is a description"
};
// Insert image stub
var postId = Meteor.call('insertSamplePost', samplePost, function(error, id) {
if (error) {
console.log(error);
} else {
return id;
}
});
// This returned undefined. :-()
console.log(postId);
var sampleComment = {
body: "This is a comment",
postId: postId
};
var sampleCategory = {
tag: "Sample Category",
postId: postId
};
Comments.insert(sampleComment);
Categories.insert(sampleCategory);
}
});
}
// Collections
Posts = new Meteor.Collection('posts');
Comments = new Meteor.Collection('comments');
Categories = new Meteor.Collection('categories');
// Methods
Meteor.methods({
insertSamplePost: function(postAttributes) {
var post = _.extend(postAttributes, {
userId: "John Doe",
submitted: new Date().getTime()
});
return Posts.insert(post);
}
});
When you do:
var myVar = Meteor.call("methodName", methodArg, function(error, result) {
return result;
}
Your myVar variable will actually be whatever Meteor.call() returns, not what your callback function returns. Instead, what you can do is:
var postId;
Meteor.call('insertSamplePost', samplePost, function(error, id) {
if (error) {
console.log(error);
} else {
postId = id;
}
});
However, as Akshat mentions, by the time the callback function actually runs and asynchronously sets the postId, your insert calls on the other collections will already have run.
This code would actually be a little simpler if you avoid the server method altogether - you can modify the document in your collection's allow callback:
Template.post.events({
'click .new-sample-post' : function (e) {
var samplePost = {
title: "This is a title",
description: "This is a description"
};
var postId = Posts.insert(samplePost);
var sampleComment = {
body: "This is a comment",
postId: postId
};
var sampleCategory = {
tag: "Sample Category",
postId: postId
};
Comments.insert(sampleComment);
Categories.insert(sampleCategory);
}
});
Now you can add the userId and submitted fields in your Posts.allow() callback:
Posts.allow({
insert: function(userId, doc) {
doc.userId = userId;
doc.submitted = new Date().getTime();
return true;
}
});
If you wanted, you can still do the two secondary inserts within the callback for your first insert, in order to make the operation more atomic (in other words, to make sure the secondary inserts don't happen if the first insert fails).
You can use Session to store the results since Session is reactive and client side javascript is asynchronous so you cant assign the result to a variable directly using return.
So the reason you get undefined is because the result of Meteor.call is given in the callback. The callback will yield a result much later and by the time it returns a result the rest of your code will already have run. This is why its a good idea to use Session because you can use it in a template helper.
However for inserting a post its better to just insert the comments and category in the callback itself since you're not displaying the result in the html.
Meteor.call('insertSamplePost', samplePost, function(error, postId) {
if (error) {
console.log(error);
} else {
var sampleComment = {
body: "This is a comment",
postId: postId
};
var sampleCategory = {
tag: "Sample Category",
postId: postId
};
Comments.insert(sampleComment);
Categories.insert(sampleCategory);
}
});
This way if the result is an error the comment and category wont be inserted.

double upsert in Node.js and mongoose

var urlSchema = new Schema ( {
url : String,
visitor : [{name: String,date: Date}],
counter : Number
});
var url = mongoose.model('url',urlSchema);
var domain = blah blah;
var conditions = { url: domain };
var update = { $inc : {counter:1},
$push : { visitor: [{
name: data.username,
date: new Date()
}]
}
};
var options = {upsert: true};
url.update(conditions,update,options,function(err){
if(err){
console.log(err);
}else{
console.log('A domain successfully added to DB');
}
Currently I am using the schema and code above to make an access counter for each page.
It upserts url documents which is counting total access and holding access user info.
so far so good It's working properly.
now I want to add "counter : Number" in visitor array and when the event occurs, if the user is already in visitor array,I want to update that instead of pushing new one.
But I have no idea how to make the 'double upsert' command.
is there anyway to do that?
It may be a bit difficult even impossible perform a query that satisfy your condition. I have reproduced your scenario with following query
url.findOne({'url': 'search.php', 'visitor.name': "JohnDoe"},
function (err, visitor) {
if (visitor) {
url.update(
{
'url': 'search.php', 'visitor.name': "JohnDoe"
},
{
$inc: {'visitor.$.counter': 1, 'counter': 1}
},
function(err, result) {
if (err) {
console.log("Error occured")
} else {
console.log("Success");
}
});
} else {
var conditions = { url: 'search.php' };
var update = { $inc : {counter:1},
$push : { visitor: [{
name: data.username,
date: new Date(),
counter: 0
}]
}
};
var options = {upsert: true};
url.update(conditions,update,options,function(err){
if(err){
console.log(err);
}else{
console.log('A domain successfully added to DB');
}
});
}
}
);
Simple, insert if not exists with counter = 0, update if exists with incrementing counter by 1

Categories