I have a event handler in my AngularJS directive:
angular.element($window).on("wheel", onScrollAction);
Before onScrollAction in my directive I have defined some variables, outside of the onScrollAction function itself because I don't want them assigned on every wheel event, as they shouldn't change.
app.directive('scroll', function ($window) {
return function(scope, element, attrs) {
var elem = angular.element(document.querySelectorAll('.titletitle')).eq(1);
var elemHeight = elem[0].scrollHeight;
//so on until the 5th element
//then object to store all the elements and their heights:
var theObject = [{el:elem,elH:elemHeight},{el:elem2,elH:elem2Height},{el:elem3,elH:elem3Height},{el:elem4,elH:elem4Height},{el:elem5,elH:elem5Height}]
var theActiveElem = theObject[0];
var onScrollAction = function (event) {
console.log(theActiveElem) //renders undefined
console.log(elem) // renders the element
My question is, how come the elem is fine going from a global scope to a function scope, when theActiveElem is not and how do I fix it so I can do actions on theActiveElem in my event handler.
Thank you.
This is really weird to me, would like an explanation...
My console log inside the event handler looked like:
console.log(theActiveElem,theObject); //theActiveElement undefined
thepatch = Math.floor(theoffset/theActiveElem.elH)
if(thepatch==1){
var theActiveElem = theObject[thepatch];
console.log(theActiveElem);
}
But as soon as I changed the var theActiveElem = theObject[thepatch]; to theActiveElem = theObject[thepatch]; it fixed.
I recognize that I shouldn't have declared it with var on that line, but why would that cause an error in the log a few lines up?
Anyway, this is resolved now.
Related
I have a function that creates a new record in the database and returns the ID of the record created. From this I need to assign a function to a select with the value of the returned ID.
.done(function(response) {
//console.log(siblings[1].dataset.contno);
var dbResponse = JSON.parse(response);
document.getElementById(runID).setAttribute('data-runid', dbResponse.id);
var newRunID = dbResponse.id;
var driverSelectID='driverSelectRun'+runCode;
//adding the onchange function with the correct ID to the dropdowns (the assignVehicle FUnction takes the runID which is unknown untill response)
(function(newRunID) {
document.getElementById(driverSelectID).onchange = function () {
assignDriver(newRunID);
}
})(newRunID);
(function(newRunID) {
document.getElementById(vehicleSelectID).onchange = function () {
assignVehicle(newRunID);
}
})(newRunID);
console.log(newRunID);
});
The console.log for the newRunID is 1566 but the onchange function of this select does not contain the new run id it simply shows as assignVehicle(newRunID) instead of actually using the value returned from the database (assignVehicle(1566)). I have used the exact same method on another part of the code which works fine. Can anyone see why this is not working correctly.
Thanks in advance for any replies!
<select id="driverSelectRun6">...</select>
That is the code for the select. It is definately being targeted correctly as the function is being set just without the arguement.
UPDATE
This was a scope issue. The newRunID was declared using var newRunID= but this was delcared in the .done function so was of local scope instead of global. removing the var to make it just newRunID= worked because assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object)
The issue here is you are redefining the variable newRunID as an argument and that argument is actually the event object that is returned from the change event listener.
.onchange = function (newRunID) {
should be
.onchange = function () {
(function(newRunID) {
document.getElementById(driverSelectID).onchange = function () {
assignDriver(newRunID);
}
})(newRunID);
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
the following code works perfect of Firefox but crashes on Chrome, with the following error: Uncaught TypeError: Property 'pos' of object [object Object] is not a function
Here is the code, with comments:
var CantidadMenu = $('div[class^=container_menu_]').length;
var position = $("#menu_unidades").position();
var IzAdd = 0;
var w = $("#menu_unidades").width();
var h = $("#menu_unidades").height();
for (i=0;i<CantidadMenu;i++){
var pos = 'pos'+(i+1); //I create a variable that will hold a string like: pos1,pos2...
IzAdd = IzAdd+25;
function pos(div){ //on this line I use the variable I created, which crashes on Chrome
var estilo1 = $(div).css({'left':IzAdd+25,'top':position.top+(IzAdd-25)});
return estilo1;
}
pos('.container_menu_'+(i+1));
$('.container_menu_'+(i+1)).css({'z-index':297+i,'width':w,'height':h});
}
Here you define a function named pos:
function pos(div){ //on this line I use the variable I created, which crashes on Chrome
var estilo1 = $(div).css({'left':IzAdd+25,'top':position.top+(IzAdd-25)});
return estilo1;
}
console.log(pos) // function ....
Here you overwrite it with a string:
var pos = 'pos'+(i+1);
console.log(pos) // string....
You should name either the function or the string to something else.
PS: I know that in your code the order is reversed, but function declarations are hoisted to the top of the scope, so the JS interpreter "sees" them in the order i wrote them in: first function, then the string.
PSS: The crash is actually on this line:
pos('.container_menu_'+(i+1));
function pos(div) is the same as var pos = function(div)... (except the former is defined at the parse-time, and the latter at the run-time, but that's irrelevant for your code), so if you expected by defining that pos = 'pos1';, for example, you'd get function pos(div) to become function pos1(div), it won't.
It will just overwrite the pos variable, and it will no longer be a string, but a function.
To fix your code, write a single function at the top of your code, outside of the for loop, add another parameter to it (IzAdd) and make sure you fix the function calls appropriately.
The function should look something like this:
function pos(div, IzAdd){
return $(div).css({'left':IzAdd+25,'top':position.top+(IzAdd-25)});
}
The following script works correctly although I need to make few amends. In each function I am getting the values need for the different formulas. However I tend to replicate the same line of code in different functions.
Ex.
function one(){ var v1= document.getElementById('one').value; }
function two(){ var v1= document.getElementById('one').value; }
Full code
I would like to declare all of the variables once and than only use the ones I need for the specific functions. If I declare them right at the top than once they are called they still hold the original value so I need to update that value to the current one if changed of course.
Your code will be very hard to read if you do it like in your fiddle.
Instead do
var myVars;
window.onload=function() {
myVars = {
'list_price': document.getElementById('list_price'),
'negotiated': document.getElementById('negotiated'),
.
.
'lease_payment': document.getElementById('lease_payment')
}
now you can do
var price = myVars.list_price.value;
or perhaps add a function
function getVal(id) {
var val = document.getElementById(id).value;
if (val =="" || isNaN(val)) return 0;
return parsetInt(val,10);
}
now you can do
var price = getVal("list_price");
mplungjan's solution is a great one. If you're at all concerned by your global vars leaking into the window scope, wrap your code in an Immediately Invoked Function Expression to prevent that from happening:
(function(){
// code goes here
}());
There are two ways to go about this:
Update your variable when the value changes
Use a function that always returns the correct value
1) You can add a listener for the change event or the keyup event that changes your global variable:
// save initial value
var val = document.getElementById('one').value;
// update the value when input is changed
addEventListener(document.getElementById('one'), 'change', function() {
val = document.getElementById('one').value;
});
console.log(val);
2) You can use a function that always returns the current value:
var val = function() { return document.getElementById('one').value; };
console.log(val());
2b) If you hate parenthesis, you can define a property that uses the function above as a getter:
Object.defineProperty(window, 'one', {
get : function() { return document.getElementById('one').value; }
});
console.log(one);
I have the following problem:
I have a function
workspace.func = function() {console.log(5);}
I attach it as an event handler:
$(workspace).bind("ping", workspace.func);
Then, I change the function definition:
var cF = workspace.func;
workspace.func = function() {
...
cf.call(this);
}
but
$(workspace).trigger("ping")
>>5
How can I properly wrap the function at runtime, so that the handler points to the changed one as well?
You can do it like this:
workspace.func = function() {console.log(5);}
$(workspace).bind("ping", function() {workspace.func()});
var cF = workspace.func;
workspace.func = function() {
...
cf.call(this);
}
After reassigning the value of workspace.func, the ping event handler will go to the new function because it gets the function pointer from the variable and then executes it so if you change which function that variable points to, it will pick up the new value - unlike your original version which had a reference to the actual function so changing the workspace.func variable didn't do anything.