Access Computed Value in subscribable function - javascript

When using my view model:
function SummaryViewModel (arrayString) {
//------- Attributes -------
var self = this;
self.Claims = ko.observableArray(namesapce.Helpers.subnamespace.ToCollection(arrayString));
self.ShowTable = ko.computed(function() {
var collection = ko.unwrap(self.Claims());
return collection.length > 0;
}, this);
self.showWarningPanel = self.ShowTable.Not();
}
I am trying to invert the computed value. So either the table will be displayed or a warning message.
I have created the following subscribable function:
ko.subscribable.fn.Not = function () {
return ko.pureComputed(function() {
var bool = this();
return !(ko.unwrap(bool));
});
};
However, the value for this() does not provide the value of the computed attribute. It instead returns all the objects in the current scope.
Originally I marked the method as ko.computed.fn and this also did not return the computed value.
I have been referring to the documentation on the KO website to help build the function.
http://knockoutjs.com/documentation/fn.html

You'll have to pass this to the pureComputed you're creating inside:
ko.subscribable.fn.Not = function () {
return ko.pureComputed(function() {
return !this();
}, this);
// ^^^^ Here, you tell knockout to execute the function with `this`
// context. Alternatively, you could use the var `self = this`
// pattern.
};
var myObs = ko.observable(true);
var invertedObs = myObs.Not();
myObs(false);
console.log("observable: " + myObs());
console.log("inverted: " + invertedObs());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

Related

private object not setting data

Hi I'm trying to implement a LinkedList in Javascript. When i assign a value to my node it doesn't seem to store it when I use my getter. For example:
var Node =function() {
var _data;
var _next ={};
var that = this;
that.getData = function() {
return _data;
};
that.setData = function(data) {
that._data = data;
};
that.getNext = function() {
return _next;
};
that.setNext = function(next) {
that._next = next;
};
return that;
};
Will not work with:
var nodeObj = new Node();
nodeObj.setData("hello");
console.log(nodeObj.getData());
_data is not the same as that._data, you must do this:
that.getData = function() {
return that._data;
};
OR you could do this instead:
that.setData = function(data) {
_data = data;
};
the benefit of the second approach being that you're simulating a private variable (because you cannot do nodeObj._data in the second case but you can in the first)
also var that = this; is unnecessary, you can simply do this._data in this case.
For your case here, you can assume that if you're calling a function like yourObject.someFunction(), then within someFunction the value of this equals yourObject. (And this isn't always true in javascript but since you're starting off you should think about it this way for now. If you pass a function to another function as a variable and then call it then this wouldn't be the case).

How to get property call a function with javascript?

I need to know who call a function, for example i have code like this :
var observe = function(newvalue, callback) {
console.log('who call me?');
callback('new value is ' + newvalue);
}
var ViewModel = function() {
var self = this;
self.Id = '1';
self.Name = observe;
self.NickName = observe;
self.someFunction = function() {
return 1 + 2;
}
}
var vm = new ViewModel();
vm.NickName('test', function(resp) {
console.log(resp);
})
For this example, in observe i need the code know who call it is vm.NickName or NickName.
How to trick this problem with pure javascript?
From within a function, you cannot determine what reference was used to call it. If you want to do that, you need to create separate functions (which can then call the central one), or pass it an argument that tells it how it's being called, etc.
For instance, this example passes it an argument:
var observe = function(who, newvalue, callback) {
console.log('Called by: ' + who);
callback('new value is ' + newvalue);
};
// ...
self.Name = observe.bind(self, 'Name');
self.NickName = observe.bind(self, 'NickName');

Extend the properties returned by a function?

I'm a JS beginner. I have defined a function on my Backbone model as follows.
myFunction: function () {
return {
firstAttr: this.model.get('value-attribute')
};
}
It is available to me as this.myFunction.
From somewhere else in the code, I want to extend this.myFunction to return another attribute. In other words, I'd like it to return a dict with two attributes: { firstAttr: 'something', secondAttr: true }.
How can I do this?
I've tried:
this.myFunction().secondAttr = true;
but I know that's the wrong thing to do.
Assuming your model prototype looks like
var MyModel = Backbone.Model.extend({
myFunction: function () {
return {
// I assume you work directly on a model
// the principle would be the same with a wrapper object
firstAttr: this.get('value-attribute')
};
}
});
you can either mask your method on a model by model basis like this:
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
m.myFunction = function () {
var res = MyModel.prototype.myFunction.call(this);
res.secondAttr = true;
return res;
};
console.log(m.myFunction());
See http://jsfiddle.net/V8zt2/ for a demo
Or dynamically modify your prototype to alter all instances :
var f = MyModel.prototype.myFunction;
MyModel.prototype.myFunction = function () {
var res = f.call(this);
res.secondAttr = true;
return res;
};
var m = new MyModel({'value-attribute': 'attr, the first'});
console.log(m.myFunction());
http://jsfiddle.net/V8zt2/1/
How about modifying your myFunction to :
myFunction : function () {
var i,
obj = {};
for (i=0; i< arguments.length;i++){
obj['attribute'+(i+1)] = this.model.get(arguments[i]);
}
return obj;
}
This way you can send keys of model, that you want to be in the returned object as arguments to myFunction.

Javascript: Modify array directly only within its own function

I have a very simple function:
var errorsViewModel = function () {
var self = this;
var _errors = ko.observableArray([]);
self.get = function () {
return _errors;
};
self.insert = function ( error ) {
_errors.push(error);
};
}
What I want to acomplish is make _errors array modifiable directly only within its own function. That is users from outside can get the array for reading through the get method and insert itsert items only through the insert method.
But not to be able to do something like this:
var err = new errorsViewModel();
var array = err.get();
array.push('item');
Instead use the errorsViewModel interface :
err.insert('some error');
Is that possible?
Just copy the returned array:
self.get = function () {
return _errors.slice(0);
};
That way, when get is called, the caller can make changes to it if they want - but it won't modify the original.
To make sure that your array isn't accessible from outside your scope I would suggest that you expose the array via a ko.computed and then notify it's listeners on an insert.
var errorsViewModel = function () {
var self = this;
var _errors = [];
self.errors = ko.computed(function () {
return self.get();
});
self.get = function () {
return _errors.splice(0);
};
self.insert = function ( error ) {
_errors.push(error);
self.errors.valueHasMutated();
};
}

Object Not Defined with Knockout Data Mapping Plugin

I'm trying to use the mapping plugin to make children objects' properties observable. I have the following:
// setData defined here
var mapping = {
create: function(options) {
//customize at the root level.
var innerModel = ko.mapping.fromJS(options.data);
innerModel.cardCount = ko.computed(function () {
debugger;
return this.cards().length; // cards not defined - "this" is Window for some reason
});
innerModel.deleteCard = function (card) {
// Pending UI
// call API here
// On success, complete
this.cards.remove(card);
}.bind(this);
innerModel.addCard = function () {
//debugger;
// Pending UI
// Call API here
// On success, complete
this.cards.push(dummyCard);
//this.cardToAdd("");
}.bind(this);
return innerModel;
}
};
var SetViewModel = ko.mapping.fromJS(setData, mapping);
ko.applyBindings(SetViewModel);
When I run this in chrome debugger, I get "Object [Object global] has no method cards". Cards should be an observable array. What am I doing wrong?
innerModel.cardCount = ko.computed(function () {
debugger;
return this.cards().length; // cards not defined - "this" is Window for some reason
});
this is inside the anonymous function you're creating and is therefore bound to the global object. if you want to reference innermodel you'll have to do so directly, or bind innermodel to the function.
innerModel.cardCount = ko.computed(function () {
return innerModel.cards().length;
});
or
var computedFunction = function () {
return this.cards().length;
};
innerModel.cardCount = ko.computed(computedFunction.apply(innerModel));

Categories

Resources