Famo.us - this.add and this_add - this

What is difference betwen using this.add and this._add in Famo.us framework. I am little confused with that _add part (naimin conventions that underscore in front of variable or method name 'mimics' private variable or method), but in code ther is no _add method.
Example:
function _createStripViews(){
this.stripViews = [];
this.stripModifiers = [];
var stripData = [
{title: 'APPAREL', iconUrl: './img/apparel_icon.png', stripColor: '#00aaac', textTitle: './img/apparel_text.png'},
{title: 'FOOTWEAR', iconUrl: './img/footwear_icon.png', stripColor: '#006a6d', textTitle: './img/footwear_text.png'},
{title: 'ALL MATERIALS', iconUrl: './img/allMaterials_icon.png', stripColor: '#be326a', textTitle: './img/allMaterials_text.png'},
{title: 'CHEMISTRY', iconUrl: './img/chemistry_icon.png', stripColor: '#32900e', textTitle: './img/chemistry_text.png'},
{title: 'ENERGY/GREENHOUSE GAS', iconUrl: './img/energyGreenhouse_icon.png', stripColor: '#cc4300', textTitle: './img/energyGreenhouse_text.png'},
{title: 'WATER/LAND', iconUrl: './img/waterLand_icon.png', stripColor: '#1a81b6', textTitle: './img/waterLand_text.png'},
{title: 'PHYSICAL WASTE', iconUrl: './img/physicalWaste_icon.png', stripColor: '#ccb200', textTitle: './img/physicalWaste_text.png'},
{title: 'RECYCLED', iconUrl: './img/recycled_icon.png', stripColor: '#7d0ea2', textTitle: './img/recycled_text.png'},
{title: 'ORGANIC', iconUrl: './img/organic_icon.png', stripColor: '#6c00c7', textTitle: './img/organic_text.png'}
];
for(var i = 0; i < stripData.length; i++){
var stripView = new StripView({
width: this.options.stripWidth,
height: this.options.stripHeight,
title: stripData[i].title,
color: stripData[i].stripColor,
iconUrl: stripData[i].iconUrl,
textTitle: stripData[i].textTitle,
index: i
});
this.stripViews.push(stripView);
var yOffset = this.options.topOffset + this.options.stripOffset * i;
var stripModifier = new Modifier({
transform: Transform.translate(0, yOffset, 0)
});
this.stripModifiers.push(stripModifier);
this._add(stripModifier).add(stripView);
stripView.pipe(this);
stripView.on('tap', this.animateStrips.bind(this));
};
};

Actually there is no difference. If you look at the file View.js in the Famo.us framework you will see the following..
/**
* Alias for add
* #method _add
*/
View.prototype._add = View.prototype.add;
They are the exact same thing. My guess is that if you want to add an 'add' function to a custom view, you may still reference Views 'add' function using _add.
Hope this helps!

Using the _-prefix is a common pattern in JavaScript when programming in an object oriented manner. It usually means that a instance method/variable is intended as private or protected as JavaScript doesn't really let you do that in a nice way.
Hence, even if you can use both and they currently do exactly the same, I'd advice to use the .add as it's probably the one that is supposed to be publicly exposed.

Related

I couldn't find a working Telegraf inline query project

I want to make a telegram bot about algebra. I need to send code to http://api.mathjs.org/v4/?expr=2*(7-3) after the expr part. I want to send numbers with inline query, but how can I do it?
The original example uses context object deconstruction, which doesn't seem to work and spits out error: TypeError: Cannot read property 'assert' of undefined
Here is the code without object deconstruction, which works for me (I've made it superfluously verbose for better understanding ):
bot.on('inline_query', async (ctx) => {
const offset = parseInt(ctx.inlineQuery.offset) || 0;
let items = [];
for(var i = 0; i < 100; i++) {
items.push({ title: 'Item '+i, desc: 'item '+i+' desc', id: '0000'+i, moreinfo: 'More info about item'+i+', mucho importante information'})
}
let results = items.slice(offset, offset+10).map((item) => ({
type: "article",
id: item.id,
title: item.title,
description: item.desc,
input_message_content: {
message_text: '*'+item.title+'*\n'+item.desc,
parse_mode: 'Markdown'
},
reply_markup: {
inline_keyboard: [
[{ text: 'More info', callback_data: 'moreinfo' }]
]},
hide_url: true,
url: 'http://www.domain.se/'+item.id,
}));
console.log('hello');
let ourReturn = ctx.answerInlineQuery(results, {is_personal: true, next_offset: offset+results.length, cache_time: 10});
return ourReturn;
});
Here is the article that helped me to solve this problem.
You can find multiple examples of Telegraf usage at https://github.com/telegraf/telegraf/tree/develop/docs/examples
Here is an example of a bot utilizing an inline query

Load defaultaddress of customer in netsuite via record search

I am working on creating a RESTlet to load paginated customer records. One of the thing i need is the customer's defaultaddress. This field is available when I load a single customer like this:
customer = record.load({
type: record.Type.CUSTOMER,
id: context.id, // e.g. 1234
isDynamic: false
});
However, when I try to load all customers with pagination like this:
define(['N/record', 'N/search'], function(record, search) {
var currencies = {};
function getClients(context) {
var mySearch = search.create({
type: search.Type.CUSTOMER,
columns: [
{ name: 'companyname' },
{ name: 'vatregnumber' },
{ name: 'lastmodifieddate' },
{ name: 'currency' },
{ name: 'email' },
{ name: 'phone' },
{ name: 'defaultaddress' }
]
});
var searchResult = mySearch.run().getRange({
start: context.start || 0,
end: context.end || 100
});
var results = [];
for (var i = 0; i < searchResult.length; i++) {
results.push({
tax_number: searchResult[i].getValue({ name: 'vatregnumber' }),
name: searchResult[i].getValue({ name: 'companyname' }),
// snipped...
});
}
return results;
}
function loadCurrencyName(id) {
return record.load({
type: record.Type.CURRENCY,
id: id,
isDynamic: false
}).name;
}
return {
get: getClients
}
});
and execute the rest api call to the above RESETlet script; I get the following error:
{
"type":"error.SuiteScriptError",
"name":"SSS_INVALID_SRCH_COL",
"message":"An nlobjSearchColumn contains an invalid column, or is not in proper syntax: defaultaddress.",
"stack":[ ... snipped ... ],
"cause":{ ... snipped ... },
"id":"",
"notifyOff":false
}
Any idea how to best to load the default address of the customer, whilst loading all customers using the paged search feature?
{defaultaddress} is calculated when the customer record is loaded - it's not a stored field and is not available for saved searches. As the field help says, it's simply the default billing address and changes automatically according to what address in the address subtab you have checked 'Default Billing" on.
To work around this and display what you're looking for, you can simply replace defaultaddress with billaddress.

Can I populate more fields after I have already l loaded a document on mongoose?

I want to populate aditional fields after I have already loaded one document.
I am loading my cart on a ecommerce I'm building, like this on all routes:
app.use(function(req, res, next) {
Cart.findOne({session: req.cookies['express:sess']})
.populate({ path: "products.product", select: "price name photos slug" })
.exec(function(err, cart){
if(err){
return err; //TODO: PAG 500
}
if(cart){
res.locals.cart = cart;
} else {
res.locals.cart = new Cart({ session: req.cookies['express:sess']});
}
next();
});
});
But at one page, I'd like to have more the fields description and addons from product loaded.
I tried to just load the products, but then I miss the associated information of quantity that I have on the cart
var CartSchema = new Schema({
products: [{
product: { type: Schema.ObjectId, ref : 'Product' },
quantity: { type: Number, default: 1}
}],
totalItems: { type: Number, default: 0},
message: { type: String },
});
I know I could break this up in more middlewares, according to my needs on fields on different pages, or reload the cart, and I could also just go through both arrays, the products I reload and the products I loaded on the cart and do some kind of merging, but I figured that mongoose might have some way to do this.
This can actually be done:
https://mongoosejs.com/docs/api.html#document_Document-populate
So in this specific case, I'd need to add this piece of code to the function that wants cart with more fields populated, and the middleware wouldn't need any changes
ES5 with callback:
var populate = [
{ path: "products.product", select: "price name photos slug" },
{ path: "card", select: "price name photo"}
];
var cart = res.locals.cart;
cart.populate(populate, function(err, populatedCart) {
res.locals.cart = populatedCart;
next();
});
With ES6:
const populate = [
{ path: "products.product", select: "price name photos slug" },
{ path: "card", select: "price name photo"}
];
res.locals.cart = await res.locals.cart.populate(populate).execPopulate();
You cannot "re-populate" a populated field.
How about a simple if to determine which fields you want to populated. For example:
app.use(function(req, res, next) {
var productSelect;
// This is just an example, you can get the condition from params, body, header..
if (req.body.isMoreField) {
productSelect = 'add more field in here';
}
else {
productSelect = 'less field here';
}
Cart
.findOne({
// ...
})
.populate({
// ...
select: productSelect,
// ...
})
.exec()
.then(function(cart) {
// ...
})
});

Initializing a ref array in Mongoose

Say I have the following schemas:
var promoGroupSchema = new Schema({
title: String,
offers: [{Schema.Types.ObjectId, ref: 'Offer']
});
and
var offerSchema = new Schema({
type: String
});
How do you initialize a promoGroup with new offers? The following won't work since save() is asynchronous. Now, I know I could put a function as a parameter of the save function, but that gets ugly with more offers.
var offer1 = new offerSchema({
type: "free bananas!"
});
var offer2 = new offerSchema({
type: "free apples!"
});
offer1.save();
offer2.save();
var newPromoGroup = new promoGroupSchema({
title: "Some title here",
offers: [offer1._id, offer2._id]
});
From what I read, Mongoose gives the object an _id as soon as you create them, can I rely on those?
You should access _id in the save callback. If you have a lot of offers to group, using a library like async will make your life easier.
var myOffers = [...]; // An array with offers you want to group together
// Array of functions you want async to execute
var saves = myOffers.map(function(offer) {
return function(callback) {
offer.save(callback);
}
}
// Run maximum 5 save operations in parallel
async.parallelLimit(saves, 5, function(err, res) {
if(err) {
console.log('One of the saves produced an error:', err);
}
else {
console.log('All saves succeeded');
var newPromoGroup = new promoGroupSchema({
title: "Some title here",
offers: _.pluck(myOffers, '_id') // pluck: see underscore library
});
}
});
You could also try to use Promises.

Collection and view not working in backbone script?

Hey guys I am currently following a tutorial and learning backbone, but for some reason I cannot get anything besides the Backbone model to work. Everything underneath it such as the collection or view does not seem to respond when entering things in the console. This is currently my code, I cannot find anything wrong with it and it validates in JSLint. One thing I noticed though is that the video is from before the 1.0 update of backbone. I am using jade for the layout and will include the code below as well.
UPDATED: I am working with this now.
(function(){
//app can be the name of the project/app
window.App = {
Models: {},
Collections: {},
Views: {},
Templates: {},
Routes: {}
};
window.template = function (id) {
return _.template($('#' + id).html());
};
//Can get rid of the Collection and views out of the names of each
//User Model
App.Models.User = Backbone.Model.extend({
defaults: {
firstName: 'J.R.',
lastName: 'Smith',
email: 'jsmith#knicks.com',
phone: '212-424-6234',
birthday: '03/05/1982',
city: 'New York'
},
location: function(){
return this.get('firstName') + ' ' + this.get('lastName') + 'is currently in ' + this.get('city') + '.';
}
});
// list of users
App.Collections.UsersCollection = Backbone.Collection.extend({
model: App.Models.User
});
//User View
App.Views.UserView = Backbone.View.extend({
tagName: 'li',
events: {
'click .edit':
},
template: template('userTemplate'),
initialize: function() {
this.render();
},
render: function() {
var template = this.template(this.model.toJSON());
this.$el.html(template);
return this;
//always return this on render methods
}
});
// view for users
App.Views.UsersView = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
},
render: function() {
this.collection.each(function(user) {
//user is the model associated to the new created user
var userView = new App.Views.UserView({model: user});
this.$el.append(userView.el);
}, this);
}
});
var userView = new App.Views.UserView({model: User});
$(document.body).append(userView.render().el);
})();
Jade layout page
doctype 5
html
head
title=title
link(rel='stylesheet', href='/css/style.css', type='text/css')
link(rel='stylesheet', href='/css/bootstrap-responsive.css')
link(href='/css/bootstrap.css', rel='stylesheet', type='text/css')
link(href='/css/font-awesome.min.css', rel='stylesheet', type='text/css')
script(src='/js/jquery.min.js', type='text/javascript')
script(src='/js/jquery.validate.min.js', type='text/javascript')
script(src='/js/script.js', type='text/javascript')
script(src='/js/underscore.min.js', type='text/javascript')
script(src='/js/backbone.min.js', type='text/javascript')
body
div#container
div#header
block content
include footer
Jade index page
extends layout
block content
h1= title
p Welcome to #{title}
script(src='/js/main.js', type='text/javascript')
script(id='userTemplate', type='text/template')
<%=firstName%>
button.edit Edit
<%=lastName%>
button.edit Edit
<%=email%>
button.edit Edit
<%=phone%>
button.edit Edit
<%=birthday%>
button.edit Edit
<%=city%>
button.edit Edit
A view's render method simply fills in the view's el, someone else has to add that el to the page that people will see. You're using tagName in your view:
tagName: 'li'
That just means that Backbone will create an <li> as your view's el, it doesn't mean that that <li> will be added to anything. The usual pattern is for render to return this:
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
and then whoever is calling render can add the el to the page with something like this:
var userView = new UserView({model: user});
$(whatever).append(userView.render().el);
I do my Backbone work client-side so I'm not sure how that would fit into your set up.
I think the problem lies here:
var userView = new App.Views.UserView({model: User});
$(document.body).append(userView.render().el);
Looking at your code I would expect an instance of App.Views.UsersView to be appended, and for it to be populated - in the code above you're pushing in { model: User } to an instance of a UserView instance rather than an instance of UsersCollection to an instance of UsersView.
Firstly your UsersView.render method should return this; in order to allow use of the .render().el pattern, UsersView handles creating and attaching instances of UserView for each model in the collection so you don't need to worry about this again.
render: function() {
this.collection.each(function(user) {
//user is the model associated to the new created user
var userView = new App.Views.UserView({model: user});
this.$el.append(userView.el);
}, this);
return this;
}
Then, the following looks right to me:
var users_data=[{
firstName: 'A',
lastName: 'Person',
email: 'a#knicks.com',
phone: '212-424-6234',
birthday: '03/05/1982',
city: 'New York'
},
firstName: 'Another',
lastName: 'Person',
email: 'another#knicks.com',
phone: '212-424-6234',
birthday: '03/05/1982',
city: 'New York'
},
firstName: 'A',
lastName: 'Person',
email: 'a#knicks.com',
phone: '212-424-6234',
birthday: '03/05/1982',
city: 'New York'
}];
var users = new App.Collections.UsersCollection( users_data );
var usersView = new App.Views.UsersView( users );
$( document.body ).append( usersView.render().el );

Resources