Initialize custom ko.computed in class - javascript

I don't know if it's possible, but I would like to achieve something like this:
function templateCheck(Properties,ComputedFunction){
var self = this;
self.Prop1 = ko.observable(Properties.Prop1);
self.CustomCaltulation = ko.computed(ComputedFunction);
return {
returningValue: self.CustomCalculation
}
}
// This doesn't work
var test = new templateCheck({Prop1: "something"},function(){ return self.Prop1(); })
// Error: TypeError: Object [object global] has no method 'Prop1'
Thus far I'm unsuccessful to achieve this.

There's no need for a 'self' variable. It's actually making it harder for you, since 'self' is not defined outside the context of templateCheck, as you found out. The trick is to use the 'owner' property of the computed variable, which sets the 'meaning' of this
function templateCheck(Properties, ComputedFunction){
this.Prop1 = ko.observable(Properties.Prop1);
this.CustomCalculation = ko.computed({
read: ComputedFunction,
owner: this
});
return {
returningValue: this.CustomCalculation
};
}
var test = new templateCheck({Prop1: "something"},function(){ return this.Prop1(); })
I do wonder why you are trying to do this though. It feels a bit like a code smell to me. Maybe there's a better way?

Your problem is that the self variable is not defined in the context of your function.
function templateCheck(Properties){
var self = this;
self.Prop1 = ko.observable(Properties.Prop1);
self.setComputedFunction(computedFunction) {
self.customCalculation = ko.computed(computedFunction);
}
}
var template = new templateCheck({Prop1: "something"});
var myComputedFunction = function(){ return template.Prop1(); };
template.setComputedFunction(myComputedFunction);
var test=template.customCalculation;

You have written self.CustomCaltulation instead of self.CustomCalculation . This might not be the issue in your case but soon i see your question i found this.

Related

Are private members in javascript really that complicated?

I am trying to clarify my understanding of private members in Javascript. It seems like it should be easy:
function MyClass(param) {
var thisIsPrivate = param;
this.getPrivateMember = function() {
return thisIsPrivate;
}
}
var thing = new MyClass('tada!');
console.log(thing.thisIsPrivate) // undefined
console.log(thing.getPrivateMember()) // "tada!"
In my reading, I keep coming across articles that don't even mention this as an option, but rather come up with complicated solutions like using closures or WeakMaps. Often the conclusion is that there is no good way to work with private members in Javascript.
Can anybody fill me in on what I'm missing? Is this a bad idea for some reason?
Thanks for the replies. So my understanding of the limitation of this approach is that methods added outside of the constructor cannot see the 'private' variables. I feel somewhat enlightened.
function MyClass(param) {
var thisIsPrivate = param;
this.getPrivateMember = function() {
return thisIsPrivate;
}
}
MyClass.prototype.showPrivateMember = function(){
console.log(thisIsPrivate);
}
var thing = new MyClass('tada!');
console.log(thing.thisIsPrivate) // undefined
console.log(thing.getPrivateMember()) // tada!
thing.showPrivateMember(); // ReferenceError: thisIsPrivate is not defined at MyClass.showPrivateMember
thing.showPrivateMember = function(){
console.log(thisIsPrivate);
}
thing.showPrivateMember(); // ReferenceError: thisIsPrivate is not defined at MyClass.showPrivateMember

confusion, this-pointer and events in javascript

I have a javascript object which I would like to be able to handle some interactive features. It's a bit tricky to describe the scenario in a simple way so hopefully it'll not get all out of hand here.
my object looks something like
myobject = function() {
this.initialize = function() {
// HERE this = the myobject instance
var test = document.createElement('div');
test.onmousedown = this.mousedown;
}
this.mousedown = function(e) {
// HERE this = the calling div-element
}
}
So my problem is basically that this will not be an myobject instance when this.mousedown(e) is called, it will rather be the caller (if the terminology is correct?) in this case it is the div I created and put in a variable called test above.
I would like to have access to the instance on which the method is being run (as I believe that to be the mousedown method I created).
This far I have had some ideas which I have tried out:
create a data- attribute on the div containing the this object and operate on that.
sending the this pointer as an argument along with e to this.mousedown(e)
It's all I can think of now hope it makes sence.
You could create a copy when you first instantiate the object:
var myobject = function() {
var self = this;
this.initialize() {
// HERE this = the myobject instance
var test = document.createElement('div');
test.onmousedown = this.mousedown;
}
this.mousedown(e) {
// HERE this = the calling div-element
// use self instead of this
}
}
The simplest solution is to make a 'self' var that you refer to in the callback:
myobject = funciton() {
var self = this;
this.initialize() {
//use self to refer to myobject
self.mousedown(e);
}
this.mousedown(e) {
}
}

TypeError xxx is not a function

All, I am struggling with an error which says TypeError: curTemplete.addSection is not a function, Please forgive that I am not familiar with the js OO, Please help to review my problem. thanks.
The code looks like below.
Templete.js
LayoutTemplete=function(currentTmpContainer,templeteId,data)
{
var curTemplete = this;
curTemplete.addSection(null, null);//this line run with error above.
this.addSection = function(uiItem, data) {
alert('ddd');
};
};
In the dom ready event.
function loadTempleteContent(templeteId)
{
var jData=[{name: 'jerry'},{name: 'mike'},{name: 'claire'}];
var tmp = new LayoutTemplete($("#currentTmpContainer"),templeteId,jData);
}
You cannot call a function before it was defined. This has nothing to do with OOP. Consider this example:
foo();
var foo = function() {
alert(42);
};
It will throw a similar error.
Define the function/the property before you access it:
this.addSection = function(uiItem, data) {
alert('ddd');
};
this.addSection(null, null);
Better yet, define addSection on the prototype, so that you don't create a new function every time you create an instances of LayoutTemplete.
LayoutTemplete = function(currentTmpContainer,templeteId,data) {
this.addSection(null, null);
};
LayoutTemplete.prototype.addSection = function(uiItem, data) {
alert('ddd');
};
Felix is trying to tell you what your issue is, here it is explicitly:
var curTemplete = this;
curTemplete.addSection(null, null);//this line run with error above.
Here you reference and attempt to call curTemplete.addection, which has not been assigned a value yet, so it resolves to undefined. When the call is attempted, undefined is not a function (as the error tells you). addSection is not defined until the assignment below:
this.addSection = function(uiItem, data) {
alert('ddd');
};
Now it's defined. Move the assignment before the call (and if you're going to assign this to a local variable, you may as well use it):
var curTemplete = this;
curTemplete.addSection = function(uiItem, data) {
alert('ddd');
};
curTemplete.addSection(null, null);

Javascript inheritance on variable within a function (OpenERP)

Basically I'm trying to override a function by extending it. I have the following base (simplified) code:
openerp.point_of_sale = function(db) {
var Order = Backbone.Model.extend({
exportAsJSON: function() {
return {'bigobject'}
}
})
}
Then, I'm writing my own .js where I want to inherit and override exportAsJSON function and I'm not sure how to .extend it. Here is my erroneous approach:
openerp.my_module = function(db) {
db.point_of_sale.Order = db.point_of_sale.Order.extend({
exportAsJSON: function() {
var order_data = this._super();
//... add more stuff on object
return order_data;
}
})
}
What would be the correct way of doing it?
I hope I'm providing enough information for an answer (I'm working on OpenERP by the way). Any help will be appreciated.
EDIT:
More specifically, the error seems to be in the extension itself:
db.point_of_sale.Order = db.point_of_sale.Order.extend({
...even if I put a simple return 0; within my exportAsJSON function, the page doesn't load and I get the following error in my browser console:
"Cannot call method 'extend' of undefined"
I think you want something like SuperClass.prototype.method.call(this):
openerp.my_module = function(db) {
db.point_of_sale.Order = db.point_of_sale.Order.extend({
exportAsJSON: function() {
var order_data = db.point_of_sale.Order.prototype.exportAsJSON.call(this);
//... add more stuff on object
return order_data;
}
})
}
This is how you would normally do that in JavaScript:
var eaj = db.point_of_sale.Order.prototype.exportAsJSON;
db.point_of_sale.Order = db.point_of_sale.Order.extend({
exportAsJSON: function() {
var order_data = eaj.apply( this, arguments );
//... add more stuff on object
return order_data;
}
})
This is basically where you problem lies:
openerp.point_of_sale = function(db) {
var Order = Backbone.Model.extend({
^
|
this is a private variable
not a property!
Therefore you cannot access it at all. If it was defined like this:
openerp.point_of_sale = function(db) {
openerp.point_of_sale.Order = Backbone.Model.extend({
^
|
this is now a property of point_of_sale
(basically public variable)
then you can access it the way you're trying to:
db.point_of_sale.Order = db.point_of_sale.Order.extend({
So, the answer is you cannot do that. You need to extend or modify db.point_of_sale instead of Order.

Javascript apply — Inheriting classes

The code below is adapted from this answer
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
ErrorMessageClass.prototype = new MessageClass();
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate());
console.log(errorB.getPrivate());
The original post did not have the MessageClass.apply(this, arguments); since the purpose was to show how inheritance can go wrong in Javascript.
My question is, is saying: ErrorMessageClass.prototype = new MessageClass(); before the ErrorMessageClass constructor has even been declared bad practice? My understanding is that calling undeclared identifiers like that causes a silent declaration to occur, with the result being placed on the global window object, which I understand is bad.
Is this form:
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
ErrorMessageClass.prototype = new MessageClass();
considered to be better practice? This link shows the code written as it was originally above, which is why I even tried it. Does this blogger know something I don't (quite likely)?
EDIT
Lots of great info in the answers below, but I did want to highlight this link which really explains things perfectly
Usually, to avoid this confusion, you would just attach the prototype after, but as Adam Rackis pointed out, function declarations are hoisted, like var statements.
However, you should not instantiate the base object as the prototype. If your base object takes arguments, what are you supposed to use? Use an empty "surrogate" constructor
// Used to setup inheritance
function surrogate () {};
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
// The key steps to creating clean inheritance
surrogate.prototype = MessageClass;
// Sets up inheritance without instantiating a base class object
ErrorMessageClass.prototype = new surrogate();
// Fix the constructor property
ErrorMessageClass.prototype.constructor = ErrorMessageClass
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
There's much more to be said. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
It works because function declarations are evaluated first. If you tried to move these classes under an object literal "namespace" the first version would fail.
I personally find the second method to be much easier to read - also, don't forget to set the sub-class' prototype.constructor property back to itself. Personally, I use an inherits() method on the Function prototype which wraps up essentially the type of code you're using here.

Categories

Resources