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

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

Related

Not able to access a variable

The variable i am using becomes undefined after a certain point. Can someone help me in understanding what is happening.
The below code is a protractor code.
this.searchBy = element(by.model('searchCompanyComponent.searchByValue'));
this.clickTheProvidedValueInSearchByDropdown = function (selectedItem) {
var x = this.searchBy;
this.searchBy.all(by.tagName('option')).filter(function (elem, index) {
return elem.getText().then(function (text) {
return text.toUpperCase().replace(/ |-/g, '') === selectedItem.toUpperCase().replace(/ |-/g, '');
});
}).getText().then(function (text) {
console.info(x); // 1
console.log(this.searchBy); // 2
});
};
console.log(this.searchBy); //3
The console log at 1 and 3 shows the locator object, but console log at 2 shows as undefined.
What is the reason behind this unexpected behavior?
In JavaScript, this can mean a lot of different things depending on the context in which you are referencing it.
When you are saying console.log(this.searchBy); // 2 you are in the context of the anonymous function you passed to getText, which has no searchBy property. You will either need to bind this function to the context of your page object or use the stored reference to searchBy in x
It may be helpful to review this mdn article

Javascript Revealing Module Pattern in AngularJS Service not working

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,
}
});

Pass var to angular $resource success function

I've been going crazy over this and I think the answer is probably out there but I don't know the right way to ask Google the question.
Essentially I need a way to make a $resource call, and pass in some data that I want to then use in the success function.
app.controller('VariantListController', ['djResource', function(djResource){
var Variants = djResource('/ship-builder/variants/?format=json');
var Vehicle = djResource('/ship-builder/vehicles/:id', {id: '#id'});
this.variants = Variants.query(function(variants){
$(variants).each(function(){
console.log(this);
variantData = this;
var vehicleData = Vehicle.get({id:this.baseVehicle}, function(){
console.log(variantData);
})
})
});
}]);
In the above example, in the innermost success function, 'variantData' is always the value of the LAST entry from the previous level. This makes sense because the value was set by the last item in the array long before the success happens. I need a way though to have the value of the 'variantData' that was inexistince when the Vehicle.get() was called.
Does that make sense? I find it very hard to explain the issue.
You need to create a closure to make it work. Something like
this.variants = Variants.query(function(variants){
$(variants).each(function(){
getVehicleData(this);
})
});
function getVehicalData(variantData) {
var vehicleData = Vehicle.get({id:variantData.vehicleId}, function(){
console.log(variantData);
})
}
I am by no means an expert on the $resource service, but perhaps using the $promise.then method instead of the success callback would work.
$(variants).each(function(){
console.log(this);
variantData = this;
Vehicle.get({id:this.baseVehicle}).$promise.then(function() {
console.log(variantData);
});
});
Since the value in variantData may change before the success callback is actually called, you want to ensure the the callback has the original value stored.
var vehicleData = Vehicle.get({id:this.baseVehicle}, function(vData){
return function() {
console.log(vData);
}
}(variantData));
The above will create a new function with variantData stored in a closure.

Changing the state of a toggle in JavaScript/jQuery

Is it possible to change the state of a toggle function? Like:
myDiv.toggle ... function 1 , function 2
I click on the myDiv element, the function 1 executes
I click again, function 2
I click again, function 1
BUT
Change the state
function 1 again
etc.
But I need to be able to change the state from outside the toggle function.
Here is a javascript object that uses closure to track it's state and toggle:
var TOGGLER = function() {
var _state = true;
var _msg = "function1";
var function1 = function() {
_msg = "function1";
}
var function2 = function() {
_msg = "function2";
}
return {
toggle: (function () {
_state = !_state;
if (_state) {
function1();
} else {
function2();
}
return _msg;
})
}
}();
Here is a jsfiddle that shows how to use it to toggle based with the following jquery: http://jsfiddle.net/yjPKH/5/
$(document).ready(function() {
$("#search").click(function() {
var message = TOGGLER.toggle();
$("#state").text(message);
});
});
The toggle function is meant for simple use cases. Changing the state externally is not "simple" anymore.
You cannot easily/safely (it's internal so it may change during minor versions) access the state variable of the toggle function easily as it's stored in the internal dataset of the element.
If you really want to do it, you can try this code though:
$._data(ELEMENT, "lastToggle" + func.guid, 0);
func is the function you passed to .toggle(), so you need to save this function in a variable. Here's a minimal example: http://jsfiddle.net/xqgrP/
However, since inside the function there's a var guid = fn.guid || jQuery.guid++ statement, I somehow think that the devs actually meant to use guid instead of func.guid for the _data key - in that case a minor update is very likely to break things. And after the fix you'd have to iterate over the data set to retrieve the correct key as there is no way to access the guid from outside.

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