Why would "this" in function inside angularjs service be undefined - javascript

Why would this inside function be undefined in angularjs service?
.service('SliceService', function () {
var self = this;
var Slice = function(intervals, intervalSpan) {
self.activeSlice = [];
self.hasNext = true;
self.hasPrevious = false;
self.intervals = intervals;
self.intervalSpan = intervalSpan;
}
Slice.prototype.findIntervalIndex = function (time, slice) {
slice = slice || self.intervals;
return _.findIndex(slice, function (o) {
return o.time === time;
});
};
return Slice;
})
.controller('myController', ['SliceService', function(SliceService) {
SliceService([arr], 12);
SliceService.findINtervalIndex(time);
}])
In the above example when using it in a controller, this.activeSlice throws an error TypeError: Cannot set property 'activeSlice' of undefined.
-
Update
Thanks, everyone! I've updated my example to better reflect what I'm trying to do. With the above I'm getting a TypeError: SliceService.findIntervalIndex is not a function — Also maybe a service is not fit for what I'm trying to do?

Try saving the value of "this" before accessing it inside the anonymous scope:
(function(){
'use strict';
angular.module('myServices').service('SliceService', function () {
var context = this;
var Slice = function(intervals, intervalSpan) {
context.activeSlice = [];
context.hasNext = true;
context.hasPrevious = false;
context.intervals = intervals;
context.intervalSpan = intervalSpan;
}
return Slice;
});
}());
Using Bind:
angular.module('myServices').service('SliceService', function () {
var Slice = function(intervals, intervalSpan) {
this.activeSlice = [];
this.hasNext = true;
this.hasPrevious = false;
this.intervals = intervals;
this.intervalSpan = intervalSpan;
}.bind(this);
return Slice;
});
Note:
using arrow function of javascript ES6 makes sure that this always points to the same context. so you could replace regular function with arrow function. This is however not universally supported without transpiling.
service('SliceService', ()=>{
// operations
}

Thanks to #SeedyROM and some additional google searches on angular services. This solved all my issues...
angular.module('vpower.services').service('SliceService', function () {
this.activeSlice = [];
this.hasNext = true;
this.hasPrevious = false;
this.intervals = [];
this.intervalSpan = 12;
this.findIntervalIndex = function (time, slice) {
var curTime;
slice = slice || this.intervals;
return _.findIndex(slice, function (o) {
curTime = o.time._i || o.time;
return curTime === time;
});
};
I think I was not fully understanding the way services work.

Related

how to properly call functions in prototype in js

How do I properly call the functions inside pretest?
I get this error: Uncaught TypeError: b.testmenow is not a function
var pretest = function () {
var MAX_NUM = 250.0;
var prebase = function (NEW_NUM) {
this.NEW_NUM = NEW_NUM ? NEW_NUM : true;
};
prebase.prototype.testmenow = function () {
return this.NEW_NUM;
};
return prebase;
};
var b = new pretest(111);
console.log(b.testmenow());
You need to accept your input into new pretest(111) by adding n.
And then you must instantiate your prebase constructor using n.
var pretest = function (n) {
var MAX_NUM = 250.0;
var prebase = function (NEW_NUM) {
this.NEW_NUM = NEW_NUM ? NEW_NUM : true;
};
prebase.prototype.testmenow = function () {
return this.NEW_NUM;
};
return new prebase(n);
};
var b = pretest(111);
console.log(b.testmenow());
It is strange that you have two constructors here, you can surely do this with one.
As Felix has deftly mentioned, you can call pretest(111) instead of new pretest(111).

Javascript accessing parent function variable

hi I have a Question about accessing variables that are in a parent function
var DateRangePicker = function (name, clickFunction) {
this.context = name;
this.UpdateGraph = clickFunction;
this.FinalDate = function () {
var Dates = $(this.context).find("[name=datepickerText]").val().split('-');
return Dates[1];
};
this.InitialDate = function () {
var Dates = $(this.context).find("[name=datepickerText]").val().split('- ');
return Dates[0];
};
$(this.context).find("[name=UpdateDatepicker]").click(function () {
var pickerText = $(InnerContext).find('[name=datepickerText]');
var dates = pickerText.val().split('-');
UpdateGraph(InitialDate(), FinalDate());
$(context).find("[name=Toogler]").click();
});
return this;
}
How can i access the "this.UpdateGraph()" function inside the updateDatepicker click so far it sais that UpdateGraph and this.UpdateGraph doesnt exists
You can bind the this context to your handler function, to keep from having an extra scope variable:
$(this.context).find("[name=UpdateDatepicker]").click(function () {
var pickerText = $(this.InnerContext).find('[name=datepickerText]');
var dates = pickerText.val().split('-');
this.UpdateGraph(this.InitialDate(), this.FinalDate());
$(this.context).find("[name=Toogler]").click();
}.bind(this));

JavaScript: Prevent Array.push()

I have a sealed object with an array member on which I want to prevent direct pushes.
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d; }
});
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // pushed = sadness
How can I prevent the push?
UPDATE:
Thanks for all the thoughts. I eventually need the JSON to send to the server. It looks like I might need to use an object for the array then figure out a way to generate and return the JSON needed, or change _something to use .slice(). Will play and report.
you could override the push method:
var _d = [];
_d.__proto__.push = function() { return this.length; }
and when you need to use it in your module, call Array.prototype.push:
_b.addD = function (newD) {
Array.prototype.push.call(_d, newD);
};
I haven't done any performance tests on this, but this certainly helps to protect your array.
(function(undefined) {
var protectedArrays = [];
protectArray = function protectArray(arr) {
protectedArrays.push(arr);
return getPrivateUpdater(arr);
}
var isProtected = function(arr) {
return protectedArrays.indexOf(arr)>-1;
}
var getPrivateUpdater = function(arr) {
var ret = {};
Object.keys(funcBackups).forEach(function(funcName) {
ret[funcName] = funcBackups[funcName].bind(arr);
});
return ret;
}
var returnsNewArray = ['Array.prototype.splice'];
var returnsOriginalArray = ['Array.prototype.fill','Array.prototype.reverse','Array.prototype.copyWithin','Array.prototype.sort'];
var returnsLength = ['Array.prototype.push','Array.prototype.unshift'];
var returnsValue = ['Array.prototype.shift','Array.prototype.pop'];
var funcBackups = {};
overwriteFuncs(returnsNewArray, function() { return []; });
overwriteFuncs(returnsOriginalArray, function() { return this; });
overwriteFuncs(returnsLength, function() { return this.length; });
overwriteFuncs(returnsValue, function() { return undefined; });
function overwriteFuncs(funcs, ret) {
for(var i=0,c=funcs.length;i<c;i++)
{
var func = funcs[i];
var funcParts = func.split('.');
var obj = window;
for(var j=0,l=funcParts.length;j<l;j++)
{
(function() {
var part = funcParts[j];
if(j!=l-1) obj = obj[part];
else if(typeof obj[part] === "function")
{
var funcBk = obj[part];
funcBackups[funcBk.name] = funcBk;
obj[part] = renameFunction(funcBk.name, function() {
if(isProtected(this)) return ret.apply(this, arguments);
else return funcBk.apply(this,arguments);
});
}
})();
}
}
}
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
})();
You would use it like so:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal
This way, you can internally keep a copy of the interface that isn't made global to allow your helper funcs to modify the array as normal, but any attempt to use .push .splice etc will fail, either directly, or using the .bind(myArr,arg) method.
It's still not completely watertight, but a pretty good protector. You could potentially use the Object.defineProperty method to generate protected properties for the first 900 indexes, but I'm not sure of the implications of this. There is also the method Object.preventExtensions() but I'm unaware of a way to undo this effect when you need to change it yourself
Thank you, dandavis!
I used the slice method:
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d.slice(); } // UPDATED
});
_b.updateC = function (newValue) {
_c = newValue;
};
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // no more update = happiness
This allows me to protect from direct push calls enforcing some logic.

JS module pattern override function

I have following pattern
BASE = function () {
var that = {};
var number = 10;
that.showNumber = function(){
that.alertNumber();
}
that.alertNumber = function () {
alert(number);
};
return that;
};
CHILD = function () {
var that = Object.create(BASE());
var secondNumber = 20;
// Override base function
that.alertNumber = function () {
alert(secondNumber);
};
return that;
};
var ch = CHILD();
ch.showNumber();
Can you tell me how can I adjust my module pattern inspired by Douglas CrockFord to fully override alerNumber function? So far showNumber function displays 10 instead of 20.
Thank you all in advanced
JSFiddle with code is here
You could change
that.showNumber = function(){
that.alertNumber();
}
to
that.showNumber = function(){
this.alertNumber();
}
But I'm not sure I see why you don't simply use the prototype-base inheritance model.

Javascript behaviour reuse: What side effects will this approach have?

I'm trying to understand pure prototype-based JavaScript and one specific thing I'm struggling with is reuse (inheritance).
For my project I landed this way of creating objects that can be reused.
// very generic prototype
var Apparatus = (function(){
var self = Object.create({});
self.state = false;
self.on = function() { this.state = true; };
return self;
})();
// more specific prototype
var Radio = (function(){
var self = Object.create(Apparatus);
self.frequency = 0;
self.setFrequency = function(f) { this.frequency = f; }
self.getFrequency = function() { return this.frequency; }
return self;
})();
I then want to "instantiate"/copy the Radio object, creating two different radios.
var kitchenRadio = Object.create(Radio);
kitchenRadio.state = false;
kitchenRadio.on();
var carRadio = Object.create(Radio);
carRadio.state = false;
console.log(kitchenRadio.state, carRadio.state);
// true false
This works, but will it continue to? Can anyone predict any unwanted outcomes?
Like #pimvdb said, remove state and this works well.
// very generic prototype
var Apparatus = (function(){
var self = Object.create({});
self.on = function() { this.state = true; };
return self;
})();
// more specific prototype
var Radio = (function(){
var self = Object.create(Apparatus);
self.setFrequency = function(f) { this.frequency = f; }
self.getFrequency = function() { return this.frequency; }
return self;
})();
I then use Object.create(Object, params) to instantiate it.

Categories