Using Backbone-relational with CoffeeScript - debugging

I'm trying to use a Backbone-relational and CoffeeScript in a project.The following is an example in CoffeeScript of the type of things I'm trying to model :
class NestedModel extends Backbone.RelationalModel
defaults:
Description: 'A nested model'
NestedModel.setup()
class MainModel extends Backbone.RelationalModel
defaults:
Description: 'A MainModel description'
StartDate: null
relations: [
type: Backbone.HasOne
key: 'nestedmodel'
relatedModel: 'NestedModel'
includeInJSON: '_id'
reverseRelation:
type: Backbone.HasOne
includeInJSON: '_id'
key: 'mainmodel'
]
MainModel.setup()
nm = new NestedModel()
mm = new MainModel(nestedmodel: nm)
console.log mm.get("nestedmodel").get("mainmodel").get("Description")
return
That CoffeeScript produces the following JavaScript:
var MainModel, NestedModel, mm, nm;
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor;
child.__super__ = parent.prototype;
return child;
};
NestedModel = (function() {
__extends(NestedModel, Backbone.RelationalModel);
function NestedModel() {
NestedModel.__super__.constructor.apply(this, arguments);
}
NestedModel.prototype.defaults = {
Description: 'A nested model'
};
return NestedModel;
})();
NestedModel.setup();
MainModel = (function() {
__extends(MainModel, Backbone.RelationalModel);
function MainModel() {
MainModel.__super__.constructor.apply(this, arguments);
}
MainModel.prototype.defaults = {
Description: 'A MainModel description',
StartDate: null
};
MainModel.prototype.relations = [
{
type: Backbone.HasOne,
key: 'nestedmodel',
relatedModel: 'NestedModel',
includeInJSON: '_id',
reverseRelation: {
type: Backbone.HasOne,
includeInJSON: '_id',
key: 'mainmodel'
}
}
];
return MainModel;
})();
MainModel.setup();
nm = new NestedModel();
mm = new MainModel({
nestedmodel: nm
});
console.log(mm.get("nestedmodel").get("mainmodel").get("Description"));
return;
Which produces the following warning and error
Warning:
Relation= child
; no model, key or relatedModel (function MainModel() {
MainModel.__super__.constructor.apply(this, arguments);
}, "nestedmodel", undefined)
Error:
Uncaught TypeError: Cannot call method 'get' of undefined
Simply removing the 'NestedModel' variable from the 1st line of generated JavaScript
var MainModel, NestedModel, mm, nm;
Causes the correct behaviour. Obviously I can't keep removing the variable definition from the generated JavaScript. What am I doing wrong?
Ok, it appears to be a scoping issue. See the following jsFiddle example. But why can't I just refer to the classes in the local function scope?

But why can't I just refer to the classes in the local function scope?
Classes are implemented as Immediately Invoked Function Expressions
The key to understanding design patterns such as immediately-invoked function expressions is to realize JavaScript has function scope (but not block scope) and passes values by reference inside a closure.
References
Immediately Invoked Function Expressions

Related

Setting Bookshelf attribute during initialization throws an error on 'this' being undefined

I'm seeing weird behavior regarding 'this' in a Bookshelf model and am stumped. I'm attempting to hash a password using a hook on the 'saving' event. However, if I try and get/set an attribute on 'this', it complains 'this' is undefined:
'use strict';
var DB = require('../config/db'),
_ = require('underscore'),
str = require('underscore.string'),
Base = require('./base'),
Promise = require('bluebird'),
bcrypt = Promise.promisifyAll(require('bcrypt'));
var User = DB.Model.extend({
tableName: 'users',
hasTimestamps: ['createdAt', 'updatedAt'],
// convert snake_case to camelCase
parse: function(attrs) {
return _.reduce(attrs, function(memo, val, key) {
memo[str.camelize(key)] = val;
return memo;
}, {});
},
// convert camelCase to snake_case
format: function(attrs) {
return _.reduce(attrs, function(memo, val, key) {
memo[str.underscored(key)] = val;
return memo;
}, {})
},
initialize: function() {
this.on('saving', this.hashPassword, this);
},
hashPassword: function() {
return bcrypt.genSaltAsync(10).then(function(salt){
return bcrypt.hashAsync(this.get('password'), salt);
}).then(function(hash){
this.set({'password':hash});
});
}
});
module.exports = User;
When I try and save a user model, I'm seeing the following stack trace:
Debug: internal, implementation, error
Error: TypeError: Cannot call method 'get' of undefined
at Object.exports.create (/usr/src/app/node_modules/boom/lib/index.js:21:17)
at Object.exports.internal (/usr/src/app/node_modules/boom/lib/index.js:254:92)
at Object.exports.badImplementation (/usr/src/app/node_modules/boom/lib/index.js:290:23)
at null.<anonymous> (/usr/src/app/routes/users.js:31:20)
at tryCatcher (/usr/src/app/node_modules/bluebird/js/main/util.js:24:31)
at Promise._settlePromiseFromHandler (/usr/src/app/node_modules/bluebird/js/main/promise.js:454:31)
at Promise._settlePromiseAt (/usr/src/app/node_modules/bluebird/js/main/promise.js:530:18)
at Promise._settlePromises (/usr/src/app/node_modules/bluebird/js/main/promise.js:646:14)
at Async._drainQueue (/usr/src/app/node_modules/bluebird/js/main/async.js:177:16)
at Async._drainQueues (/usr/src/app/node_modules/bluebird/js/main/async.js:187:10)
at Async.drainQueues (/usr/src/app/node_modules/bluebird/js/main/async.js:15:14)
at process._tickDomainCallback (node.js:486:13)
Any ideas?
Does this work?
hashPassword: function() {
var self = this;
return bcrypt.genSaltAsync(10).then(function(salt) {
return bcrypt.hashAsync(self.get('password'), salt);
}).then(function(hash) {
self.set({
'password': hash
});
});
}

Using Inheritance Patterns to Organize Large jQuery Applications - how to extend the plugin?

I found this working example of Inheritance Patterns that separates business logic and framework code. I'm tempted to use it as a boilerplate, but since it is an inheritance Pattern, then how can I extend the business logic (the methods in var Speaker)?
For instance, how can I extend a walk: method into it?
/**
* Object Speaker
* An object representing a person who speaks.
*/
var Speaker = {
init: function(options, elem) {
// Mix in the passed in options with the default options
this.options = $.extend({},this.options,options);
// Save the element reference, both as a jQuery
// reference and a normal reference
this.elem = elem;
this.$elem = $(elem);
// Build the dom initial structure
this._build();
// return this so we can chain/use the bridge with less code.
return this;
},
options: {
name: "No name"
},
_build: function(){
this.$elem.html('<h1>'+this.options.name+'</h1>');
},
speak: function(msg){
// You have direct access to the associated and cached jQuery element
this.$elem.append('<p>'+msg+'</p>');
}
};
// Make sure Object.create is available in the browser (for our prototypal inheritance)
// Courtesy of Papa Crockford
// Note this is not entirely equal to native Object.create, but compatible with our use-case
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {} // optionally move this outside the declaration and into a closure if you need more speed.
F.prototype = o;
return new F();
};
}
$.plugin = function(name, object) {
$.fn[name] = function(options) {
// optionally, you could test if options was a string
// and use it to call a method name on the plugin instance.
return this.each(function() {
if ( ! $.data(this, name) ) {
$.data(this, name, Object.create(object).init(options, this));
}
});
};
};
// With the Speaker object, we could essentially do this:
$.plugin('speaker', Speaker);
Any ideas?
How about simply using JavaScript's regular prototype inheritance?
Consider this:
function Speaker(options, elem) {
this.elem = $(elem)[0];
this.options = $.extend(this.defaults, options);
this.build();
}
Speaker.prototype = {
defaults: {
name: "No name"
},
build: function () {
$('<h1>', {text: this.options.name}).appendTo(this.elem);
return this;
},
speak: function(message) {
$('<p>', {text: message}).appendTo(this.elem);
return this;
}
};
Now you can do:
var pp = new Speaker({name: "Porky Pig"}, $("<div>").appendTo("body"));
pp.speak("That's all folks!");
Speaker.prototype.walk = function (destination) {
$('<p>', {
text: this.options.name + " walks " + destination + ".",
css: { color: "red" }
}).appendTo(this.elem);
return this;
}
pp.walk("off the stage");
Runnable version:
function Speaker(options, elem) {
this.elem = $(elem)[0];
this.options = $.extend(this.defaults, options);
this.build();
}
Speaker.prototype = {
defaults: {
name: "No name"
},
build: function () {
$('<h1>', {text: this.options.name}).appendTo(this.elem);
return this;
},
speak: function(message) {
$('<p>', {text: message}).appendTo(this.elem);
return this;
}
};
var pp = new Speaker({name: "Porky Pig"}, $("<div>").appendTo("body"));
pp.speak("That's all folks!");
Speaker.prototype.walk = function (destination) {
$('<p>', {
text: this.options.name + " walks " + destination + ".",
css: { color: "red" }
}).appendTo(this.elem);
return this;
}
pp.walk("off the stage");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

TypeScript kendoTreeView change / select class method callback

I've been searching around to find why Kendo callbacks are not working with TypeScript but I couldn't find something useful.
So my question is how can kendo use class method as a callback?
Ex:
$("#ipt_tree").kendoTreeView(
{
dataSpriteCssClassField: "sprite",
dataSource: data,
template: "<span data-oid='#= item.oid#'>#= item.text#</span>",
//change: this.Tree_Item_Selected, //doens't get even called
//change: ( item: any ): void => //'this' is not 'this' of the class
//{
// this.Tree_Item_Selected( item );
//}
change: function( item: any ) //using compiler this variable
{
_this.Tree_Item_Selected( item );
}
});
The only solution I've found is to use the _this variable that compiler makes.
Now for the jquery the method callbacks work perfectly.
$( "#ipb_aci_button_edit" ).show().on( "click", this.Info_OnClick_Edit );
private Info_OnClick_Edit = (): void =>
{
//'this' is correct
}
If using the current version of TypeScript (1.0RC), you create a class:
class Demo {
private Tree_Item_Selected(item:any) { }
public Create_Tree(data:any) {
var kendoSettings = {
dataSpriteCssClassField: "sprite",
dataSource: data,
template: "<span>#= item.text#</span>",
change: ( item: any ): void =>
{
this.Tree_Item_Selected( item );
},
change2: function( item: any )
{
_this.Tree_Item_Selected( item );
}
};
}
}
And compile that to JavaScript, the functions change and change2 in the example code both produce the exact same code block:
change: function (item) {
_this.Tree_Item_Selected(item);
},
change2: function (item) {
_this.Tree_Item_Selected(item);
}
The only difference is that the second one produces an error that _this is not found.
In the second example, it's working because it's captured the this correctly. However, you might want to consider a different syntax:
$( "#ipb_aci_button_edit" ).show().on( "click",
(e:JQueryEventObject) => { this.Handle_Info_OnClick_Edit(e) } );
private Handle_Info_OnClick_Edit(e:JQueryEventObject): void
{
// 'this' is correct as it was captured by the event handler code
}

AngularJS: i18n and pluralization

Looking on the pluralization part in Spanish here, as an example:
I see that
var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
apparently, all is in English
can anyone explain if this is a bug?
thanks very much
Lior
By glancing the code I can see it's a set of simple pluralization rules. Every locale has this constant. So no, it's not a bug.
Here is how I am doing my i18n work, it seems to be working great! It is based off a set of localized resource files that get initialized at runtime. At the bottom is how I handle pluralization using this approach.
I18n module to hold string id map and parameter insertion
.factory('I18n', ['$http', 'User', function($http, User) {
// Resource File
var LANG_FILE;
// Fetch Resource File
function init() {
return $http.get('resources/locales/' + User.locale + '.json')
.then(function(response) {
LANG_FILE = response.data;
});
}
function lang(stringId, params) {
var string = LANG_FILE[stringId] || stringId;
if (params && params.length) {
for (var i = 0; i < params.length; i++) {
string = string.replace('%' + (i + 1), params[i]);
}
}
return string;
}
return {
init: init,
lang: lang
};
}]);
This can be initialized using a .run block
.run(['I18n', function(I18n) {
I18n.init();
}]);
And used anywhere to translate a string like this
.controller(['$scope', 'I18n', function($scope, I18n) {
$scope.title = I18n.lang(some_string_id);
}]);
Custom i18n DIRECTIVE to handle one time translations
.directive('i18n', ['I18n', function(I18n) {
return {
restrict: 'A',
scope: {},
link: function(scope, $el, attrs) {
$el[0].innerHTML = I18n.lang(attrs.i18n);
}
};
}]);
Which can be used like this.
<div i18n="some_string_id"></div>
Custom PLURALIZE directive that matches string ids from your resource file with the count as the parameter.
.directive('pluralize', ['I18n', function(I18n) {
return {
restrict: 'A',
scope: {
count: '='
},
link: function($scope, $el, attrs) {
var when = JSON.parse(attrs.when)
, param = [$scope.count];
if (when[$scope.count]) {
$el[0].innerHTML = I18n.lang(when[$scope.count], param);
} else {
$el[0].innerHTML = I18n.lang(when['other'], param);
}
}
};
}]);
And can be used like this.
<div pluralize count="{{obj.count}}" when="{1:'single_item','other': 'multiple_item'}"></div>
The String Resource file would be located at resources/locales/en-US.json, and would look something like this.
{
some_string_id: 'This is in English',
single_item: '%1 item',
multiple_item: '%1 items'
}
The other locales would have the same string ids, with different translated texts.

jquery plugin creation issue

I have created a plugin with following codes:
var myplugin = {
init: function(options) {
$.myplugin.settings = $.extend({}, $.myplugin.defaults, options);
},
method1: function(par1) {
.....
},
method2: function(par1) {
.....
}
};
$.myplugin = function(method){
if ( myplugin[method] ) {
return myplugin[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if (typeof method === 'object' || !method) {
return myplugin.init.apply(this, arguments);
} else {
$.error( 'Method "' + method + '" does not exist in myplugin!');
}
};
$.myplugin.defaults = {
option1: 'test',
option2: '',
option3: ''
};
$.myplugin.settings = {};
$.myplugin();
This works well but the issue is that when I try to set more than 1 option and try to return its values afterwards, it gives empty; setting one option works well. For eg.
If on changing the first combo box value I call this:
$.myplugin({option1: 'first test'});
it works, but when I try to call another on second combo box it doesn't save the option, instead it reset to empty.
Is there any fix?
I would re-organize the plugin to use this structure:
var methods = {
settings: {
foo: "foo",
bar: "bar"
},
init: function(options) {
this.settings = $.extend({}, this.settings, options);
},
method1: function(par1) {
alert(this.settings.foo);
},
method2: function(par1) {
alert(this.settings.bar);
}
};
function MyPlugin(options) {
this.init(options);
return this;
}
$.extend(MyPlugin.prototype, methods);
$.myPlugin = function(options) {
return new MyPlugin(options);
}
/* usage */
// without parameters
var obj1 = $.myPlugin();
// with parameters
var obj2 = $.myPlugin({foo: "foobar"});
// each has it's own settings
obj1.method1();
obj2.method1();
Demo: http://jsfiddle.net/ypXdS/
Essentially $.myPlugin simply creates and returns a new instance of the MyPlugin class. You could get rid of it completely and use new myPlugin(options) in it's place.

Resources