I have created a dynamic Bar graph using visualize function and visualize.css the value for graphs is given through HTML table now I want to perform an event on that graph.
Create a custom event:
(function() {
/**
* Small event class, can be instanciated as an object or using .call used to decorate other
* Objects with events funcitonality.
*/
MyEvent.Event = function() {
this.events = {};
this.bind = function(eventName, func) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(func);
};
this.trigger = function(eventName, args, scope) {
if (this.events[eventName]) {
var len = this.events[eventName].length,
funcArgs = (jQuery.isArray(args)) ? args : [args];
// This will go from back to front through the array not sure if this really matters?
while (len--) {
this.events[eventName][len].apply(scope || window, funcArgs);
}
}
}
this.removeAllEvents = function() {
this.events = {};
}
};
// Page level events class
MyEvent.pageEvents = new MyEvent.Event();
})();
trigger it:
MyEvent.pageEvents.trigger("Method-name", "data"));
and Finally listen it:
MyEvent.pageEvents.bind("Method-name", function(Data) {
//Code goes here
});
USING JQUERY?
Take a look at trigger and bind.
Related
I am creating multiple objects and binding to the same handler. My requirement is I want to send particular value to handle when it is called.
Code:
sliderObj = [];
for(i=0;i<3;i++)
{
sliderObj[i] = this._turntableSlider = new SliderView();
sliderObj[i].on("change:value", this._handleChangeSpeedSlider);
}
When handler is called for sliderObj[0] want to send value 0 similarly 1 for sliderObj[1] etc.
Please help me out how to do that.
Try using .bind():
sliderObj[i].on("change:value", this._handleChangeSpeedSlider.bind(this, i));
Simple demo
Prefer listenTo over on.
Passing the index
Simplest solution would be to wrap the callback into an anonymous function.
But since we're looping and value of i will change, we need to create a simple function which returns a new function using the frozen value of i. (This is similar to using TJ's bind answer)
function getChangeSpeedHandler(index) {
return function() {
this._handleChangeSpeedSlider(index);
}
}
for (i = 0; i < 3; i++) {
var slider = sliderObj[i] = new SliderView();
this.listenTo(slider, "change:value", getChangeSpeedHandler(i));
}
Passing the slider view
Assuming the value of i in the handler is only used to get the right sliderObj, you could pass the slider view directly.
function getChangeSpeedHandler(slider) {
return function() {
this._handleChangeSpeedSlider(slider);
}
}
for (i = 0; i < 3; i++) {
var slider = sliderObj[i] = new SliderView();
this.listenTo(slider, "change:value", getChangeSpeedHandler(slider));
}
Delegating the event handling to the slider view
If you want to handle changes inside the SliderView, it should handle the event itself.
this.listenTo(this.model, 'change:value', this.onValueChange);
Triggering custom events
If it's really the parent that needs to know the slider and their number is dynamic, you could pass the i value to the SliderView and then it could trigger a custom event.
In the slider view:
var SliderView = Backbone.View.extend({
initialize: function(options) {
options = options || {};
this.index = options.index;
// ...
},
onValueChange: function(model, value, options) {
this.trigger('slider:change', value, this.index, this);
},
});
Then in the parent:
initialize: function() {
for (i = 0; i < 3; i++) {
var slider = sliderObj[i] = new SliderView({ index: i });
this.listenTo(slider, "slider:change", this._handleChangeSpeedSlider);
}
},
_handleChangeSpeedSlider: function(value, index, sliderView) {
// handle the change
}
I want to detect if the method of an object is called.
I have a video player in my page and when it is done playing, I want to show some contents.
For example:
function videoSet(){
var instance = this;
this.video = $('#video')
this.video.bind("ended", function() {
instance.endVideo()
});
}
videoSet.prototype.endVideo = function(){
$('#test1').css('visibility','visible');
}
//more methods...
function main(){
this.init();
}
main.prototype.init = function(){
this.video = new videoSet() //init an video object.
// more code...
//I need to know if the video is ended...
}
var mainObj = new main();
Inside my endVideo method, I have $('#test1').css('visibility','visible'); but I have so much code in my main object and I want to be able to detect if the video has ended in my main object.
Is that possible?
You can have multiple eventListeners on DOM objects...
var Video = function () { this.video = document.querySelector("#my-video"); };
var Main = function () {
var myVideo = new Video();
myVideo.video.addEventListener("ended", function () { console.log("It's over!"); });
myVideo.video.addEventListener("ended", function () {
console.log("Play something else.");
});
};
Main();
There's nothing stopping you from adding an event-listener to the object from inside of main.
Moreover, this leads to custom event systems -- Publisher/Subscriber or Observer or "Emitters".
If you can implement one of these, on an object, then your object can create/fire custom events, and pass custom data, and any time you have access to that object, you can subscribe (as long as you know what the events are called, and how to handle the data you will get back).
For example, you might want to have a video-playing system that loads the next film (or a countdown screen, until the next film, et cetera, for continuous playback, with a playlist that highlights the current film).
var VideoPlayer = function (id) {
var player = this;
player.video = document.getElementById(id);
// attach an emitter-system with "on", "off" and "emit", or whatever you choose
addEmitter(player);
player.load = function (video) { player.video.src = video.src; };
player.init = function () {
player.video.addEventListener("ended", function () {
// fire custom-event
player.emit("video-ended");
});
player.video.addEventListener("canplay", function () {
// auto-play video, fire event
player.video.play();
player.emit("video-playing");
});
};
},
VideoPlaylist = function (id, videos) {
var playlist = this;
playlist.root = document.getElementById(id);
playlist.videos = videos;
playlist.addVideo = function (video) { /* attach each video to the root */ };
playlist.currentVideoIndex = 0;
playlist.currentVideo = playlist.videos[playlist.currentVideoIndex];
playlist.select = function (i) {
playlist.currentVideoIndex = i;
playlist.currentVideo = playlist.videos[i];
// fire a custom event
playlist.emit("load-video", playlist.currentVideo);
};
playlist.nextVideo = function () {
var i = (playlist.currentVideoIndex + 1) % playlist.videos.length; // loops
playlist.select(i);
};
addEmitter(playlist);
};
var Main = function () {
var video_player = new VideoPlayer("my-player"),
video_playlist = new VideoPlaylist("my-playlist", [{ src : "...", title : "A" }, { src : "...", title : "B" }]);
video_player.on("video-ended", video_playlist.next);
video_playlist.on("load-video", video_player.load );
// add another listener for another component, to handle on-screen controls
video_player.on("video-playing", video_controller.show_playing);
// add another listener for another component, to display the data about the video
video_playlist.on("load-video", video_description.display);
// add another listener for another component to load comments
video_playlist.on("load-video", video_comments.load);
};
Main();
This isn't a particularly Java-like way of writing programs, but JavaScript isn't particularly Java-like (though you can make it look similar).
You'll notice that inside of the Main function all I'm doing is wiring behaviours together, rather than writing out custom logic.
Of course, you can take this way further...
...and I haven't shown you how my emitter is made, but they're not hard to make, either.
Publisher/Subscriber or Observer or Emitter implementations are great practice for JS (and very easy in JS compared to other languages).
But as you can see, with a little thinking, this is a really simple and versatile way of dispatching code.
You can use an ended flag in the videoSet object like
function videoSet() {
var instance = this;
this.ended=false;
this.video = $('#video')
this.video.bind("ended", function () {
instance.endVideo()
});
}
videoSet.prototype.endVideo = function () {
$('#test1').css('visibility', 'visible');
this.ended=true;
}
videoSet.prototype.isEnded = function () {
return this.ended;
}
//more methods...
function main() {
this.init();
//later
if(myVideoSet.isEnded()){
console.log('completed')
}
}
I was wondering if anyone can help me understand how exactly to create different Custom event listeners.
I don't have a specific case of an event but I want to learn just in general how it is done, so I can apply it where it is needed.
What I was looking to do, just incase some folks might need to know, was:
var position = 0;
for(var i = 0; i < 10; i++)
{
position++;
if((position + 1) % 4 == 0)
{
// do some functions
}
}
var evt = document.createEvent("Event");
evt.initEvent("myEvent",true,true);
// custom param
evt.foo = "bar";
//register
document.addEventListener("myEvent",myEventHandler,false);
//invoke
document.dispatchEvent(evt);
Here is the way to do it more locally, pinpointing listeners and publishers:
http://www.kaizou.org/2010/03/generating-custom-javascript-events/
Implementing custom events is not hard. You can implement it in many ways. Lately I'm doing it like this:
/***************************************************************
*
* Observable
*
***************************************************************/
var Observable;
(Observable = function() {
}).prototype = {
listen: function(type, method, scope, context) {
var listeners, handlers;
if (!(listeners = this.listeners)) {
listeners = this.listeners = {};
}
if (!(handlers = listeners[type])){
handlers = listeners[type] = [];
}
scope = (scope ? scope : window);
handlers.push({
method: method,
scope: scope,
context: (context ? context : scope)
});
},
fireEvent: function(type, data, context) {
var listeners, handlers, i, n, handler, scope;
if (!(listeners = this.listeners)) {
return;
}
if (!(handlers = listeners[type])){
return;
}
for (i = 0, n = handlers.length; i < n; i++){
handler = handlers[i];
if (typeof(context)!=="undefined" && context !== handler.context) continue;
if (handler.method.call(
handler.scope, this, type, data
)===false) {
return false;
}
}
return true;
}
};
The Observable object can be reused and applied by whatever constructor needs it simply by mixng the prototype of Observable with the protoype of that constructor.
To start listening, you have to register yourself to the observable object, like so:
var obs = new Observable();
obs.listen("myEvent", function(observable, eventType, data){
//handle myEvent
});
Or if your listener is a method of an object, like so:
obs.listen("myEvent", listener.handler, listener);
Where listener is an instance of an object, which implements the method "handler".
The Observable object can now call its fireEvent method whenever something happens that it wants to communicate to its listeners:
this.fireEvent("myEvent", data);
Where data is some data that the listeners my find interesting. Whatever you put in there is up to you - you know best what your custom event is made up of.
The fireEvent method simply goes through all the listeners that were registered for "myEvent", and calls the registered function. If the function returns false, then that is taken to mean that the event is canceled, and the observable will not call the other listeners. As a result the entire fireEvent method will return fasle too so the observable knows that whatever action it was notifying its listeners of should now be rolled back.
Perhaps this solution doesn't suit everybody, but I;ve had much benefit from this relatively simple piece of code.
From here:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
// create the event
const event = new Event('build');
// elem is any element
elem.dispatchEvent(event);
// later on.. binding to that event
// we'll bind to the document for the event delegation style.
document.addEventListener('build', function(e){
// e.target matches the elem from above
}, false);
Here is a really simple (TypeScript/Babelish) implementation:
const simpleEvent = <T extends Function>(context = null) => {
let cbs: T[] = [];
return {
addListener: (cb: T) => { cbs.push(cb); },
removeListener: (cb: T) => { let i = cbs.indexOf(cb); cbs.splice(i, Math.max(i, 0)); },
trigger: (<T> (((...args) => cbs.forEach(cb => cb.apply(context, args))) as any))
};
};
You use it like this:
let onMyEvent = simpleEvent();
let listener = (test) => { console.log("triggered", test); };
onMyEvent.addListener(listener);
onMyEvent.trigger("hello");
onMyEvent.removeListener(listener);
Or in classes like this
class Example {
public onMyEvent = simpleEvent(this);
}
If you want plain JavaScript you can transpile it using TypeScript playground.
I'd like to create an event for each function in a script, then inject the event trigger into the end of the function.
This way I can see exactly when each function has completed and use the events like hooks for other functions
If I can do it dynamically, I can add as many new functions as I like without having to create and append these events.
Here's a basic example of what I'm trying to do, this won't actually work, but it gives you an idea. I have been using jQuery, but I'll accept any JavaScript framework at all, and any method.
var obj = {};
(function()
{
this.init = function()
{
// loop through every function
$.each(this, function(k, v)
{
// create an event for every function
$('body').bind(v, function()
{
console.log('Event: ' + v + ' Finished');
});
// Add a event trigger into each specific function in the loop
this[v].call($('body').trigger(v));
});
}
this.another_function = function()
{
// do something
}
this.some_function = function()
{
/do something
}
}).apply(obj);
obj.init();
(edit) The script itself basically renders a Calendar, but there are a lot of callbacks, ajax requests, buttons. etc... If I could tie each feature down to an event, it would make my life easier when extending it, adding new features etc...
Loop through every function, replace it with new one, which calls original function on the same object and triggers event on body.
var obj = { };
(function()
{
this.init = function()
{
var self = this;
foreach(var name in this) {
if (typeof k !== 'Function') continue;
if (name ==='init') continue;
var original = this[name];
var newFunc = function() {
original.apply(self, arguments);
$('body').trigger(name);
}
this[name] = newFunc;
}
}
this.another_function = function()
{
// do something
}
this.some_function = function()
{
/do something
}
}).apply(obj);
obj.init();
I have 3 classes:
function A(data){
this.data = data || [];
}
A.prototype.remove = function(index){
// remove index from this.data;
};
function B(data){
this.data = data || [];
}
B.prototype.add = function(x){
this.data.push(x);
};
B.prototype.update = function(index, x){
this.data[index] = x;
};
function C(data){
this.data = data || [];
}
C.prototype.add = function(x){
this.data.push(x);
};
var a = new A(xx);
var b = new B(xx);
var c = new C(xx);
There relations are:
if I call a.remove(i) to remove an element, b will add it to its data.
if I call b.update(i, x), c will add x to its data.
How could I design this with smallest coupling?
ps: this is just an example to demonstrate the situation, please don't care about the initialization etc.
I would use events for loose coupling at its best. As base I recommend using Backbone.js (see Backbone.Events section) it has very small footprint and provide you with great custom events support. Brief description from docs:
Events is a module that can be mixed in to any object, giving the object the ability to bind and trigger custom named events.
It could look like this:
function A(data){
this.data = data || [];
}
A.prototype.remove = function(index){
// remove index from this.data;
// dispatch A_Remove event
this.trigger("A_Remove", this.data);
};
function B(data){
this.data = data || [];
}
B.prototype.add = function(x){
this.data.push(x);
};
B.prototype.update = function(index, x){
this.data[index] = x;
this.trigger("B_Update", x);
};
function C(data){
this.data = data || [];
}
C.prototype.add = function(x){
this.data.push(x);
};
var a = new A(xx);
var b = new B(xx);
var c = new C(xx);
// mixin event support to your objects
_.extend(a, Backbone.Events);
_.extend(b, Backbone.Events);
_.extend(c, Backbone.Events);
// event listener for A_Remove event
a.bind("A_Remove", function(data) {
b.add(data);
});
// event listener for B_Update event
b.bind("B_Update", function(data) {
c.add(data);
});
With this event-based approach, your classes are as loose coupled as they can be, there's no need for A, B or C to know about each other. At the same time you get highest flexibility - at any point you can add more listeners or event types.
I feel that's the best solution.
I would add callbacks to class A and class B
function A(data, callback) {
this.data = data || [];
this.callback = callback || function() {};
}
A.prototype.remove = function(index) {
// remove index from this.data;
this.callback(this.data[index]);
}
...
var b = new B(xx);
var a = new A(xx, function(e) {b.add(e);});