Access local function inside ko.computed - javascript

How come this line of code doesnt work.
Im using durandal/knockout and i have a structure like this
define(function () {
var vm = function() {
compute: ko.computed(function() {
return _compute(1); // fail
});
var _compute= function(e) {
return e;
}
}
return vm;
});
Basically I am just trying to access the private method _compute - but KO.compute doesnt allow that?
Even if i make it public, I still cant access it.
I trying to implement revealing pattern in this, but still no luck!
var vm = function() {
compute: ko.computed(function() {
return this._compute(1); // still failing
});
this._compute= function(e) {
return e;
}
}
update: so far, only this one works
define(function () {
var vm = function() {
var self = this;
var self._compute= function(e) {
return e;
}
compute: ko.computed(function() {
return this._compute(1); // works
}, self);
}
but like I said, _compute is not meant to be exposed.
Update: actually its another error.
this one now works
define(function () {
var vm = function() {
var self = this;
var _compute= function(e) {
return e;
}
compute: ko.computed(function() {
return _compute(1); // works
});
}
Basically, just need to declare the private function before the ko.computed prop!
Thanks!
Additional Note:
Why does it need to be declared before the computed function? I prefer all my "properties" in the first lines while the functions in the bottom. It is neater i Think.

This syntax does not create a property when in a function:
compute: ko.computed(function() {
return _compute(1); // fail
});
You have to use = instead of :.
Try this
var vm = function() {
var self = this;
var _compute = function(e) {
return e;
}
this.compute = ko.computed(function() {
return _compute(1);
});
}
Also note that this is not how you should use a computed observable. It should contain calls to other observables!
From doc:
What if you’ve got an observable for firstName, and another for
lastName, and you want to display the full name? That’s where computed
observables come in - these are functions that are dependent on one or
more other observables, and will automatically update whenever any of
these dependencies change.

Related

Javascript & knockoutjs: how to refactor the following code to be able to access the properties outside the function

Im struggling to find a way to get the properties Override & Justification available outside of the function. The code is:
self.CasOverridesViewModel = ko.observable(self.CasOverridesViewModel);
var hasOverrides = typeof self.CasOverridesViewModel === typeof(Function);
if (hasOverrides) {
self.setupOverrides = function() {
var extendViewModel = function(obj, extend) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
extend(obj[property]);
}
}
};
extendViewModel(self.CasOverridesViewModel(), function(item) {
item.isOverrideFilledIn = ko.computed( function() {
var result = false;
if (!!item.Override()) {
result = true;
}
return result;
});
if (item) {
item.isJustificationMissing = ko.computed(function() {
var override = item.Override();
var result = false;
if (!!override) {
result = !item.hasAtleastNineWords();
}
return result;
});
item.hasAtleastNineWords = ko.computed(function() {
var justification = item.Justification(),
moreThanNineWords = false;
if (justification != null) {
moreThanNineWords = justification.trim().split(/\s+/).length > 9;
}
return moreThanNineWords;
});
item.isValid = ko.computed(function() {
return (!item.isJustificationMissing());
});
}
});
}();
}
I've tried it by setting up a global variable like:
var item;
or
var obj;
if(hasOverrides) {...
So the thing that gets me the most that im not able to grasp how the connection is made
between the underlying model CasOverridesviewModel. As i assumed that self.CasOverridesViewModel.Override() would be able to fetch the data that is written on the screen.
Another try i did was var override = ko.observable(self.CasOverridesViewModel.Override()), which led to js typeError as you cannot read from an undefined object.
So if anyone is able to give me some guidance on how to get the fields from an input field available outside of this function. It would be deeply appreciated.
If I need to clarify some aspects do not hesitate to ask.
The upmost gratitude!
not sure how far outside you wanted to go with your variable but if you just define your global var at root level but only add to it at the moment your inner variable gets a value, you won't get the error of setting undefined.
var root = {
override: ko.observable()
};
root.override.subscribe((val) => console.log(val));
var ViewModel = function () {
var self = this;
self.override = ko.observable();
self.override.subscribe((val) => root.override(val));
self.load = function () {
self.override(true);
};
self.load();
};
ko.applyBindings(new ViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

How to organise this module pattern and elegantly deal with ajax calls

I have couple of modules that do their own thing, but need them to sometimes access a property of one another (not that intertwined, just one json obj). Like so
var Bananas = (function() {
// Bananas.properties would look like this
// Bananas.properties = { 'color' : 'yellow' };
var methodToGetProperties = function() {
API.get('bananas')
.done(function(data) {
Bananas.properties = data;
}
};
var publiclyReturnProperties = function() {
if (!Bananas.properties) {
methodToGetProperties();
} else {
return Bananas.properties;
}
};
var doSomethingBananas = function() {
bananas.doing.something;
bananaHolder.innerHTML = Bananas.properties;
}
var init = function() {
doSomethingBananas
}
return {
init: init,
properties: publiclyReturnProperties,
};
})();
var Apples = (function() {
var doSomethingApples = function() {
apple.innerHTML = Bananas.properties.color;
};
var init = function() {
doSomethingApples();
};
return {
init: init
};
})();
Bananas.init(); Apples.init();
Now, the way I do it now is by simply revealing the methodToGetProperties, which returns the API call, and then work on using jQueries deferred method wherever I call it. But I feel this ruins my code by putting .done everywhere.
I've been reading up to singleton pattern and feel it might be the solution to my problem, but I'm not sure how to implement it. Or maybe implement a callback function in methodToGetProperties, but again not confident as to how.
Would kindly appreciate advice on how to organise my app.

Passing variable into object method javascript

trying to get my head around objects, methods, closures, etc... in Javascript.
Can't see why this isn't working, some fundamental flaw in my thinking I guess. I'm expecting the val variable to be passed through to the addNote() function but it isn't. I thought that any variables declared outside of a function are available to that function, as long as they're not within another function. Is that not correct?
if(typeof(Storage) !== "undefined") {
console.log(localStorage);
var $input = $('#input'),
$submit = $('#submit'),
$list = $('#list'),
val = $input.val();
var noteApp = {
addNote : function(val) {
var item = val.wrap('<li />');
item.appendTo($list);
clearField();
},
clearField : function() {
$input.val = '';
},
delNote : function(note) {
}
};
$submit.on('click', function(){
noteApp.addNote();
});
} else {
}
I'm trying to learn how the pros manage to get their code so clean, concise and modular. I figured a note app would be a perfect start, shame I got stuck at the first hurdle...
Cheers.
There are several issues with the code in the question
defining an argument named val and not passing an argument to the function
when calling clearField() inside the object literal it's this.clearField()
You're only getting the value once, not on every click
val is a string, it has no wrap method
$input.val = ''; is not valid jQuery
I would clean it up like this
var noteApp = {
init: function() {
if (this.hasStorage) {
this.elements().events();
}
},
elements: function() {
this.input = $('#input');
this.submit = $('#submit');
this.list = $('#list');
return this;
},
events: function() {
var self = this;
this.submit.on('click', function(){
self.addNote();
});
},
hasStorage: (function() {
return typeof(Storage) !== "undefined";
})(),
addNote: function() {
this.list.append('<li>' + this.input.val() + '</li>');
this.clearField();
return this;
},
clearField: function() {
this.input.val('');
},
delNote : function(note) {
}
}
FIDDLE
Remember to call the init method
$(function() { noteApp.init(); });
In your call to addNote(), you don't pass any argument for the val, so it will be undefined:
noteApp.addNote();
// ^^ nothing
Pass the input (seems you want the jQuery object not the string value because of your val.wrap call):
noteApp.addNote($input);
When you declare the val in the function, it is scoped to that function and will only be populated if the function call passes a value for that argument. Even if you have another variable in an upper scope with the same name val, they are still differentiated. Any reference to val in the function will refer to the local val not the upper scope.

Defining computed observables on members of child array using Knockout mapping plugin

I have the following:
// Child Array is Cards, trying to add computed observable for each child
var CardViewModel = function (data) {
ko.mapping.fromJS(data, {}, this);
this.editing = ko.observable(false);
};
var mapping = {
'cards': { // This never gets hit, UNLESS I remove the 'create' method below
create: function (options) {
debugger;
return new CardViewModel(options.data);
}
},
create: function(options) {
var innerModel = ko.mapping.fromJS(options.data);
innerModel.cardCount = ko.computed(function () {
return innerModel.cards().length;
});
return innerModel;
}
};
var SetViewModel = ko.mapping.fromJS(setData, mapping);
debugger;
ko.applyBindings(SetViewModel);
However I can't get the 'cards' binding to work - that code isn't reached unless I remove the 'create' method. I'm trying to follow the example from the knockout site:
http://knockoutjs.com/documentation/plugins-mapping.html
They do this for the child object definition:
var mapping = {
'children': {
create: function(options) {
return new myChildModel(options.data);
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
With the ChildModel defined like this:
var myChildModel = function(data) {
ko.mapping.fromJS(data, {}, this);
this.nameLength = ko.computed(function() {
return this.name().length;
}, this);
}
I've spent the past day on this and cannot for the life of me figure out why this isn't working. Any tips would be awesome.
EDIT: Here's a fiddle of what I'm working with. It's only showing SIDE 1 in the result because "editing" isn't recognized here:
<div data-bind="visible: !$parent.editing()" class="span5 side-study-box">
http://jsfiddle.net/PTSkR/1/
This is the error I get in chrome when I run it:
Uncaught Error: Unable to parse bindings. Message: TypeError: Object
has no method 'editing'; Bindings value: visible: !$parent.editing()
You have overridden the create behavior for your view model. The mapping plugin will not call any of the other handlers for the properties for you. Since you're mapping from within the create method, move your cards handler in there.
var mapping = {
create: function(options) {
var innerModel = ko.mapping.fromJS(options.data, {
'cards': {
create: function (options) {
debugger;
return new CardViewModel(options.data);
}
}
});
innerModel.cardCount = ko.computed(function () {
return innerModel.cards().length;
});
return innerModel;
}
};
updated fiddle
you didnt needed to have parenthesis. I just changed from
!$parent.editing()
to
!$parent.editing
See the updated fiddle here

Choose which set of methods an object has, based on argument during object creation - JavaScript

I have searched and read for a few hours yet I still cant understand the basic design pattern for creating a new object that has a choice of different methods (of the same name) that is set dependant on one of the arguments. here's some code to explain what I am trying to do.
All advice and alternative approaches welcome. I hope someone can emancipate me form this cloud of ignorance.
Thanks
function BaseConstructor(whichMethods) {
if (whichMethods==='a') {
// do something to incorporate methodSetA
}
else if (whichMethods==='b') {
// do something to incorporate methodSetB
}
this.init();
};
var methodSetA = {
init: function() {
// do initialisation A way
},
speak: function() {
alert('i speak AAA way')
}
};
var methodSetB = {
init: function() {
// do initialisation B way
},
speak: function(){
alert('i got BBB all the way')
}
};
thing = new BaseConstructor('b');
// b is an instance of BaseConstructor and has done the bWay init() function
thing.speak() // return alert 'i got BBB all the way'
You can do it like this using a factory function (a regular function that creates the appropriate object for you):
function BaseConstructor(whichMethods) {
var elem;
if (whichMethods==='a') {
elem = new MethodSetA();
} else if (whichMethods==='b') {
elem = new MethodSetB();
} else {
// figure out what to do here if whichMethods is neither of the previous options
}
elem.init();
return(elem);
};
And invoke it as a regular function call:
var thing = BaseConstructor('b');
thing.speak();
Note: there is no use of new with BaseConstructor() as it's a regular function call.
Well, to do it your way using "method sets," you can iterate and copy into this (here's a demo):
function copy(source, destination) {
for(var x in source) {
if(source.hasOwnProperty(x)) {
destination[x] = source[x];
}
}
}
function BaseConstructor(whichMethods) {
if(whichMethods === 'a') {
copy(methodSetA, this);
} else if(whichMethods === 'b') {
copy(methodSetB, this);
}
this.init();
}
Personally, though, I'd prefer to assign directly to this.
You are looking for factory pattern.
Example:
function objectFactory(whichMethods) {
if (whichMethods==='a') {
return new objectSetA();
}
else if (whichMethods==='b') {
return new objectSetB()
}
};
function objectSetA() {
this.init = function() {
// do initialisation A way
},
this.speak = function() {
alert('i speak AAA way')
}
};
function objectSetB() {
this.init = function() {
// do initialisation B way
},
this.speak = function(){
alert('i got BBB all the way')
}
};
var thing = objectFactory('b');
thing.speak();

Categories