best practices for designing a page with lots of events - javascript

So I have a grid on a page that displays tablular data, with a checkbox by each row.
So in this situation, when a checkbox is clicked, allot of things will react on the page potentially.
Also, if a button is clicked, again allot of things will potentially react on the page.
So say if someone checks a checkbox, the row should be highlighted, there is a toolbar that will show/hide buttons, etc.
If someone were to click on the toolbar directly, again things similar to when the checkbox was clicked will react.
So what I want to do is this, whenever a checkbox is clicked, or whenever a toolbar button is clicked, I want to 'announce' to anyone who is listening that this event occurred.
I can then, based on the source of the event, react in a similar or different manner.
how to best go about designing things like this?

I think you want to look into using the Observer Pattern. Basically, interested parties subscribe or listen for an event on a publisher, and when the event occurs, the source notifies all the listeners of it.

two things come to mind:
1. event delegation (you don't want to bind to each input on the grid)
look at this link to a great way of doing this while also maintaining a clean code:
by ben nadel
2. using custom events, or even better - use this pub/sub plugin
i have a large grid like this in my app that evolved over time, and manually binding to each input + responding in different ways caused the code to be a "bit" ugly,
It's great that you now where you are going and prepare up front

You could try YUI Custom Events. This allow you to fire off your own "event" which listeners can hear.

I like how it works with jquery, since you can bind an event to many
elements at once.
$("input[type=checkbox]").click(function(e){
alert(e.currentTarget.id);
});
This code would make all checkboxes alert their name. Of course, by using css classes,
you could bind a subset of all checkboxes to create an action.
$("input[type=checkbox].cssClass").click(function(e){
someOtherFunction(e.currentTarget);
});

Related

Make event fire first... alternative to using $._data in jQuery

I want to create a "confirm plugin" that will fire first and ask the user if "they are sure". Just to be clear, I will be using a custom made confirm box, not a the default Window confirm() Method.
If yes then it will fire all the other events that have been bound to it. If no then it will do nothing.
A use case would be a delete button that has a separate click event bound to it, which when pressed will delete an element.
If I attach my plugin to the button then it will bind another click event and by using the events info inside $._data I can send my even to the top of the list (making it fire first), I then stop propagation (this stops the other binding firing which deletes the element). If the user clicks ok on my confirm box, I trigger a click again this time just bypass the stop stuff and it will then fire the original events
I am using a slightly modified version of https://github.com/private-face/jquery.bind-first
The only way it can access this info on an element is by using:
$._data($(this)[0]).events
I want to know how "future proof" this is as I know this changed already since 1.7. Are there any plans to officially support a similar thing.
If all else fails, I know I can just make sure that the plugin and the bindings happen first in the code, but this is not really the most flexible solution.
Using $._data is a smelly solution, hence this post. Maybe there are some fancy custom event things I can do?
The short and simple answer is not at all. Using, or more importantly relying on undocumented features is never a good idea.
It sounds like you have an XY Problem here. There are likely many other ways to achieve what you're trying to do here, and using $._data is almost certainly not the best solution.

How to fire a DOM event with YUI3

I've encountered an annoying issue while working on YUI.
I have a main area and a navigation block. The elements in the main area can be activated with a direct click or by clicking an element in the navigation block that triggers the appropriate element in the main area.
As it turns out, triggering a click event programmatically in YUI isn't as simple as I thought it might be. Looking at the documentation I found pleanty of information on how to attach and delegate events but not how to call one.
I found this question, but it deals with creating a new custom event and not calling an existing one.
All other similar questions are answered with using .simulate(), but this is actually not the best option for compatability reasons and it's also not recommended by YAHOO itself for client-side use http://yuilibrary.com/yui/docs/event/simulate.html#faking. EDIT: After re-reading the section I realized the warning is irrelevant for the subject of this question.
I found a solution by calling the click() command in the node's DOM element, but this is really a last resort and I would like to know if there's a more "clean" way to do it through YUI.
Here is an example of what I'm doing now: http://jsfiddle.net/3fso2dg8/
In the example, the second button is triggering the click event of the first button by using the DOM element
Y.one('#clickme')._node.click();
CONCLUSIONS
After more fiddling with the code I came to realize simulate() is the preferred option in most cases, but not all.
The YUI vesrion I'm required to work with (3.14) has a known issue on simulating a click event in IE9 and above. Since - for other technical reasons - I cannot upgrade to whatever version this issue was fixed and I need to keep a multi-platform compatibility, my original solution is still the best option. Anyone else that uses YUI components that don't respond well on IE, maybe you stumbled upon the same issue so this is one way to solve it.
After looking for exactly the same functionality I just used simulate in user-facing code - where It would just mimic clicking with no return method etc. (simple submit button or choose fil trigger).
When I would needed "complex" functionality I would just add a class or new ID and add new delegate or "on" method in my code - following the: "If a function needs to respond to user action or be called programmatically, it should be written accordingly and called directly in the latter case." prinsipp.
So to summarize - I use simulate for very simple effects with no callbacks or other "advanced" stuff and (sadly) duplicate other delegate/on elements where simulating would be tricky...
Had also looked into your method (._node.click();) and I can't see no obvious difference comparing to simulate()...

How to make all buttons(even dynamically created) in an application follow jquery button widget without calling .button() multiple times

I am new to stack overflow and this is my first question. Pardon me for any mistakes.
This question is more generic but i tried to search for an answer but could not find it.
Say i have a page and i am using jquery ui button() widget for all the button. What happens is i have a specific class defined for all the buttons on my page. So i can just specify $('.myButtonClass').button(); but whenever i render partial views which has button again i have to do the same thing in the partial views. Is there any way i can globally specify a transition for button or any element for that matter.
Here is a sample Fiddle which adds buttons on click. But the added buttons are not transitions as button widgets(I do not want to use clone).
http://jsfiddle.net/wjxn8/
$('.clsTest').button().click(function(){
$(this).after('<input type="button" value="Added" class="clsTest"/>');
});
Is this possible without:-
1) Adding the css classes for a button widget manually for all the buttons created.
2) Tracking DOM Changes using Javascript and perform transitions for all the button elements.
Thanks for your help!!!
Since you were looking for something else, why not trigger a custom event when you load partials or whatever:
$('.clsTest').button().click(function(){
$(this).after('<input type="button" value="Added" class="clsTest"/>').trigger('addButtonUI');
});
$(document).bind('addButtonUI',function(){
$('.clsTest').button();
});
http://jsfiddle.net/wJXN8/3/
If you trigger your event and have the document listening for it, then you can do whatever you would like. I could have put in there the ability to add more buttons as well, but this should get the point across.
What you are asking for, some event when a button is added.... you would need to come up with that yourself and trigger it when a button is added. There is this: How to detect new element creation in jQuery? which talks about a specific event that is triggered when new elements are added to the DOM. Haven't tested it, and it looks like it may not work on IE.
I'm not a huge fan of this, but you could poll for new buttons. Check out my fork of your fiddle (that sounds funny):
http://jsfiddle.net/lbstr/Hq97H/
Using your example, this would look like:
setInterval(function(){
$('.clsTest').not('.ui-button').button();
}, 1000);
As I said, I'm not a huge fan of this. I understand the desire for something like $.live here, but I still think its better to initialize your new content when you add it. If you are making an ajax call for new content, just initialize it when you add it to the DOM.
My silly polling code and $.live (which is now deprecated) might be convenient, but they perform terribly. Just my two cents. You know your code better than I do!

Javascript performance ? - Put events in html tag, or bind them?

I'm wondering which is better for performance... I have a "web app" sort of thing. It has a lot of javascript. When a button is clicked, a hidden div becomes visible. This new div has 5 buttons. Which is better for performance:
1.) put the button click events in the html tag of each button like onClick="alert('hey');"
2.) Attach events to each button when the div is visible, and then remove the events when I hide the div containing the buttons?
The reason I ask is because I imagine the page might get bogged down if the events in the html tags are constantly there. I figure the page might be faster to only have those events when the user can see the buttons to click them.
Any help is great! Thanks!
I would use event delegation.
This way you can freely add/remove any buttons without worrying about attaching events on each one of them. This approach is also more memory efficient, since you always have one single event handler instead of N ones directly on each button.
Unless those events are causing something to act as a link (which it seems Google learned to read) the put all this JS outside your HTML. It makes your code tidier and more maintainable.
Can't be sure about performance.
Keeping the event handlers registered when the elements are hidden will have no impact on performance, since the events won't fire.
Whether to use HTML attributes or the DOM to register event handlers isn't a matter of performance, it's a matter of clean design. You'll want to keep presentation as separate from behavior as possible. This means that if you use attributes, they should only bind the event to a handler (i.e. call a single function) rather than contain more complex code. That is, don't:
<button onclick="if ('red'==this.parent.style.backgroundColor) {...}">...</button>
do:
<button onclick="clickColorButton(event)">...</button>

Dealing with Javascript events applicable only for certain content

I'm having trouble understanding conceptually what I should do while trying to make my first large Javascript web application.
Depending on which tab a user has selected, I show different content inside a container. The content is more than just text and uses different Javascript functions and events. I am using the Yahoo! UI Library's "TabView" implementation, but the way that this issue should be handled would probably apply to other Tab approaches.
What I was thinking of doing was basically the following:
Create separate modules for each tab (e.g. MYAPP.modules.tabCalendar and MYAPP.modules.tabJournal). When the user clicks on a different tab (or navigates with browser buttons to a previous tab state), I could call MYAPP.modules[oldModule].disable() and MYAPP.modules[newModules].enable(). These functions would subscribe or unsubscribe their custom events (for example, a general click handler attached to the container).
An alternate approach to dealing with events might be to have a single global click handler. If the click is inside the container, then determine which tab is currently selected and send the click event to MYAPP.modules[currentTab].onClick().
Or, the global click handler could fire a Custom Event to which the modules have subscribed since page load, and each module's onClick events will run and determine whether or not they should do anything.
There seem to be a lot of options, but I've been having trouble finding resources that talk about the best ways to do things like this. Am I on the right path? How should I handle this?
Use the events already built into TabView to queue your JS to do things.
http://developer.yahoo.com/yui/tabview/#handlingevents
For tab changes you'll be told the previous/next tabs selected and such which should be more than enough for your JS to figure out what it should do. If you want to write a translation layer that'll look at the events and do something based on it that's fine but it's not strictly necessary.
I'm a bit fuzzy on the problem.
Yes, you should modularize your code.
Have each module setup event handlers on the elements in their respective container.
That's it. YUI TabView handles the tab switching so you don't need to enable/disable anything.

Categories