views:

257

answers:

3

Hello,

I'm trying to get jquery to do some ui affects for me while using GWT. I have notifications that I add to a page that when clicked should disappear. Since there could be multiple notifications of the same type (warning, error, etc.) I'm trying to dynamically add a style name only when they are clicked through GWT and then have jquery act on that particular class name.

The problem is that the jquery function is firing before the style name can be added so the user has to click the notification twice in order for it to close.

Any ideas?

  public abstract class AbstractNotificationWidget extends Composite implements ClickHandler, HasClickHandlers {

  protected abstract String getUniqueId();

  @Override
  public HandlerRegistration addClickHandler(ClickHandler handler) {
    return addDomHandler(handler, ClickEvent.getType());
  }

  @Override
  public void onClick(ClickEvent event) {
    doClick(getUniqueId());
  }

  protected static native void doClick(String name) /*-{
    $wnd.$("#" + name).click(function () {
      $wnd.$(this).slideUp("slow");
      $wnd.$("div", this).fadeOut("slow");
      });
  }-*/;

}

I then have subclasses that extend the above class

public class ErrorNotificationWidget extends AbstractNotificationWidget {

  private final String uniqueId;

  public ErrorNotificationWidget (String title, String message) {
    uniqueId = DOM.createUniqueId();

    initWidget(uiBinder.createAndBindUi(this));

    this.getElement().setId(uniqueId);

    this.addClickHandler(this);
  }
  @Override
  protected String getUniqueId() {
    return this.uniqueId;
  }

These subclasses use the UIBinder to determine how they should be drawn. Then these widgets get added to a panel to be displayed.

+1  A: 

Maybe you should try GWTQuery http://code.google.com/p/gwtquery/ instead try to integrate it natively.

malte
A: 

Add a class to the element which you want to close on click, i.e.

<div class="close-on-click">Content</div>

Your javascript can auto-bind the function for any existing or dynamically created elements that match the selector:

$('.close-on-click').live('click', function() {
  $(this).remove();
});
fullware
This is essentially what I'm trying to do except I can't hard code "close-on-click" in the ui.xml because then every instance of that widget would get the same class name and would close when any one of them was clicked.Thanks for the response though.
Josh
If the link is within the element you want to close, try this:$('a.close').live('click', function() { $(this).parents('.class-to-close:first').remove();});
fullware
+1  A: 

What are you exactly trying to achieve? Hide the widget based on the styles it has applied or it's id? (in the current version it seems you're mixing one with the other)

If the ClickEvent is firing to fast (which can be tested by adding a timeout before it), you can try wrapping it in a DeferredCommand.

The other possibility is that jQuery is crapping up ;) I had some weird issues when using callbacks in jQuery/Mootools - the reason was that these frameworks extend/change function() (among other things) - however, JSNI stuff is executed from a "clean" iframe, where there are no changes made by jQuery (that's why you have to reference to the main window via $wnd). You can test if this is the issue here by defining, for example, a test function in your host HTML page and then passing it as the callback function in your void doClick(String name) method:

protected static native void doClick(String name) /*-{
  $wnd.$("." + name).click($wnd.jqueryTest); // BTW, why '"." + '?
}-*/;

And my initial suggestion still holds - use FocusPanel as your main widget - trying to correctly implement HasClickHandlers (and similar interfaces) is a PITA from my experience and can lead to weird bugs and/or memory leaks.

Igor Klimer
I want to create lots of notfications and be able to close them individually. If I give them all the same DOM class name jquery will close all of them. When you call addStyleName(name) in gwt it adds the name to the DOM class of that element. The "." + name is so jquery pulls the name (.gwt-12-whatever) instead of ".name". I appreciate the suggestion to use a FocusPanel but I can't do that. I need it to be a Composite. Also I don't believe it's speed of anything anymore as even when I create the name on initialization, way before it's clicked, I still have to click twice.
Josh
You misunderstood me about the `FocusPanel` - I wanted you to use it as your root/main panel in your UiBinder template (bound to the particular notification widget). Then you could just simply call `focusPanel.addClickHandler(whatever)` (instead of implementing `HasClickHandlers` yourself, etc). About the style names - instead of searching for an element by it's style names, it should be faster (and less error prone) to do it by id - since there shouldn't be an element with the same id twice in the DOM (that's why I recommended using `DOM.createUniqueId`).
Igor Klimer
How does one add an id through gwt? I only know of the function addStyleName() which adds to the DOM class.
Josh
I think you should be able to do it via UiBinder in the template (I'm sure it works fine for HTML tags, but I'm not so sure about GWT Widgets), but I usually do it on the class side via `someWidget.getElement().setId(id)`, where `someWidget` is either your main widget (the root widget in UiBinder's template or the widget/panel you pass to `initWidget`) or just `this` - either way should work.
Igor Klimer
Thanks, that is nicer to add it as an id instead of a class. The two click issue persists however. I see what you mean about the FlowPanel. Though the code to add a click handler is really straight forward (return addDomHandler(handler, ClickEvent.getType());)
Josh
Well that did it. I wrapped the HTMLPanel I was using inside of a FlowPanel and added the handler to that and it's working with a single click. Still don't understand how or why but at least it's working.Thanks!!
Josh
Great to know you got it working :)
Igor Klimer