I am trying to make a function available globally. I wrapped it in an immediate function but it only works if I call a new $MyClass() inside the function. I want to be able to use it like Jquery, calling functions like this elsewhere in my project:
$MyClass('myButton').click(function(){
console.log('The button was clicked');
});
This is what I want access to:
(function() {
function $MyClass(element){
element = document.getElementById(element)
this.element = element;
return this;
}
$MyClass.prototype.click = function(callback) {
this.element.addEventListener("click", clickFunction);
function clickFunction() {
callback();
}
}
$MyClass.prototype.hover = function(inEvent, outEvent) {
this.element.addEventListener("mouseover", hoverOn);
if (outEvent != undefined) {
this.element.addEventListener("mouseout", hoverOff);
}
function hoverOn() {
inEvent();
}
function hoverOff() {
outEvent();
}
}
}());
How do I expose $MyClass to the global namespace? None of the answers I've found online have made sense to me enough to apply it to my project.
Related
I'm not that good with Javascript, so I'm not sure why I can't call the function dgnProcessesFilter like this.
var conditions = this.dgnProcessesFilter(item.proc_id, "proc_id");
The error im getting is Uncaught TypeError: this.dgnProcessesFilter is not a function
Just a few line up from that I have the function deceleration.
dgnProcessesFilter:function(id, type){
if(type == "site_id"){
return _dgnProceses.filter((process)=>process.site_id==id);
}
if(type == "proc_id"){
return _dgnProceses.filter((process)=>process.proc_id==id);
}
},
and in another function I also call that function, but with a immediate RETURN on the result, and it works just fine.
Why is this, can someone please help me and explain why maybe.
Bellow the call to this function woks fine.
getDgnProcesses: function(siteSelector) {
if(siteSelector.isNaN ){
if(siteSelector) {
return this.dgnProcessesFilter(siteSelector, "site_id");
} else {
return util.cloneArray(_dgnProceses || []);
}
} else {
if(siteSelector) {
var selectedSite = this.getSite("description", siteSelector);
if(selectedSite){
if (selectedSite.hasOwnProperty("site_id")) {
return this.dgnProcessesFilter(selectedSite.site_id, "site_id");
}
} else {
return [];
}
} else {
return util.cloneArray(_dgnProceses || []);
}
}
},
update
the call is from a search component
the store in included
_searchDiagnosis: function() {
this.setState({foundDiagnosis: this.state.searchValue ? DiagnosisStore.getDiagnosisSearch(this.state.searchValue).bind(DiagnosisStore) : [] });
},
I just tried the .bind(DiagnosisStore), but it did not seem to do the job.
all the functions are enclosed in the following.
var DiagnosisStore = assign({}, EventEmitter.prototype, {...}
I think you are loosing the lexical binding of 'this' at some point. If you are using ES6 or a transpiler (like Babel) try to use the "arrow" function notation to keep the value of 'this' of the surrounding code.
Here these is a blog post explaining arrow functions https://toddmotto.com/es6-arrow-functions-syntaxes-and-lexical-scoping/
Use also the new ES6 method declaration to be sure that 'this' is the object that contains the method:
getDgnProcesses(siteSelector) {
},
I have a problem understanding the scope of 'this' especially when nesting code
here is the example that I have a problem with
var callbacks = [];
MyClass.protoype.CallServer = function(name,index,callback)
{
//some code
callbacks[callback.length] = callback;
callserverfor(name,index, callbacks.length-1);
}
MyClass.prototype.ReceiveFromServer = function(callbackId,param)
{
//somecode for simplicity let's say
if(param)
callbacks[callbackId].call(param);
else
callbacks[callbackId].call();
}
MyClass.prototype.Connect(Index,callback)
{
CallServer('Connect' , Index, callback);
}
MyClass.prototype.Start= function(Index)
{
this.Connect(Index,function()
{
this.ISConnected = true;
//HERE this lost scope
this.GetIdentified(Index, function( Identifier)
{
alert('Identifier');
});
});
}
I even tried bind
MyClass.prototype.ReceiveFromServer = function(callbackId,param)
{
//somecode for simplicity let's say
if(param)
callbacks[callbackId].call(param);
else
callbacks[callbackId].call();
}
MyClass.prototype.Connect(Index,callback)
{
CallServer('Connect' , Index, callback);
}
MyClass.prototype.Start= function(Index)
{
this.Connect(Index,function()
{
this.ISConnected = true;
var GetIdentifier = this.GetIdentifier;
GetIdentifier.bind(this);
//HERE this lost scope
this.GetIdentifier(Index, function( Identifier)
{
alert('Identifier');
});
});
}
When I tried to use Me which point to this inside the code .. it worked ..
Can I understand what is happening here as I don't get it
MyClass.prototype.ReceiveFromServer = function(callbackId,param)
{
//somecode for simplicity let's say
if(param)
callbacks[callbackId].call(param);
else
callbacks[callbackId].call();
}
MyClass.prototype.Connect(Index,callback)
{
CallServer('Connect' , Index, callback);
}
MyClass.prototype.Start= function(Index)
{
var Me= this;
this.Connect(Index,function()
{
Me.ISConnected = true;
//HERE this lost scope
Me.GetIdentifier(Index, function( Identifier)
{
alert('Identifier');
});
});
}
Is there a better way of doing this or determining the scope of the callback ? any suggestions
Let me explain it with a little example:
var functions=[]; //a common array
functions.name="functions" //we add an attribute to that object
function generator(v) {
var temp=v;
return function () {
console.log(this.name+temp);
};
}
for (var i=0;i<5;i++) {
functions[i]=generator(i); // here we add a bunch of functions to that object
}
If you execute functions[2]() you will obtain "functions2"in the console. Why? Because you are calling to a function that belongs to an object, (so that function is a method of that object) and that object is the "current context".
Then, if you execute something like this:
var f= functions[2];
f();
It will print "2" because f is executed as a "standalone" function, so the context is the "global context" and there is no "name" attribute created.
Be careful with callbacks, because they can be executed by other objects or functions. For example, if you set an event listener callback (you create a functions to be executed when user clicks somewhere), is the listener of that event who is going to execute it. So a classic trick is to create a variable as "me" "self" or "_this" to store the needed context in a clausure:
var myObj={ name:'my object'};
myObject= function () {
var self=this; //here
window.onclick=function(e) {
console.log("I'm keeping a link to myObj: "+ self.name);
}
}
If you want to select another context, you can also use f.call(context, first_parameter) or f.apply(context,[param0,param1...])
Resolved!! see the end of the question for the result that I used
I am trying to write a function that can handle my apps paging by routes.
I have a function route() that is called with argument being the route(page) to move to.
route is an object that defines a model that it uses that handles its logic.
This model contains 3 functions
indexAction
- This renders my view and appends it to my page.
bindEvents
- This is where I have placed all of my click events
shutDown
- This is instructions to run when moving to a new page
The router function first runs shutdown on the current page, here I have the $(selector).off() and $(selector).remove()
it then runs the enidexAction and bindEvents function.
My issue now is when I return to this page, all my click functions are running twice, then three times etc... its as if the off() never actually unbind from the anchor.
here is an example of one of my models
var NewPageModel = (function() {
var instance;
var modal = 'null';
function createInstance() {
var object = {
indexAction: indexAction,
shutDown: shutDown,
bindEvents: bindEvents
};
return object;
}
function indexAction (data, callback){
var partials = {};
ViewManager.render('pageName',{context:data}, partials,function(html){
ViewManager.appendUnique('#xxx',html,'uniqueID');
callback();
});
}
/**
* Remove modal
*/
function shutDown(){
this.modal.off();
this.modal.remove();
}
function bindEvents() {
if(this.modal!='null'){
return;
}
this.modal = $(PagerManager.pages.newGroup.id);
this.modal.on('click','div.close', function () {
shutDown();
});
this.modal.on('click', 'button.cancel', function () {
shutDown();
});
this.modal.on('click', 'button.submit', function () {
//code that submits form information
});
}
return {
getInstance: function () {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
};
})();
EDIT!!
So I am still learning about the importance of scopes and how they can be applied to functions
Here is the working code
var NewPageModel = (function() {
var instance;
var modal;
function createInstance() {
var object = {
indexAction: indexAction,
shutDown: shutDown,
bindEvents: bindEvents
};
return object;
}
function indexAction (data, callback){
var partials = {};
ViewManager.render('pageName',{context:data}, partials,function(html){
ViewManager.appendUnique('#xxx',html,'uniqueID');
callback();
});
}
/**
* Remove modal
*/
function shutDown(){
this.modal.off();
this.modal.remove();
this.modal = null;
}
function bindEvents() {
//This is confused logic, if I use off() in shutdown, I don't need to do this as I need to bind all the events again. hence in shutdown modal=null;
if(!this.modal){
return;
}
this.modal = $('#modal');
this.modal.on('click','div.close', function () {
shutDown().apply(this);
}).bind(this);;
this.modal.on('click', 'button.cancel', function () {
shutDown().apply(this);
}).bind(this);;
this.modal.on('click', 'button.submit', function () {
//here I only use the apply(this) if I use another internal function
//code that submits form information
}).bind(this);;
}
return {
getInstance: function () {
if (!this.instance) {
this.instance = createInstance();
}
return this.instance;
}
};
})();
You are losing your this in the event handler functions (this will be the element clicked) so the shutDown is not getting the correct this:
this.modal.on('click','div.close', function () {
shutDown();
});
should be:
var self = this;
this.modal.on('click', 'button.cancel', function () {
self.shutDown();
});
e.g.
function bindEvents() {
var self = this;
if(this.modal!='null'){ /// <<<< !!!!!! WTF
return;
}
this.modal = $(PagerManager.pages.newGroup.id);
this.modal.on('click','div.close', function () {
self.shutDown();
});
this.modal.on('click', 'button.cancel', function () {
self.shutDown();
});
this.modal.on('click', 'button.submit', function () {
//code that submits form information
});
}
Note: I am ignoring the string comparison to null for now as I have no clue what you are doing there :)
As pointed out in comment by #Gurami Dagundaridze you can also retain the correct this using bind (I think the syntax goes like this):
this.modal.on('click', 'button.cancel', shutDown.bind(this));
In the spirit of keeping your syntax and just fixing the bug,
if(this.modal!='null'){ should be if(modal!='null'){
Because this.modal will be undefined at that condition and will just return.
In the spirit of fixing your code, you need to keep a reference to this or it will default to window in the browser.
var modal;
function createInstance() {
var object = {
modal : modal,
shutDown: shutDown,
bindEvents: bindEvents
};
return object;
}
function bindEvents() {
if(this.modal){
return;
}
// ..... //
this.modal.on('click','div.close', function () {
shutDown.apply(this);
}.bind(this));
// ..... //
}
Working demo :
http://jsfiddle.net/uyovgdj3/
Yes, I have thoroughly searched google and did not find anything that suits my requirement.
The code i have so far is at the link below:
http://jsfiddle.net/ZKwTY/4/
There are multiple onchange events which call almost the same code, i would like to combine them maybe in a comma separated fashion to call it only once.
something like this
(on1Change, on2Change, on3Change): function () {
this.loadData();
}
is this possible??
Note: these functions are bound to the controls via a framework over which i do not have control, i need to create these functions and the framework would bind these to the respective controls
or you can create your object like this
var ol = {
on1Change: this.loadData,
on2Change: this.loadData,
on3Change: this.loadData,
on4Change: this.loadData,
loadData: function () {
this.loadData1();
this.loadData2();
},
loadData1: function () {
alert('hi from loadData1');
},
loadData2: function () {
alert('hi from loadData2');
}
};
Then if you want to do it once, then declare a object
var ol = {
loadData: function () {
this.loadData1();
this.loadData2();
},
loadData1: function () {
alert('hi from loadData1');
},
loadData2: function () {
alert('hi from loadData2');
}
};// end of object
ol.on1Change = ol.on2Change = ol.on3Change = ol.on4Change = ol.loadData;
add all propteries dynamically after object declaration
use bind()
$("selector").bind(on1Change, on2Change, on3Change): function () {
this.loadData();
}.....
you can try somethig like this http://jsfiddle.net/s4VVY/
i.e. add methods after object create
[1,2,3,4,5].forEach(function(it){ol["on"+it+"Change"] = function(){this.loadData()}})
UPDATE
may be this help
var ol = (function(){
var o = {
loadData: function () {
this.loadData1();
this.loadData2();
},
loadData1: function () {
alert('hi from loadData1');
},
loadData2: function () {
alert('hi from loadData2');
}
}
o.on1Change=o.on2Change=o.on3Change=o.on4Change=function(){ this.loadData();};
return o;
})()
also you can make function bindFunc
function bindFunc(){
var obj = arguments[0],
handler = arguments[1],
properties = Array.prototype.slice.call(arguments,2);
for(var i in properties){
obj[properties[i]] = handler;
}
}
and call as
bindFunc(o,function(){this.loadData();},"on1Change","on2Change","on3Change","on4Change")
I have next situation...
For some reasons I need to bind knockout ViewModel inside function and call it on specific terms.
this is my code:
if (... some conditions ...) {
var polugodiste = $("#polugodiste").val();
ApplyBindingsIzostanak(polugodiste);
$('#flip-min').change(function () {
IzostanakViewModel.selectedPolugodiste(parseInt($(this).val()));
IzostanakViewModel.GetIzostanci();
});
}
and function:
function ApplyBindingsIzostanak(polugodiste)
{
var Izostanak = function (cas, tekst) {
this.Cas = cas;
this.Tekst = tekst;
};
var IzostanakViewModel = {
selectedStatus: ko.observable(),
selectedPolugodiste: ko.observable(polugodiste),
ucenikIzostanakList: ko.observableArray([]),
GetIzostanci: function () {
.. do some code ...
}
};
ko.applyBindings(IzostanakViewModel);
}
Binding is working, but I get error when I try calling IzostanakViewModel inside my if, it says IzostanakViewModel is not defined.
Can I and how expose IzostanakViewModel from function and use it inside if statement?
NOTE*
I could try something like this:
add this code to ApplyBindingsIzostanak():
window.foo = function() {
IzostanakViewMode.GetIzostanci();
}
and then call it from if statement, but maybe there is better solution...
IzostanakViewModel is a variable within the ApplyBindingsIzostanak() function. Why don't you just return it so you have a reference to it?
function ApplyBindingsIzostanak(polugodiste)
// ...
return IzostanakViewModel;
}
var IzostanakViewModel = ApplyBindingsIzostanak(polugodiste);
$('#flip-min').change(function () {
IzostanakViewModel.selectedPolugodiste(parseInt($(this).val()));
IzostanakViewModel.GetIzostanci();
});