Javascript Revealing Module Pattern in AngularJS Service not working - javascript

I'm using the following code in my angularJS service to get some task done :
angular.factory('promiseFactory', function(){
var artistIds = [];
function setArtistIds(artistIds){
artistIds = artistIds;
}
return {
createPromiseForNotification: promiseFactory,
getNotis: getNotis,
setNotis : setNotis,
//setArtistIds : setArtistIds,
artistIds : artistIds
}
});
This factory is used in another factory notifications.js wherein I'm trying to set
promiseFactory.artistIds = [1,2,3];
on some ajax call but its not working, when I use the artistIds variable in any of the functions of my promiseFactory, it turns out to be blank array [] (the initial value). Why?
Ok, Secondly, this thing works when I use a function called setArtistIds to implement the same thing but even then I have to do something like
function setArtistIds(i){ // Right
artistIds = i;
}
But not when I do it like this :
function setArtistIds(artistIds){ // Wrong
artistIds = artistIds;
}
Can someone please explain me what wrong I'm doing.

When you are executing this line of code:
promiseFactory.artistIds = [1,2,3];
You are only changing property of the object returned by your factory.
But all your methods not even using it, they are using variable artistIds in the closure.
In order to fix this error, add getter and setter to your factory.
When you are naming parameter of the setter function the same way as your closure variable, you are hiding it. That's why it was not working.
Just give it another name.
angular.factory('promiseFactory', function(){
var artistIds = [];
function setArtistIds(newArtistIds){
artistIds = newArtistIds;
}
function getArtistIds(){
return artistIds;
}
return {
createPromiseForNotification: promiseFactory,
getNotis: getNotis,
setNotis : setNotis,
setArtistIds : setArtistIds,
getArtistIds : getArtistIds,
}
});

Related

Angular Scope issue -> function comes off scope after one use?

Here is the relevant snippet of code:
$scope.newLike = LikeFactory.newLike;
$scope.newDislike = LikeFactory.newDislike;
$scope.updateLike = LikeFactory.updateLike;
$scope.updateDislike = LikeFactory.updateDislike;
$scope.vote = function(sockId, nnew, update) {
if (!$scope.verifyUser) $scope.alert("Please log in to like a sock!");
if (!$scope.like.like && !$scope.like.dislike) {
return nnew(sockId).then(function(vote) { $scope.vote = vote; });
} else {
return update(sockId).then(function(update) { $scope.vote = update; });
}
}
I call this function, $scope.vote, in the html with an ng-click="vote(sock.id, newLike, updateLike)" or ng-click="vote(sock.id, newDisike, updateDislike)" whether on an like vs dislike button. The call button works fine when first liking and updating once there is an instance of a 'like' for a particular unique sock/user combo but after one 'update' I get the error:
angular.js:13642 TypeError: v2.vote is not a function
Do I need to trigger a $digest for the function to continue to be in $scope? Does it somehow come off $scope after being used? It seems like a strange error to me.
Edit: duh! It's late, thanks for the answers!
You define $scope.vote as a function in your controller. After first invocation you assign a result that may not be a function to this variable, thus vote is no longer a function:
$scope.vote = function() {} // => 'vote' variable is holding a function
$scope.vote = vote / update // => 'vote' might not reference a function but a value
Log your result after the promise is resolved (in the then block), to understand what is the new assigned value.
It's normal, here : $scope.vote = update you use the same varaible that the function name
The issue must be with the following statement:
$scope.vote = vote;
The vote might not be function and so v2.vote is not a function

Setting "this" to the instance, in a callback set during the creation of a prototype function

I have this code:
var createAllAreSelectedClickedHandler = function(selectablesArrayGetter) {
return function() {
var array = selectablesArrayGetter();
var desiredState = array.every(function(selectable) { return selectable.selected; }) ? false : true;
array.forEach(function(selectable) {
selectable.selected = desiredState;
});
};
};
Followed by this one:
function PromoViewModel() { this.registrations = [...] }
PromoViewModel.prototype.allEventsSelectedClickedHandler = createAllAreSelectedClickedHandler(function() { return this.registrations; }));
I can't manage to set the correct value of this. The "this" value when the function is created points to Window so I can't do .bind(this). I've tried doing .bind(PromoViewModel.prototype) but it lacks all the precious instance fields set inside the constructor.
I know I could simply set this.allEventsSelectedClickedHandler in the constructor function, but I'm trying to separate the methods creation from the variables.
The problem is the call selectablesArrayGetter(); which determines the this value for the callback.
You will need to "pass" the this value that the method (i.e. the closure you are returning) is invoked on, using call:
var array = selectablesArrayGetter.call(this);
I'd recommend defining your PromoViewModel.prototype.allEventsSelectedClickedHandler method as follows:
PromoViewModel.prototype.allEventsSelectedClickedHandler = function() {
var _array = this.registrations;
var desiredState = _array.every(function(selectable) { return selectable.selected; }) ? false : true;
_array.forEach(function(selectable) {
selectable.selected = desiredState;
});
};
the function that you're passing as callback uses this, but doesn't have the PromoViewModel context. You can ensure the method has the proper context by binding this to a variable.
function PromoViewModel()
{
var me = this;
this.registrations = [...];
this.allEventsSelectedClickedHandler = createAllAreSelectedClickedHandler(function() {
return me.registrations;
});
}
Working fiddle: http://jsfiddle.net/michaschwab/coegnL5j/9/ also has Bergi's answer in there (commented out) to show that that works just as well.
Ok here is what I did.
In the prototype definition instead of directly associating it to createAllAreSelectedClickedHandler function, I actually define a function that returns the createAllAreSelectedClickedHandler function. By doing this, I can define a variable (in this case protoScope) that maps this context when defined.
When doing that, if you put a break-point in the createAllAreSelectedClickedHandler function you will see that the selectablesArrayGetter value is correct (the acutal registrations array).
PromoViewModel.prototype.allEventsSelectedClickedHandler = function (){
var protoScope = this;
return createAllAreSelectedClickedHandler(function() {
return protoScope.registrations;
});
}

Get the name of a method stored in a variable

I have some trouble with getting the name of a method stored in a variable... Here is an exemple of what I want :
Function MyObject(){
this.actualMethod = this.thatName;
}
MyObject.prototype.thatName = function(){}
MyObject.prototype.getActualMethodName = function(){
return this.actualMethod.name; /* This doesn't work since the function itself is anonymous, so this.actualMethod.name doesn't work... I want it to return "thatName" */
}
I tried to navigate through the prototype with my console, in vain... Is there a way to do this ?
You need to name the function:
MyObject.prototype.thatName = function thatName() {};
Or, as you mentioned, you can find its name in the prototype (but I wouldn't suggest you to do it):
for (var key in MyObject.prototype) {
if (MyObject.prototype[key] === this.actualMethod) {
return key;
}
}
But why do you need this? Maybe there could be a better solution.

Need some help understanding basics about JS module pattern

I am trying to organize my code using the revealing module pattern.
I have a very basic question about how to set up a setter method.
$(document).ready(function() {
var designs = (function() {
var curRow,
setCurRow = function(val) {
curRow = val;
},
initTable = function() {
setCurRow(0);
};
return {
curRow : curRow,
setCurRow : setCurRow,
initTable : initTable
}
}) ();
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.curRow);
});
The problem is that i dont get the someNewVal in the console output, I get undefined instead! I have a feeling I am doing something pretty silly here.
You can also solve this in another way by understanding the scopes of the variables and functions involved.
When you return your object constructor { curRow: curRow ... }, that just initializes the object member named curRow to the value of the variable curRow in the scope of the anonymous function; it doesn't create any persistent connection between them.
Once the anonymous function returns, calling designs.setCurRow is updating the curRow variable in that scope exactly as you expect, but that variable is now totally inaccessible to the outside world -- there is no connection between it and the curRow member of designs.
You can solve this by making the setCurRow method operate on this.curRow, as in the other solutions. In that case you don't need to make curRow a variable in the original scope, since it's entirely unused. The other solution is to add a 'getter' method to your current one:
var designs = (function() {
var curRow,
setCurRow = function(val) {
curRow = val;
},
getCurRow = function() {
return curRow;
},
initTable = function() {
setCurRow(0);
};
return {
getCurRow : getCurRow,
setCurRow : setCurRow,
initTable : initTable
};
}) ();
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.getCurRow());
Because getCurRow and setCurRow are functions that are closed in the scope containing the variable varRow, they can reach back into that scope and access and change variables that are only accessible within it.
In this case making curRow a member of the object you return is probably simpler, but the other way is useful too since you can use it to create effectively private members and methods.
Looks like you want an object, not a module:
$(document).ready(function() {
var designs = {
setCurRow: function(val) {
this.curRow = val;
},
initTable: function() {
this.setCurRow(0);
},
curRow: 0
};
designs.initTable();
designs.setCurRow(someNewVal);
console.log(designs.curRow);
});
The problem is that setCurRow sets the value of the variable curRow after designs.curRow has already been set. Consider something like this:
var a = 1;
b = a; // sets b = a = 1
b = 2; // sets b = 2; leaves a = 1
Your code is doing the same thing, but with object-properties and setter methods to make it look complicated. :-)
As ruakh pointed out, you never re-assign curRow on the returned object, so it is always the default value. Change it to:
setCurRow = function(val) {
this.curRow = curRow = val;
},
And everything should work*.
* At least mostly - you won't be able to use call and apply on setCurRow (or pass it to setTimeout or setInterval without binding it first to your object (designs), since this is bound at call time in JavaScript.

Change var in object literal function

Hi guys I am writing some code using the object literal pattern, I have function that returns a value:
'currentLocation': function() {
var cL = 0;
return cL;
},
I then need to update the variable 'cL' from another function like this:
teamStatus.currentLocation() = teamStatus.currentLocation() + teamStatus.scrollDistance();
This part is part of another function - however I get an error back stating: invalid assignment left-hand side
I am guessing I can not update the variable in this way, could anyone suggest a better method or point me in the right direction.
Any help would be greatly appreciated.
Going to add more code to highlight what I am trying to do:
'currentLocation': function() {
var cL = 0;
return cL;
},
'increaseTable': function() {
if (teamStatus.currentLocation() <= teamStatus.teamStatusTableHeight() ) {
teamStatus.currentLocation = teamStatus.currentLocation() + teamStatus.scrollDistance();
$("#tableTrackActual").animate({scrollTop: (teamStatus.currentLocation)});
$("#tableMembers").animate({scrollTop: (teamStatus.currentLocation) });
//console.log(teamStatus.currentLocation());
teamStatus.buttonRevealer();
}
}
As you can see increaseTable should update the value of currentLocation - help this sheds more light on what I am trying to achieve.
You're writing teamStatus.currentLocation() =, which calls the function teamStatus.currentLocation and tries to assign to the return value. That isn't valid. You want just teamStatus.currentLocation = — no function call.
The variable inside your function is completely private to that function (and any functions defined within it). If you need to create a number of functions that share a set of private variables, you can do that with a closure. For instance:
var Thing = (function() {
var thingWideData;
function getData() {
return thingWideData;
}
function setData(newData) {
thingWideData = newData;
}
return {
getData: getData,
setData: setData
};
})();
What that does is create a Thing object which has getData and setData functions available for it, which get and set the completely private thingWideData variable contained by the anonymous closure. More about this pattern here and here, although the latter of those is more about private methods than private data.
What your code produces is:
0 = 0 + <some number>
Which variable do you want to update? cL? You are declaring it in the function, you cannot assign a value to it from outside. Depending on the rest of your code, you might be better off with getters and setters:
var object = {
_cL = 0,
get currentLocation() {
return this._cL;
},
set currentLocation(value) {
this._cL = value;
}
}
then you can do:
teamStatus.currentLocation = teamStatus.currentLocation + teamStatus.scrollDistance();
Update:
Regarding IE: If currentLocation should actually be just a number, it might be sufficient to just declare it as property:
var obj = {
currentLocation: 0
}

Categories