knockout observables within an object - javascript

I'm going to try to explain this to the best of my ability. I have an object called BaseForm within that object I have functions and knockout observables. I have a function called Initialize that has an object within it filled with ko observables. One of the observables is called FormVisible and is initialized to true (FormVisible: ko.observable(true)). I also have a function called OnClickRow. In this function it changes FormVisible from true to false. I am instantiating BaseForm multiple times. When I call OnClickRow it only effects the last object that was instantiated. Why does this happen? How can I fix it?
Here's my code:
function BaseForm() {
var that = this;
BaseForm.prototype.Initialize = function(model) {
this.model = model;
this.FormVM = {
FormVisible: ko.observable(true)
}
}
BaseForm.prototype.OnClickRow = function() {
that.FormVM.FormVisible(false);
}
}
this.base1 = new BaseForm();
this.base1.Initialize("new");
this.base2 = new BaseForm();
this.base2.Initialize("old");
this.base3 = new BaseForm();
this.base3.Initialize("other");
this.base1.OnClickRow();
And here is the jsfiddle.

I have actually figured it out. It's a pretty easy fix. I changed this.FormVM to that.FormVM and within OnClickRow I changed that.FormVM.FormVisible(false); to this.FormVM.FormVisible(false). I'm still not enirely sure why this way works and why the other does not. So if anyone has an explanation, that would be great. Thanks!
Here's the updated fiddle.

You need to move the prototype configuration outside of the constructor, and change 'that' to 'this':
function BaseForm() {
var that = this;
}
BaseForm.prototype.Initialize = function(model) {
this.model = model;
this.FormVM = {
FormVisible: ko.observable(true)
}
}
BaseForm.prototype.OnClickRow = function() {
this.FormVM.FormVisible(false);
}
The prototype inheritance chain is called on 'new' or Object.create(). Therefore you should not declare prototype methods in the constructor because there's not guarantee that the prototype chain is initialized yet.
Moving these methods outside the constructor means 'that' would be undefined and using 'this' thus refers to the desired object.
I would suggest a review of the Mozilla Javascript documentation to enhance your knowledge on custom objects.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript#Custom_objects

Related

Get method's instance owner

Given a class and an instance of it
var class=function() {
this.propA=99;
this.methodA=function() {
console.log(this.propA);
};
};
var object=new Class();
I'd like to be able to perform a call to methodA where this will be the instance of it and the example (this.propA) will work. Exactly as
object.methodA.call(object);
but without having any reference to object. Like this in some pseoducode:
var methodToCall=object.methodA;
...
...
methodToCall.call(getInstanceOwnerOf(methodToCall));
The objective of this is to pass methods as callbacks to async functions and keep this as the instance when the method is called.
Some workarounds would be to pass method and object to that async function, or to store this in a local variable, but these are the things I want to avoid.
Use bind to bind to the context you want function called in. Note this returns a NEW function which is not the same as the original.
I usually create the new function and give it a different name but you can do it multiple ways.
To be more specific, you can't be sure this is the class the function is declared in, depends on how you called the function and if you are in strict mode.
an example below:
Fiddle: https://jsfiddle.net/f7af535L/
class SomeClass {
constructor(someVar) {
this.myVar = someVar;
this.publicSayVar = this.sayVar.bind(this);
}
sayVar() {
console.log(this.myVar);
}
}
var object = new SomeClass("hello");
var testcall = object.publicSayVar;
testcall();

javascript pattern used in angular

I followed a AngularJS tutorial on http://www.tutorialspoint.com/angularjs/angularjs_services.htm
The method passed to CalcService service got me confused. Is Angular using revealing prototype or a different one. I was confused because that inner function declared in this.square should be private and not visible outside the context of the object. How Angular is able to access square.
mainApp.service('CalcService', function(MathService){
this.square = function(a) {
return MathService.multiply(a,a);
}
});
An AngularJS service is a very distinct thing.
When it's initialized, it gets newed. Take this as an example:
function CalcService() {
this.square = function() {
// square some stuff
};
}
// then in the controller, directive, or wherever,
// it gets initialized behind the scenes like this
new CalcService();
However, it gets initialized as singleton, meaning that there's only ever one reference to the object, even if the component where you register it attempts to re-initialize it (see my recent answer on singletons in AngularJS).
Not sure what you mean when you mention a "revealing prototype pattern", but the this , in the case of an AngularJS service, is simply implementing a non-prototypal method on a new, regular JavaScript object.
Keeping with the same example above, in "normal" JavaScript, you could call new CalcService().square(). JavaScript doesn't have any native notion of private methods (though there are ways of implementing "class" methods that appear to be private.)
var service = new CalcService();
service.square();
There's nothing "private" about that method, just like there's nothing "private" about methods that are attached to AngularJS service objects... The only thing remotely "private" about it is that it happens to belong only to that specific object by virtue of the this keyword.
In your example, you are passing a constructor function into the angular service DI method.
In the constructor function you assign a method to this.square .
Just try this without angular and you will see you it behaves thr same.
function Calc() {
this.square = function() {
console.log('we get here');
}
}
var calc = new Calc();
calc.square();
This is the main feature of Javascript's prototype object oriented model. This is plain old OO javascript.
Above answers does good explanation how service work but they don't explained how this which is newly created object is exposed.
Whenever you create a service angular create a new object of that function for you, and that's get return whenever its get inject in controller, directive, service, etc. Internally method uses prototype of function to create an this which is context of function. Lets look at below code how it work internally.
function CalcService(){
//The line below this creates an obj object.
//obj = Object.create(CalcService.prototype)
//this = obj;
//`this` is nothing but an instance of function/CalcService.prototype which is giving access to its property attached to this
var privateVariableExample = 'test'; //this is private variable of service.
this.square = function(a) {
//return multiplacation result from here
}
//return this;
}
var objectOfCalcService = new CalcService();
objectOfCalcService.square(1);

Scope issue inside objects that are inside objects

I've come across a problem while trying to build a simple jQuery plugin, having to do with scopes I guess.
The problem in short: A class (A) creates an object (B), in which a property (C) is set to one of the class methods (D). How can I access class A's methods not contained inside the object (B) through the property ( C)?
Longer version (code below): I'm declaring an object (lets call it publicMethods) inside the plugin, comprised of a bunch of methods. These methods should be some default methods (declared inside the plugin), or user declared ones if the user has declared her own when initializing the plugin.
The idea is that when the user defines her own custom method, there should be some functions and variables accessible to her (like this.someVar) in that function.
This creates some limitations though.
I want the default methods to have access to some internal functions and variables, not contained inside the object publicMethods. But when I access these methods through the object they are inside, instead of calling them directly, I do not have access to another variables/functions not inside that object.
I'm trying to find a way to let the default methods have access to it's class siblings. I know I can do some conditional statements before calling the method (if it is user defined or not), or even declare a global variable pointing to "this", but I'd rather keep it clean.
var Plugin = function (opt) {
this.settings = $.extend({
"someVar" : "Value",
"someFunc" : null
});
this.anotherVar = "Hello World";
this.setPublic();
this.run();
}
Plugin.prototype = {
setPublic: function() {
this.publicMethods.someFunc = this.someFunc;
if ($.isFunction(this.settings.someFunc)) {
this.publicMethods.someFunc = this.settings.someFunc;
} else {
this.publicMethods.someFunc = this.someFunc;
}
},
someFunc: function(arg) {
return this.anotherVar; // returns type error the second time
},
run: function () {
this.someFunc();
this.publicMethods.someFunc();
}
}
From MDN: Function.prototype.bind():
The bind() method creates a new function that, when called, has its this keyword set to the provided value, [...].
So the following should work:
setPublic: function() {
this.publicMethods.someFunc = this.someFunc.bind(this);
if ($.isFunction(this.settings.someFunc)) {
this.publicMethods.someFunc = this.settings.someFunc.bind(this);
}
// This is redundant anyway:
/* else {
this.publicMethods.someFunc = this.someFunc.bind(this);
}*/
},

Accessing property of parent in nested object

I am refactoring some JS code and need to access Objects like
Object1.Object2.IsValid();
this is what I have right now.
function _Object1(object) {
this._object1 = object;
this.Object2= new _Object2();
function IsValid() {
// tests here
}
}
function _Object2()
{
function IsValid() {
// tests here but needs to use Object1 property above.
}
}
Only problem being, I am not sure how to access Object1 in Object2 without passing any parameter. Nesting Object2 in Object1, perhaps?
Edit: I am tring to implement OOP in JS, which is like reinventing the wheel, but want to try it for now :)
I will explain the question in terms of OOP:
I have a class _Object1 and it has a method IsValid(). _Object1 also has a property Object2 which is of type _Object2.
Now, _Object2 also has method named IsValid(). But here is a catch, _Object2.IsValid need the value of _Object1 for tests.
For the above code if I do:
var Object1 = new _Object1();
I can simply call Object1.Object2.IsValid() for the result. Isn't it?
Disclaimer: I have been using JS for sometime now, but never had to dabble with things like these.
Give _Object2 what it needs:
function _Object1(object) {
this._object1 = object;
this.Object2= new _Object2(this);
function IsValid() {
// tests here
}
}
function _Object2(parentObject)
{
function IsValid() {
// parentObject refers to the _Object1 that created this object
}
}
I think what you're looking for is impossible, unless you are willing to pass the data in to the object.
Just because your _Object2 instance has been created inside the _Object1 constructor, it does not automatically have any reference to the data of your _Object1 instance. You would have to tell the _Object2 instance about the _Object1 values either in the constructor function or via some other method:
function _Object2(parentObject) { /* ... */ }
// or
_Object2.prototype.setParent = function(parent) { /* ... */}
// or
myObject2.parent = this._object1;

Backbone structure for custom objects

Looking at some backbone examples, I see some simple models like this:
var Vehicle = Backbone.Model.extend(
{
summary: function () {
return 'Vehicles move';
}
});
or
Vehicle = (function () {
return Backbone.Model.extend({
defaults: {
},
initialize: {
}
});
})();
Edit: (clarification)
I was wondering if someone could explain the differences between the two ways of defining backbone objects and what's more conventional. I know they don't have the same methods inside, but I'm more interested in how in the first one, they extend the backbone model, and the second one, they wrap it in a closure. I'm not sure if I really grasp what's going on in each and when you would use which pattern. Thanks in advance!
I would consider the first form much more conventional, especially since I don't even see the second form on the main Backbone.js website at all.
To understand how they do the same thing, first notice that Backbone.Model.extend() is a function that also returns a function:
> Backbone.Model.extend()
function () { return parent.apply(this, arguments); }
So the variable Vehicle ends up being set to a function that is a model constructor method either way you look at it. I would consider the second form more indirect and unnecessarily complex, though: it is setting Vehicle to the result of calling a function that, itself, just returns Backbone.Model.extend(), so its just a more convoluted way of saying the same thing.
If all the properties for the model are easy to define, pattern 1 is suggested. However, if any property is complex to implement thus need a "private" helper function which you do not want expose it either in your model or in global object, better to utilize the closure to hide it. that is the pattern 2.
An Example:
Vehicle = (function () {
function helper1() {} //don't want to expose it
function helper2() {}
return Backbone.Model.extend({
defaults: {
},
initialize: {
}
summary: function() {
helper1();
helper1();
}
});
})();

Categories