Properly wrapping functions in JavaScript - javascript

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.

Related

Function not being set correctly

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

JavaScript - AngularJS Scope Issue: Object in the Global Scope Undefined in Function

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.

JavaScript: TypeError: xyz is not a function when calling the function

I am trying to come up with a page on which, when user clicks a file button on the page, I try to execute the JS on the page. And I am trying to use OOP / class so hopefully it can be reused later. Here is my test code:
// This is the "class".
function BearUpload() {
// some values will go here...
}
// Add a few functions
BearUpload.prototype.function1 = function () {
console.log("function1 called");
}
BearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
var myBear = new BearUpload(); // Create a global variable for the test
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(myBear.handleFileSelect);
}
});
However, it gets error like:
TypeError: this.function1 is not a function
this.function1();
Any idea about this?
Thanks!
Bind myBear to your change eventListener
In general when you access this from handleFileSelect, this refers to the html element.
i.e. this = <input type="file" id="my-file-select-button">
$("#my-file-select-button").change(myBear.handleFileSelect.bind(myBear));
The bind() method creates a new function that, when called, has its
this keyword set to the provided value, with a given sequence of
arguments preceding any provided when the new function is called.
MDN doc
You are trying to call function1 on DOM object but you have to call on jQuery object
$(this).function1();
That's because when bound as a handler to jQuery events, this would refer to the element on which the event is triggered.
I would rather change your code like this
// Create only one global variable for your app
var APP = {};
// Create class using immediate function/closure
APP.BearUpload = (function(){
//declare private variables here
// Constructor
var bearUpload = function() {
// some values will go here...
}
// Add a few functions
bearUpload.prototype.function1 = function () {
console.log("function1 called");
}
bearUpload.prototype.handleFileSelect = function (evt) {
console.log("handleFileSelect called");
this.function1();
}
return bearUpload;
}());
APP.myBear = new APP.BearUpload();
$(document).ready(function () {
var some_condition_goes_here = true;
if (some_condition_goes_here) {
$("#my-file-select-button").change(function(e){
// do something with event 'e'
APP.myBear.handleFileSelect.call(APP.myBear, e);
});
}
});
do not use "this", it is confusing some time.
BearUpload.prototype ={
function1:function(){
var self = this;
...
},
handleFileSelect:function(e){
var self = this;
...
}
}

How to change external function variable from internal jquery event function?

How I can change external function variable from internal function?
Example:
function ExternalFunction() {
var $element = $('#my-element'); // Some jquery object
var my_variable = 'value';
$element.click(function() {
// Here I want to change "my_variable" value.
// But I can't change it with "my_variable = 'new value';".
})
}
How I can change my_variable in internal function?
Update1:
I haven't error, but I can't change variable from internal function. See example please:
http://jsfiddle.net/ye0qhu0v/4/
you cant use ExternalFunction() inside DOM ready,Declare the function outside DOM ready
Works perfectly,
function ExternalFunction() {
var $element = $('#my-element'); // Some jquery object
var my_variable = 'value';
$('#my-element').on('click', function() {
// Here I want to change "my_variable" value.
// But I can't change it with "my_variable = 'new value';".
my_variable = 'new value';//here we are assigning new value to the variable
console.log(my_variable);
})
}

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.

Categories