I have a get with this weird thing in GWT
when i set my uibinder to the getBody().addpend() the event is not firing but it works when i use RootPanel.get().add(new p1()); works. Looks like its something to do with the way you add the uibinder to the page?
working event:: RootPanel.get().add(new p1());
not working:
Document.get().getBody().appendChild(new p1().getElement());`
the event handler looks:
not working event:: Document.get().getBody().appendChild(new p1().getElement());
not working event:: Document.get().getBody().appendChild(new p1().getElement());
#UiHandler ("bleh")
void handleClick(ClickEvent e)
if (lEntidad.getText().length()>1)
lEntidad.setText("");
I can't see all of your code to confirm this, but if you are adding widgets to your app using getElement(), then any events you add through gwt won't trickle through. There's special event logic GWT handle behind the scenes to make things work in a memory-leak safe environment.
Instead of using Document.appendChild(), you should be using whatever your parent widget is, or whatever the root of your ui.xml file is. For example, an HTLMPanel. Add your new widget directly to that, then your events on the widget should pass through.
Summary
Don't add elements if you have an event on the element. Add widgets instead. That solved the issue when I had it happen.
Related
I am doing a GWT application and speed tracer says that the painting process take a long time, so reading the pdf of the : Google 2010 - IO session ("Architecting for performance with GWT"), this sentence appear :
When should I use widgets?
When a component must receive events AND
There's no way to catch events in the parent widget
I agree with the first condition (I want to use widgets because my component, such as textBox or images must receive events, such as MouseOver, MouseClick...) but my question concern the second condition. Indeed I do not understand in which case there should be no way to catch event in the parent widget since it is ("always") possible to access to any element/component manipulating the DOM with Javascript. Here I am supposing that with Javascript I can access to the Widgets (identified with ui:field for example in ui:binder) element and the DOM elements (identified with id="").
So could you tell me why I am wrong or give me an example when "There's no way to catch events in the parent widget" ?
Thanks you,
It's more about "no easy way to put code that would catch events in the parent widget". It's all about componentization: you don't want to put event handling code outside your component, and you don't want to make your event handling code attach to elements outside your component. So components still are widgets, but inside them try to use HTML and event bubbling as much as possible.
In practice, that means using HTMLPanel (or RenderablePanel for better perfs, if you use 2.5.0 RC1 and you're a bit adventurous) inside composites, and otherwise using CellWidget (with UiRenderer to make it way easy to handle events bubbling from specific child elements)
We use MVP with custom EventBus to navigate across the views. One of our GWT module loads an ebook within a view. We have a button named "Expand", which upon clicked, loads the ebook in expanded mode thereby hiding the header, footer, etc.
Let us say the view (UiBinder) with "Expand" button is named as "ShowEbookView". Upon clicking "Expand" button, the ClickEvent is captured and fired to the EventBus. The logic onExpand(final ExpandEvent expandEvent) is written in the same "ShowExpandedMod" class.
Everything is okay, but we have a button named "Popout" in the expanded mode, which when clicked, should open the Ebook in a NEW page! We need to abstract the "ShowExpandedMod" class so that it can operate with the EbookId and can be used in the new page.
We have created a new Module with EntryPoint class, HTML page and UiBinder page for this new popout window. I am not sure how to proceed now with the abstraction and to use EventBus across different modules to load the same content ... (with re-usability ofcourse)
I've explained to my best, but perhaps not very clear! Please let me know if you want more details.
Thanks!
When you open a new window in browser you basically get a new instance of your GWT app. You can not use EventBus across different browser windows, i.e. across different GWT module instances.
What you can do is:
Add an argument to the Popout page URL. This is easies done via "history tokens" (fragment identifiers), like this http://yourdomain.com/popout.html#theIdOfTheDocument. Then you can retrieve the token via History.getToken()
Use DOM to communicate between browser windows: window.open() in javascript opens a new window and returns a reference to DOM of the new window. You can then access properties and functions of the new window. This is all javascript, in order to make this work in GWT you'll need to wrap it in JSNI.
Try and use MVP4G, in specific - take a look at their multi-modules feature (which utilizes GWT's code splitting capabilities).
This should make things like multiple EventBus's and cross-module event triggers a lot easier to handle.
I know there are some questions out there about the GWT ScrollPanel and how it works, but allow me to explain the situation.
I'm working on a project to implement QoS on routers. I'm now at the developping stage of the project and I need to make a webinterface to add protocols such as ssh and http and give them their bandwidth.
To save memory usage and network traffic, I do not use GWT-EXT or Smart GWT. So to set the bandwidths I use a ScrollPanel with an empty SimplePanel in it (which is way too big), leaving only the scrollbar.
Now here's the problem:
I want each scrollbar for each added protocol to start at the bottom, not the top. I can get it working through the code if I manually move the scrollbar first, then any function works, like a scrollToBottom(), or a setScrollPosition(). If I want to move scrollbars through code before moving the scrollbar manually, however, I can't call a function on it.
(I would post a picture but I can't yet - new user)
Summary:
So if I add a protocol (using a button called btnAjouter), the two slidebars (One for guaranteed bandwidth and one for the maximum bandwidth) for each protocol start at the top. I want them to start at the bottom on the load of the widget.
Is there a way to do this?
Thanks in advance!
Glenn
Okay, my colleage found the solution. It's a rather dirty one, though.
The thing is, the functions only work when the element in question is attached to the DOM. I did do a check with a Window.alert() to see if it was attached, and it was. But the prolem was that the functions were called to early, for example on a buttonclick it would've worked. The creation and attachment of the elements all happens very fast, so the Javascript can't keep up, this is the solution:
Timer t1 = new Timer()
{
#Override
public void run()
{
s1.getScroll().scrollToBottom();
s2.getScroll().scrollToBottom();
}
};
t1.schedule(20);
Using a timer isn't the most clean solution around, but it works. s1 and s2 are my custom slidebars, getScroll() gets the ScrollPanel attached to it.
You can extend ScrollPanel and override the onLoad method. This method is called immediately after a widget becomes attached to the browser's document.
#Override
protected void onLoad() {
scrollToBottom();
}
Could you attach a handler to listen to the add event and inside that handler do something like this:
panel.getElement().setScrollTop(panel.getElement().getScrollHeight());
"panel" is the panel that you add your protocol to. It doesn't have to be a ScrollPanel. An HTMLPanel will work.
You can wrap this method in a command and pass it to Schedule.scheduleDeferred if it needs to be called after the browser event loop returns:
Schedule.scheduleDeferred(new Scheduler.ScheduledCommand(
public void execute() {
panel.getElement().setScrollTop(panel.getElement().getScrollHeight());
}
));
As we are facing GWT performance issues in a mobile app I peeked into Google Wave code since it is developed with GWT.
I thought that all the buttons there are widgets but if you look into generated HTML with firebug you see no onclick attribute set on clickable divs. I wonder how they achieve it having an element that issues click or mousedown events and seemingly neither being a widget nor injected with onclick attribute.
Being able to create such components would surely take me one step further to optimizing performance.
Thanks.
ps: wasnt google going to open source client code too. Have not been able to find it.
You don't have to put an onclick attribute on the HTML to make it have an onclick handler. This is a very simple example:
<div id="mydiv">Regular old div</div>
Then in script:
document.getElementById('mydiv').onclick = function() {
alert('hello!');
}
They wouldn't set the onclick property directly, it would have been set in the GWT code or via another Javascript library.
The GWT documentation shows how to create handlers within a GWT Java app:
public void anonClickHandlerExample() {
Button b = new Button("Click Me");
b.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
// handle the click event
}
});
}
This will generate an HTML element and bind a click handler to it. However, in practice this has the same result as using document.getElementById('element').onclick() on an existing element in your page.
You can hook functions to the onclick event using JavaScript. Here's an example using jQuery:
$(document).ready(function(){
$("#div-id").click(function(){
/* Do something */
});
});
If you're interested in optimizing performance around this, you may need to investigate event delegation, depending on your situation.
A click event is generated for every DOM element within the Body. The event travels from the Body down to the element clicked (unless you are using Internet Explorer), hits the element clicked, and then bubbles back up. The event can be captured either through DOM element attributes, event handlers in the javascript, or attributes at any of the parent levels (the bubbling or capturing event triggers this).
I'd imagine they've just set it in a .js file.
Easily done with say jQuery with $(document).ready() for example.
I've been working with Zend Framework (using Doctrine as the ORM) for quite a while now, and done a few projects with it.
In a few upcoming projects I am requiring the need for widgets similar to how Wordpress does them. You have a post/page, which could look like:
Subscribe to my newsletter:
[subscribe/]
View my events
[events limit=5 sort=date/]
View this page's comments
[comments/]
Where say the subscribe widget would be replaced with Blog::subscribeWidget, and the events could be replaced with Events::eventsWidget, etc.
Now it has done my head in the past few weeks about how on earth do I do this??? I've come up with the following options:
I could place the widgets within controllers, and then call them like actions. Problem here is that code could be flying between controllers, and I have read this is expensive due to the amount of dispatches.
I could place the widgets as view helpers. So within the view I could have $this->renderPage($Page), which would then attend to all the widgets. Problem here is that what if the widgets need to do some business logic, like for example posting a new comment, that really shouldn't be within the view, should it?
The other option is to place widgets within the model? But then how on earth do they then render content for display?
Extra complications come when:
Say the comments widget would also handle posting, deleting of comments etc.
Say for the events listing, if I want to do an ajax request to the next page of events, using method #2 (view helpers) how would this work?
If I understand you correctly your widgets will need their own action controllers, which is where their logic for fetching data to be displayed, parsing form submissions, etc. should go. The difference between a widget and a page in this case is in how it's rendered, i.e. as an HTML fragment instead of as a whole page; you can use the Action View Helper to achieve this.
If your widget includes a form it should probably use AJAX to submit the form data back to the server, so that using the widget doesn't cause the user to accidentally navigate away from the page. You can inject the required JavaScript into the page you've included the widget into by using the Head Script Helper in your widget's view and/or action.
I left Richards reply, the problem, and further use cases cook in my brain for a while longer and ended up coming to a solution.
I will have the following view helpers and methods:
Content; with methods: render, renderWidgets, renderWidget, renderCommentsWidget (comments).
Event; with methods: renderEventsWidget (many events), renderEventWidget (one event)
Subscription; with methods: renderSubscribeWidget (subscription form).
I will have inside my configuration file:
app.widgets.comments.helper = content
app.widgets.subscribe.helper = subscription
app.widgets.events.helper = event
I will also have the following models:
Content for use for all pages.
Event for use for all events.
Subcriber for use for subscriptions to content
So inside my view I will do something like this:
echo $this->content()->render($this->Content)
Content::render() will then perform any content rendering and then perform rendering of the widgets by passing along to Content::renderWidgets(). Here we will use the configuration of app.widgets to link together the widget bbcode tag to it's appropriate view helper (using the naming convention 'render'.ucfirst($tag).'Widget'). So for example Content::renderCommentsWidget() would then proceed to render the comments.
Perhaps later on I will decide to have a Widget View Helper, and individual view helpers for each widget eg. ContentCommentsWidget View Helper. But for now that would just add additional unrequired complexity.
Now to answer the AJAX problem I mentioned. Say for the comments widget allowing for comments to be posted via ajax. It would simply have an appropriate method inside the Content Controller for it. So pretty much we also have a Event and Subscription controllers too - corresponding with the view helpers. Interaction between the view helper and controller will all be hard coded, there is no purpose for it to be soft coded.
I hope this helps someone else, and the current plan is to make the project where all this is used to be an open-source project. So maybe one day you can see it all in action.
Thanks.
Update:
You can find the source code of these ideas in action in the following repositories:
BalCMS - this is the actual CMS which contains the widgets in /application/modules/balcms/view/helpers and contains the configuration in /application/modules/config/application/balcms.yaml
BalPHP - this is the resource library which contains the widget view helper at /lib/Bal/View/Helper/Widget.php