Save function value to variable - javascript

I have this in my AngularJS application:
$scope.user = {
numberValue: null
}
and I have this function that returns a value:
$scope.formalTrainingCosts = function () {
return $scope.user.avePaynonTrainedEmployees * $scope.user.newEmployeeFormalTrainingHours;
}
Can I save that value to the variable numberValue like so $scope.user.numberValue = $scope.formalTrainingCosts? If that does not work, what else can I do to get the function saved to the variable?

the answer by Blackhole will work but you can also put the function straight into the object. The downside to that would be that the function would be called every time you referenced that variable whereas Blackhole's answer would call the function once and save the answer.
$scope.user = {
numberValue: function() {
return $scope.user.avePaynonTrainedEmployees * $scope.user.newEmployeeFormalTrainingHours;
}
}
or
$scope.user = {
numberValue: $scope.formalTrainingCosts()
}

Related

Function definition cannot understand

I know some javascript function declarations. Like exression function, anonymous function, but I do not understand what kind of syntax of these two functions? Can anybody tell me what is the name of these two functions? I mean "manipulateData: function (input)" and "getDataById: function (id)".
Why return statement can have this syntax to return two functions? Why not return one function in one time instead of two functions? It will be great if you can give me some reference documents? Thanks.
app.service('MyService', function ($http, $q, $angularCacheFactory) {
var _dataCache = $angularCacheFactory('dataCache', {
maxAge: 3600000 // items expire after an hour
});
/**
* #class MyService
*/
return {
manipulateData: function (input) {
var output;
// do something with the data
return output;
},
getDataById: function (id) {
var deferred = $q.defer();
if (_dataCache.get(id)) {
deferred.resolve(_dataCache.get(id));
} else {
// Get the data from the server and populate cache
}
return deferred.promise;
}
};
});
These functions are just anonymous functions that happen to be values in an object. Consider this:
var object = {
add: function(x, y) {
return x + y;
}
};
object.add(1, 2); // = 3
This is the same as:
function addFunction(x, y) {
return x + y;
}
var object = {
add: addFunction
};
object.add(1, 2); // = 3
There's nothing special about these functions, as they're just normal properties of an object.
You are not returning a function in this case but an Object.
When you define a service in angularjs you have to provide its implementation in the callback (the second argument of app.service)
This callback has to return methods you want to make available to other parts of your application.
Then in a controller or in another service you will be able to write:
app.controller("MyCtrl", ["MyService", function(MyService) {
MyService.getDataById('an id');
}]);
Angular Service returns an instance of the service you bind to the app namespace, those functions in the return statement are public methods that can be worked with. Basically an Object that contains two methods manipulateData, and getDataById.
It's similar to this
function company() {
let product; // This is private
// Public Methods
return {
setLatestProduct: function(value) {
product = value;
console.log(product, ' set');
},
getLatestProduct: function() {
return product;
}
}
}
const apple = company();
console.log(apple); // { setLatestProduct: function, getLatestProduct: function }

Why object property became undefined when using setInterval

As below code, I make an object named "test", and give it properties and method.
The property came from its argument.
And I try to call the method every 2 sec after onload, and the result shows undefined.
But if I only call the method not using setInterval(), like this
window.onload = function() {
giveword.showWord();
}
I'll be able to show the text "Hi".. Why is that?
var giveword = new test("Hi");
function test(word) {
this.word = word;
}
test.prototype.showWord = function() {
document.getElementById("msg_box").innerHTML = this.word;
}
window.onload = function() {
setInterval(giveword.showWord, 2000);
}
Thanks for help...
The reason is because in your test.prototype.showWord function your this object is referring to the context in which the function is called, which is the window object when called from setInterval.
I think what you want to do is use a closure to make the context of showWord() be the giveword instance like this:
var giveword = new test("Hi");
function test(word) {
this.word = word;
}
test.prototype.showWord = function() {
document.getElementById("msg_box").innerHTML = this.word;
}
window.onload = function(){
setInterval(function(){giveword.showWord();}, 2000); // <<-- here's the closure
}
The difference is that with the closure you're telling the setInterval function to call a function within the context as it was when the setInterval was declared. When setInterval was declared there was a variable in scope called giveword that had a method showWord() that returns the value of your initial input. (Closures are hard to explain, and I'm afraid you'd be best served by someone else explaining them if you need more info.)
This solution this now so easy, use an arrow function in setInterval. Here is an example using setInterval inside of an object method.
const mobile = {
make: 'iPhone',
model: 'X',
battery: 10,
charging: false,
charge: function() {
if(this.battery < 100) {
this.charging = true;
console.info('Battery is charging...');
let interval = setInterval(() => {
this.battery = this.battery + 10;
console.info(mobile.battery);
if( this.battery === 100){
this.charging = false;
clearInterval(interval);
console.info('Battery has finished charging.');
}
}, 100);
}
else {
console.info('Battery does not need charging.');
}
}
}

Jasmine test function that uses a private variable

I'm trying to test one of my functions, but part of it uses a private variable from the controller.
How can I get Jasmine to fake the data from that private variable?
window.MyApp = window.MyApp || {};
(function(myController) {
var deliverablesKoModel;
myController.initialize = function(releaseId) {
// Ajax call with this success:
deliverablesKoModel = new knockOutModel(data); // this model contains an observable array named 'deliverables'
};
myController.checkDeliverableNameIsValid = function (deliverable) {
var valid = false;
if (ko.unwrap(deliverable.name) !== null && ko.unwrap(deliverable.name) !== undefined) {
// PROBLEM HERE
// when running the test deliverablesKoModel below is always undefined!
/////////////
valid = _.all(deliverablesKoModel.deliverables(), function(rel) {
return (ko.unwrap(rel.name).trim().toLowerCase() !== ko.unwrap(deliverable.name).trim().toLowerCase()
|| ko.unwrap(rel.id) === ko.unwrap(deliverable.id));
});
}
deliverable.nameIsValid(valid);
return valid;
};
}(window.MyApp.myController = window.MyApp.myController || {}));
My Jasmine test. I tried having deliverablesKoModel be a global variable but it's always out of scope when hitting the method above.
describe("checkDeliverableNameIsValid should", function () {
var deliverable;
beforeEach(function () {
window['deliverablesKoModel'] = {
deliverables: function() {
return fakeData.DeliverablesViewModel.Deliverables; // this is a json object matching the deliverables in the knockout model
}
};
deliverable = {
id: 1,
name: "test 1",
nameIsValid: function(isValid) {
return isValid;
}
};
});
it("return false if any deliverable already exists with the same name", function () {
var valid = myApp.myController.checkDeliverableNameIsValid(deliverable);
expect(valid).toBe(false);
});
});
deliverablesKoModel is private to code outside of your IIFE.
I am not familiar with knockout, but there are a few ways to set deliverablesKoModel.
Make it a property of your controller that you can set/get.
Make your controller #initialize method accept a callback function which can return an instance of your model. Then, you can send in a function when calling #initialize on your controller in your test.
Example for approach #2 above:
var deliverablesKoModel;
myController.initialize = function(releaseId, modelCallback) {
// Ajax call with this success:
deliverablesKoModel = modelCallback(data); //returns a model
};
Spec:
it("return false if any deliverable already exists with the same name", function () {
var fakeModel = function(data) {
return {
deliverables: function() {
return fakeData.DeliverablesViewModel.Deliverables;
}
}
};
//You didn't initialize your
//controller, which made the "private" variable deliverablesKoModel null in your IIFE
myApp.myController.initialize(relaseId, fakeModel);
var valid = myApp.myController.checkDeliverableNameIsValid(deliverable);
expect(valid).toBe(false);
});

Access Return Object in Javascript

For a project I'm working on, I'm building some data objects with the following lay-out (it's a binary file that I'm reading with ArrayBuffers:
AFile.prototype = {
p: new BufferPack(),
filedata: null,
position: 0,
label_records: null,
closestmultipleof: function(n,v) {
return Math.ceil((v / n) * n);
},
r: function(size) {
result = new Uint8Array(this.filedata,this.position,size);
this.position += size;
return result;
}
readValueLabel: function() {
return {
value: this.rS(8),
len: this.rS8(),
label: this.rS(this.closestmultipleof(8, this.len + 1))
};
},
readLabelRecords: function() {
return {
rec_type: this.rS32(),
label_count: this.rS32(),
value_labels: _.map(_.range(this.label_count), function(num) {
console.debug(num);
},this)
};
},
loadFile: function(blob) {
this.filedata = blob;
this.label_records = this.readLabelRecords();
}
};
However, I seem to have problems with accessing the values in the return scope. In some return scopes, I need to access the variables from the same scope in order to manipulate the data a little bit (see the definition of value_labels).
Only, it doesn't seem to be able to access the variable label_count there (probably because it is in the same return scope). How would I be able to do this?
The only way that I can get it to work is if I do this:
ret = {}
ret['a'] = 5;
ret['b'] = ret['a'] * 2
return ret;
But that seems ugly enough. Any ideas?
And yes, it is a singleton! I'm only going to use this once.
Let me make clear: The problem is within the following code:
return {
a: functionreturn(),
b: this.a * s
};
This.a doesn't seem to exist there.
[update]
You can create a closure to label_count.
function AFile(){};
AFile.prototype ={
readLabelRecords: function() {
label_count=this.rS32();
return {
label_count:label_count,
log:console.log(label_count)//'return from rs32'
};
},
};
AFile.prototype.rS32=function(){
return "return from rs32";
}
var o = new AFile();
o.readLabelRecords();
That answer was based on the code provided, the simplest code to re produce:
function complicatedCalculations(){
return 22;
}
function returnObject(){
var cacheComplicated=complicatedCalculations();//closure variable will
// be available within the entire body of returnObject function
// but never outside of it.
return{
calculated:cacheComplicated,
twiceCalculated:cacheComplicated*2//you could not access calculated
// here so using a cache closure variable
}
}
Or have your returnObject function return a new instance of an object created with a constructor function:
function returnObject(){
return new (function(){
this.calculated=complicatedCalculations();
this.twiceCalculated=this.calculated*2;
})();
}
You forgot a comma before readValueLabel which makes the structure is invalid.
Update:
Too bad that the other answer was deleted, it had a valid point even if it didn't "compile".
Reference to this is problematic inside inner scopes in JS, but it can be worked around by doing something like that:
readLabelRecords: function() {
var that = this;
return {
rec_type: that.rS32(),
label_count: that.rS32(),
value_labels: _.map(_.range(that.label_count), function(num) {
console.debug(num);
},that)
};
}

asp.net ajax property value timestamp is undefined

I have a problem with the value assignment and retrieval in asp.net ajax. The value of timestamp is undefined
Code:
/// <reference name="MicrosoftAjax.js"/>
Type.registerNamespace("LabelTimeExtender1");
LabelTimeExtender1.ClientBehavior1 = function(element) {
LabelTimeExtender1.ClientBehavior1.initializeBase(this, [element]);
this._testelement=this.get_element();
this._timestamp= this.get_element().attributes['TimeStamp'].value;
alert(_timestamp);
},
LabelTimeExtender1.ClientBehavior1.prototype = {
initialize: function() {
LabelTimeExtender1.ClientBehavior1.callBaseMethod(this, 'initialize');
setInterval (this.timer,1000);
alert("after");
},
dispose: function() {
//Add custom dispose actions here
LabelTimeExtender1.ClientBehavior1.callBaseMethod(this, 'dispose');
},
timer: function(){
alert(this.timestamp);
var splitdate=this._timestamp.split(/[:]+/);
alert(splitdate);
var date= new Date(this._timestamp);
alert( date.toString());
var datenow= new Date ();
alert(datenow.toString());
this._element.innerText=" ";
alert(this._element);
if(date.getUTCFullYear<datenow.getUTCFullYear)
{
alert("year");
var myelement= this.get_element();
myelement .innerHTML= date.getUTCFullYear.toString();
}
if(date.getUTCMonth<datenow.getUTCMonth)
{
alert("month");
this.get_element().innerHTML=date.getUTCMonth.toString();
}
if(date.getUTCDay<datenow.getUTCDay)
{
this.get_element().innerHTML=date.getUTCDay.toString();
}
if(date.getUTCHours <datenow.getUTCHours )
{
this.get_element().innerHTML=date.getUTCHours .toString();
}
if(date.getUTCMinutes<datenow.getUTCMinutes)
{
this.get_element().innerHTML=date.getUTCMinutes.toString();
}
},
set_timestamp: function(value)
{
this._timestamp=value;
},
get_timestamp: function()
{
return this._timestamp;
}
}
LabelTimeExtender1.ClientBehavior1.registerClass('LabelTimeExtender1.ClientBehavior1', Sys.UI.Behavior);
if (typeof(Sys) !== 'undefined') Sys.Application.notifyScriptLoaded();
Why is the value of _timestamp undefined?
I would suggest moving the code which sets this._timestamp into your initialize function.
My other suggestion is to use the getters and setters even within your own code to ensure encapsulation. So, the alerts would actually be alert(this.get_timestamp()). And, in your initialize function, you would call this.set_timestamp(this.get_element().attributes['TimeStamp'].value).
Thanks to the comment I see the problem is actually in the setInterval call. When you call window.setInterval(this.timer, 1000);, when the timer function is called this refers to window, not to your object. So instead, do something like this:
var self = this;
window.setInterval(function () {
self.timer();
}, 1000);
That will make this inside of timer() refer to the correct object.

Categories

Resources