Handling events inside a class (Prototype) - javascript

I am rewriting the question to make it easier to answer (I Hope). I want to have a Button inside a class (prototype) but I want the handler to be in the class also. Works fine if the handler is outside class but cannot find it if within.
Thanks in advance for your help.
function myWindow(message) {
this.SS = SpreadsheetApp.getActiveSpreadsheet();
this.App = UiApp.createApplication();
this.App.setTitle(message);
this.Panel = this.App.createVerticalPanel();
this.App.add(this.Panel);
this.Button = this.App.createButton('OK', this.App.createServerHandler('handler'));
};
myWindow.prototype = {
constructor: myWindow,
handler: function (e)
{
Browser.msgBox('Click');
},
show: function()
{
this.Panel.add(this.Button);
this.SS.show(this.App);
}
};
function Run() {
var theWindow = new myWindow('Hello World');
theWindow.show();
}
The error I get when I click the OK Button is "Script function not found handler"

Ok I have done a lot of reading and although it is not explicitly stated it seems createServerHandler is only designed for global functions and nothing else is provided in the UIAPP. That means what I have asked for cannot be done.
The solution would have to look like
function myWindow(message) {
this.SS = SpreadsheetApp.getActiveSpreadsheet();
this.App = UiApp.createApplication();
this.App.setTitle(message);
this.Panel = this.App.createVerticalPanel();
this.App.add(this.Panel);
this.Button = this.App.createButton('OK', this.App.createServerHandler('handler'));
}
myWindow.prototype = {
constructor: myWindow,
show: function() {
this.Panel.add(this.Button);
this.SS.show(this.App);
}
};
function handler(e) {
Browser.msgBox('Click');
};
function Run() {
var theWindow = new myWindow('Hello World');
theWindow.show();
};
which is not flash but workable.

Related

javascript class with event methods

My goal is to make a class with some chained functions, but I'm stuck and hoping for some help. This is what I got:
robin = new batman("myiv");
var batman = (function() {
var me = this;
function batman(id){
me._id=id;
document.getElementById(id).addEventListener('mousemove', me.mouseMoving.bind(me),true);
}
this.mouseMoving = function(){
document.getElementById(me._id).style.background="orange";
}
return batman;
}
And this pseudo code is what I am aiming to get. Basically, pass in the ID of an element in my HTML and chain functions to it such as onclick etc, and whatever code inside there, runs. as in example, changing background colors.
Is it possible?
superman("mydiv"){
.onmouseover(){
document.getElementById(the_id).style.background="#ffffff";
},
.onmouseout(){
document.getElementById(the_id).style.background="#000000";
},
etc...
}
edit: updated with missing code: "return batman;"
You can do method chaining by returning the current object using this keyword
var YourClass = function () {
this.items = [];
this.push = function (item) {
if (arguments) {
this.items.push(item);
}
return this;
}
this.count = function () {
return this.items.length;
}
}
var obj = new YourClass();
obj.push(1).push(1);
console.log(obj.count())
Working sample
https://stackblitz.com/edit/method-chaining-example?file=index.js

how to trigger event with 'this' word with OOP Javascript

I would like to trigger an events without duplicating code. So I decided to create a constructor function (class) and then a new object with a variable that connects to an event handler. Im just testing it but I cant get the if statement to trigger the alert() using this.link it works like this: if(el) but not like this: if(el === this.link)
var faqOne = document.getElementById("faqOne");
var hiddenOne = document.querySelector("p.faqOneHidden");
faqOne.addEventListener("click", function (e) {
showFaqOne.showClickedFaq(e);
}, false);
function DisplayQFaqs(link, faq) {
this.link = link;
this.faq = faq;
}
DisplayQFaqs.prototype.showClickedFaq = function (e) {
var el = e.target;
if (el === this.link) {
alert('hi');
}
};
var showFaqOne = new DisplayQFaqs(faqOne, hiddenOne);

using revealling moduler pattern for complex in javascript

I have a very complex class so i decided to break into sub modules and trying to use revealing modules pattern.
I have main class and decided to divide into smaller container function. but in current scenario
But i am not able to access any internal function from outside i.e callSearchResultWithCallBack using searchFinder.Search.callSearchResultWithCallBack(). which pattern should i use to keep this code clean as well have control to call internal function in sub module.
Thanks
var searchFinder;
function SearchFinder() {
me = this;
this.searchResult = null;
this.init = function() {
declareControls();
createAccordian();
addEvents();
fillControls();
var declareControls = function() {
this.SearchButtons = jQuery('.doSearch');
this.InputLocation = jQuery('#inputLocation');
this.InputDistanceWithIn = jQuery('#inputDistanceWithIn');
this.InputName = jQuery('#inputName');
}
var addEvents = function() {
me.SearchButtons.click(function() {
me.Search();
});
}
var fillControls = function() {
var getGetCategory = function() {
}
}
}
this.Search = function() {
var url = '';
var searchCriteria = {};
validateAndCreateCriteria();
callSearchResultWithCallBack();
function validateAndCreateCriteria() {
function validateAandGetCategory() {
if (SearchValidation.ValidateZipCode(me.InputLocation.val().trim())) {
searchCriteria.location = me.InputLocation.val().trim();
} else if (SearchValidation.ValidateCityState(me.InputLocation.val().trim())) {
searchCriteria.location = me.InputLocation.val().trim();
}
}
}
// need to access it outsite
function callSearchResultWithCallBack() {
me.searchResult(searchCriteria, SearchResultCallBack);
function SearchResultCallBack() {
}
}
}
}
jQuery(function() {
searchFinder = new SearchFinder();
searchFinder.init();
searchFinder.Search.callSearchResultWithCallBack();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
This code has multiple issues, first I will address the fact that for example declareControls is not executing. First declare the function than execute!
this.init = function() {
var declareControls = function() {
this.SearchButtons = jQuery('.doSearch');
this.InputLocation = jQuery('#inputLocation');
this.InputDistanceWithIn = jQuery('#inputDistanceWithIn');
this.InputName = jQuery('#inputName');
}
var addEvents = function() {
this.SearchButtons.click(function() {
me.Search();
});
}
var fillControls = function() {
var getGetCategory = function() {
}
}
declareControls();
//createAccordian(); //not defined
addEvents();
fillControls();
}
Now let's look at others problems that will arise.
the me object referring to this is in the scope of searchFinder and does not refer to the same this in the instance of searchFinder.
function jQuery can be replaced by the commonly used $.
searchFinder.Search.callSearchResultWithCallBack() this is never going to work. Since the Search function is an object and callSearchResultWithCallBack isn't a property of this function.
Solution; make it part of the prototype of Search.
Steps:
Move callSearchResultWithCallBack outside the search function.
Add prototype to Search function
Call function via prototype.
function callSearchResultWithCallBack() {
me.searchResult(searchCriteria, SearchResultCallBack);
function SearchResultCallBack() {
}
}
this.Search.prototype.callSearchResultWithCallBack = callSearchResultWithCallBack;
If you want to fire this function outside of search use this:
searchFinder.Search.prototype.callSearchResultWithCallBack();
Please remember that callSearchResultWithCallBack will throw an error because searchCriteria is undefined.
This fixes your problems for now, but this code has to be revised thoroughly. But this should get you started. http://ejohn.org/blog/simple-javascript-inheritance/

Custom Events in CLASS

I need to launch custom events from CLASS. I know to do this with DOM objects and jquery, using triggerHandler, like $(object)..triggerHandler("inputChange", {param:X});
The problem is when i try this with a Class, like this:
var MyClass = (function(){
var static_var = 1;
var MyClass = function () {
var privateVar;
var privateFn = function(){ alert('Im private!'); };
this.someProperty = 5;
this.someFunction = function () {
alert('Im public!');
};
this.say = function() {
alert('Num ' + this.someProperty);
$(this).triggerHandler("eventCustom");
}
this.alter = function() {
this.someProperty ++;
}
};
return MyClass;
})();
TheClass = new MyClass();
$(TheClass).on('eventCustom', function() {
alert('Event!');
});
TheClass.say();
This doesn't launch warnings or errors, but the events listener is not working (or event is not dispatched). I think the jQuery event system doesn't work with not DOM object, correct?
Any other way (I need events, not callbacks for my specific case) to launch the events?
Thanks a lot!
I wrote an ES6 event class for nowadays in under 100 lines of code without using JQuery. If you don't want to use DOM-events you can extend your class, which should deal with Events.
For listening to events, you can use on, once, onReady, onceReady. On is execute the callbackfunction every time the label is trigger. Once only one time. The "ready"-functions execute the callback, if the label had been already triggerd before.
For triggering an event, use a trigger. To remove an eventhandler, use off.
I hope the example makes it clear:
class ClassEventsES6 {
constructor() {
this.listeners = new Map();
this.onceListeners = new Map();
this.triggerdLabels = new Map();
}
// help-function for onReady and onceReady
// the callbackfunction will execute,
// if the label has already been triggerd with the last called parameters
_fCheckPast(label, callback) {
if (this.triggerdLabels.has(label)) {
callback(this.triggerdLabels.get(label));
return true;
} else {
return false;
}
}
// execute the callback everytime the label is trigger
on(label, callback, checkPast = false) {
this.listeners.has(label) || this.listeners.set(label, []);
this.listeners.get(label).push(callback);
if (checkPast)
this._fCheckPast(label, callback);
}
// execute the callback everytime the label is trigger
// check if the label had been already called
// and if so excute the callback immediately
onReady(label, callback) {
this.on(label, callback, true);
}
// execute the callback onetime the label is trigger
once(label, callback, checkPast = false) {
this.onceListeners.has(label) || this.onceListeners.set(label, []);
if (!(checkPast && this._fCheckPast(label, callback))) {
// label wurde nocht nicht aufgerufen und
// der callback in _fCheckPast nicht ausgeführt
this.onceListeners.get(label).push(callback);
}
}
// execute the callback onetime the label is trigger
// or execute the callback if the label had been called already
onceReady(label, callback) {
this.once(label, callback, true);
}
// remove the callback for a label
off(label, callback = true) {
if (callback === true) {
// remove listeners for all callbackfunctions
this.listeners.delete(label);
this.onceListeners.delete(label);
} else {
// remove listeners only with match callbackfunctions
let _off = (inListener) => {
let listeners = inListener.get(label);
if (listeners) {
inListener.set(label, listeners.filter((value) => !(value === callback)));
}
};
_off(this.listeners);
_off(this.onceListeners);
}
}
// trigger the event with the label
trigger(label, ...args) {
let res = false;
this.triggerdLabels.set(label, ...args); // save all triggerd labels for onready and onceready
let _trigger = (inListener, label, ...args) => {
let listeners = inListener.get(label);
if (listeners && listeners.length) {
listeners.forEach((listener) => {
listener(...args);
});
res = true;
}
};
_trigger(this.onceListeners, label, ...args);
_trigger(this.listeners, label, ...args);
this.onceListeners.delete(label); // callback for once executed, so delete it.
return res;
}
}
// +++ here starts the example +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class TestClassEvents extends ClassEventsES6 {
constructor() {
super();
this.once('sayHallo', this.fStartToTalk);
this.on('sayHallo', this.fSayHallo);
}
fStartToTalk() {
console.log('I start to talk... ');
}
fSayHallo(name = 'Nobody') {
console.log('Hallo ' + name);
}
}
let testClassEvents = new TestClassEvents();
testClassEvents.trigger('sayHallo', 'Tony');
testClassEvents.trigger('sayHallo', 'Tim');
testClassEvents.onReady('sayHallo', e => console.log('I already said hello to ' + e));
testClassEvents.trigger('sayHallo', 'Angie');
testClassEvents.off('sayHallo');
testClassEvents.trigger('sayHallo', 'Peter');
console.log('I dont say hallo to Peter, because the event is off!')
Your understanding of how javascript works is limited since you are approaching it from a traditional OOP point of view. Take a look at this fiddle http://jsfiddle.net/9pCmh/ & you will see that you can actually pass functions as variables to other functions. There are no classes in javascript, only functions which can be closures which can be made to emulate traditional classes:
var MyClass = (function(){
var static_var = 1;
var MyClass = function ( callback ) {
var privateVar;
var privateFn = function(){ alert('Im private!'); };
this.someProperty = 5;
this.someFunction = function () {
alert('Im public!');
};
this.say = function() {
alert('Num ' + this.someProperty);
callback();
}
this.alter = function() {
this.someProperty ++;
}
};
return MyClass;
})();
TheClass = new MyClass(function() {
alert('Event!');
});
TheClass.say();
Alternatively you could create a function in your "class" to configure the callback/trigger instead of passing it into the constructor.
Have a look at this as a start for your further reading on this concept... How do JavaScript closures work?
Edit
To appease those critics looking for an eventQueue here is an updated jsfiddle :)
http://jsfiddle.net/Qxtnd/9/
var events = new function() {
var _triggers = {};
this.on = function(event,callback) {
if(!_triggers[event])
_triggers[event] = [];
_triggers[event].push( callback );
}
this.triggerHandler = function(event,params) {
if( _triggers[event] ) {
for( i in _triggers[event] )
_triggers[event][i](params);
}
}
};
var MyClass = (function(){
var MyClass = function () {
this.say = function() {
alert('Num ' + this.someProperty);
events.triggerHandler('eventCustom');
}
};
return MyClass;
})();
TheClass = new MyClass();
events.on('eventCustom', function() {
alert('Event!');
});
events.on('eventCustom', function() {
alert('Another Event!');
});
TheClass.say();

Javascript Object Confusion

I've confused myself nicely here. My scenario is as follows:
function DesignPad() {
function EditBar() {
...
this.removeHandler = function() {
**// how do I call Dragger.removeAsset**
}
}
function Dragger(){
...
this.removeAsset = function() {}
}
this.init = function() {
this.editBar = new EditBar();
this.dragger = new Dragger();
}
}
var dp = new DesignPad();
...
I can't seem to call Dragger.RemoveAsset. I understand the why, my question is how do I call it?
I'm trying to keep like-things separated (e.g. Dragger / EditBar) but I seem to get all sorts of mixed up in my event handlers. Any suggestions, good reading materials, etc. on this stuff?
I found Douglas Crockford's Javascript to be the best introduction to JavaScript. Especialy videos for Yahoo, like: The JavaScript Programming Language where you can learn how exactly are objects created and inherited in JS.
Solution to you problem is:
function DesignPad() {
var that = this;
function EditBar() {
this.removeHandler = function() {
print("RemoveHandler");
that.dragger.removeAsset();
}
}
function Dragger() {
this.removeAsset = function() {
print("RemoveAsset");
}
}
this.init = function() {
this.editBar = new EditBar();
this.dragger = new Dragger();
}
}
var dp = new DesignPad();
dp.init();
dp.editBar.removeHandler();
But as others noticed you could refactor some things :).
To me it just looks like you should refactor that code to make it simpler.
I think that your issue comes from the fact that a nested function is private, so you can't access it from outside.
Is an instance of Dragger a 'property' of your DesignPad object? If so, you could pass a reference to that object into your removeHandler() method.
Try this:
function DesignPad() {
function EditBar(s) {
super = s;
this.removeHandler = function() {
alert('call 1');
super.dragger.removeAsset();
}
}
function Dragger(s){
super = s;
this.removeAsset = function() {
alert('call 2');
}
}
this.init = function() {
this.editBar = new EditBar(this);
this.dragger = new Dragger(this);
}
}
var dp = new DesignPad();
dp.init()
dp.editBar.removeHandler();
alert('end');

Categories

Resources