I'm wondering if what should be done for GWT com.google.gwt.user.client.ui.FileUpload
to upload to server without refresh or forwarding.
I have implemented the Form upload from this Java Doc, however it forwards the browser page to the target server URL.
How can I implement a form upload without forwarding?
Update:
final FormPanel form = new FormPanel();
form.setAction("/upload");
form.setEncoding(FormPanel.ENCODING_MULTIPART);
form.setMethod(FormPanel.METHOD_POST);
VerticalPanel panel = new VerticalPanel();
form.setWidget(panel);
final TextBox tb = new TextBox();
tb.setName("textBoxFormElement");
panel.add(tb);
// Create a FileUpload widget.
FileUpload upload = new FileUpload();
upload.setName("uploadFormElement");
panel.add(upload);
DOM.getElementById("form_panel").appendChild(panel.getElement());
Button submit = new Button("Submit");
panel.add(submit);
DOM.sinkEvents(submit.getElement(), Event.ONCLICK);
DOM.setEventListener(submit.getElement(), new EventListener(){
#Override
public void onBrowserEvent(Event event) {
if (event.getTypeInt() == Event.ONCLICK) {
form.submit();
return;
}
}});
form.addSubmitHandler(new FormPanel.SubmitHandler() {
public void onSubmit(SubmitEvent event) {
if (tb.getText().length() == 0) {
Window.alert("The text box must not be empty");
event.cancel();
}
}
});
form.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
Window.alert(event.getResults());
}
});
IMO you are making things more complex than they are.
I don't understand why, if you are using widgets, you are trying to manage the DOM by hand.
1.- Attach your form panel to the root panel using GWT way, otherwise you are going to break widget hierarchy.
RootPanel.get("form_panel").add(panel);
2.- Try not to use sink-events by hand, and use methods already present in widgets:
submit.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
form.submit();
}
});
FormPanel sets its target to a hidden <iframe> so you will never be redirected to another page.
BTW, I'd rather use gwtupload library which simplifies so much uploading code in GWT, and adds a lot of additional features.
I used before gwt-upload library.
You dont need to rediscover America.
Thanks for moxie group
gwt-upload-project page
Related
I have a problem where Vaadin does not update the display of a GridLayout in time. The GridLayout is a component in a VerticalLayout, that I use to list all uploaded files. When I upload a file everything works fine on the server-side but the client does not see the change until he creates a new request to the server (by uploading another file or triggering some other event / rarely the update works fine though).
Here is the component that contains the problematic GridLayout:
public class ListedMultiFileUpload extends VerticalLayout {
private MultiFileUpload multiFileUpload;
private GridLayout fileList;
public ListedMultiFileUpload(UploadFinishedHandler uploadFinishedHandler, UploadStateWindow uploadStateWindow) {
multiFileUpload = new MultiFileUpload(uploadFinishedHandler, uploadStateWindow);
fileList = new GridLayout(2, 5);
fileList.setImmediate(true);
addComponents(multiFileUpload, fileList);
}
public SmartMultiUpload getSmartUpload() {
return multiFileUpload.getSmartUpload();
}
public void addFile(String fileName, final Runnable fileRemover) {
final Label label = new Label(fileName);
final Button button = new Button("X");
button.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
fileList.removeComponent(label);
fileList.removeComponent(button);
fileRemover.run();
}
});
fileList.addComponent(label);
fileList.addComponent(button);
markAsDirtyRecursive();
}
}
I already tried setting the GridLayout to immediate as well as marking the whole component as dirty but nothing seems to make a difference.
So basically am I doing something wrong here? Or if not, is there a "nice" way I could force the client to update its components?
As proposed by #Morfic I enabled the Server-Push addon in automatic mode and now the required updates to the client are made by that addon. Not sure how much I like that solution but it works.
Wicket AjaxSubmitLink onSubmit is not called after applying appendJavascript which changes the DOM of a page. Sample code is:
add(new ListView("list", someArrayList){
#Override
protected void populateItem(final ListItem item) {
add(new AjaxSubmitLink("link") {
#Override
public void onClick(AjaxRequestTarget target) {
target.appendJavascript("swap('"+this.getMarkupId()+"')");
});
})
The JavaScript looks like:
function swap(markupId){
var one = $('.dashed').first().parent();
var two = $('#'+markupId).parent();
var tone = one.clone();
var ttwo = two.clone();
one.replaceWith(ttwo);
two.replaceWith(tone);
}
Any suggestions?
It might be the clone() method causing the problem. According the documentation it does not clone event handlers. Try clone(true);
You could also handle the swap server side and then rerender the list after the swap. That would be the Wicket way to do it.
Question relates to Wicket 1.6
I have a wizard step, which includes a Textfield component. When I press the Enter key, this is being handled by the default button of the Wizard bar ('Next'), and it advances to the next step in the Wizard. I don't want this to happen. When I hit Enter on the Textfield I just want the value to be updated, but remain on the same page.
I tried overriding the onBeforeRender() method of my Wizard class, which as you can see sets the default button of the containing form to null. However this now results in the 'Prev' button being triggered when I hit Enter, so the wizard goes back to the previous step.
public class ConfigurationWizard extends Wizard {
....
#Override
protected void onBeforeRender()
{
super.onBeforeRender();
Component buttonBar = getForm().get(BUTTONS_ID);
if (buttonBar instanceof IDefaultButtonProvider)
{
getForm().setDefaultButton(null);
}
}
}
So the basic question is, how do I disable the default button behaviour of the Wizard?
My approach (with a nice Wicket behavior)
Usage
TextField<String> myField = new TextField<String>("myField", myModel());
myField.add(new PreventSubmitOnEnterBehavior());
Behavior
public class PreventSubmitOnEnterBehavior extends Behavior
{
private static final long serialVersionUID = 1496517082650792177L;
public PreventSubmitOnEnterBehavior()
{
}
#Override
public void bind( Component component )
{
super.bind( component );
component.add( AttributeModifier.replace( "onkeydown", Model.of( "if(event.keyCode == 13) {event.preventDefault();}" ) ) );
}
}
This has nothing to do with the wizard buttons.
The TextField <input> is doing a form submit when the Enter key is pressed. This is standard behaviour for the <input> element.
The solution is to catch the Enter key press for the <input> and prevent the default behaviour
This bit of javascript magic does the trick for me:
<script type="text/javascript">
$(document).ready(function() {
$("#gridDiv").delegate("input","keypress",function(e){
if(e.originalEvent.keyCode == 13){
e.preventDefault();
}
});
});
</script>
where 'gridDiv' is the id of the <div> containing the TextField
I prefer another approach:
I use AjaxButtons for every button needed, with the specific submit code in the overrided onSubmit():
AjaxButton linkSubmit = new AjaxButton("linkSubmit")
#Override
public void onSubmit(AjaxRequestTarget target, Form form) {
super.onSubmit();
// Submit code goes here....
// ...
setResponsePage(new NewPage());
}
#Override
public void onError(AjaxRequestTarget target, Form form) {
}
};
My form doesn't need a "onSubmit()" method.
And the markup doesn't have any submit buttons. All buttons are coded like this:
With this approach you don't need to mess with javascript codes. The page simply will do nothing if you press Enter. You'll have to click your buttons to submit each one.
Hope this can help you.
I am developing GWT application and I use
com.google.gwt.user.client.Window.open(pageUrl, "_blank", "");
to open new page. And it opens in a new tab when called, for example, directly after button click.
But I decided to do some validations on server before opening new page and placed the call to the mentioned above method to the
public void onSuccess(Object response) {
}
And it starts to open pages in new window instead of new tab (this is true only for Chrome, other browsers still open it in a new tab).
Can anybody help me?
I built a small example to illustrate the issue:
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
Window.open("http://www.google.com/", "_blank", "");
MySampleApplicationServiceAsync serviceAsync = GWT.create(MySampleApplicationService.class);
serviceAsync.getMessage("Hello, Server!", new AsyncCallback() {
public void onFailure(Throwable caught) {
Window.alert("ERROR");
}
public void onSuccess(Object result) {
Window.open("http://www.bing.com/", "_blank", "");
}
}
);
}
});
Firefox(3.6.8) opens both pages in new tabs.
Chrome(6.0) opens "google.com" in new tab and "bing.com" in new window
Opera(10.10) opens in new tabs.
IE(8.0) opens both in new Windows.
I marked igorbel 's answer as the only correct cos I haven't found any proper way to specify the same behaviour in all situations.
I used this code and it works for me in google chrome and mozilla firefox 3.6.8 browsers
If you want to open a page in new window you should write code as
Window.open("www.google.com","_blank","enabled");
If you want to open a page in new tab you should write code as
Window.open("www.google.com","_blank","");
I am not sure you are going to be able to control this the way you want. The problem is that browsers can decide when to open windows and when to open tabs. For example, firefox has the option: "Open new windows in new tabs instead". And don't forget the browsers that don't support tabs (yes, those do still exist).
Since this is such a problematic aspect of the user experience, my recommendation would be to reconsider your design. Is it really that important for you application to differentiate between opening a new tab and opening a new window?
This code works for me:
Before calling the Async method keep a reference to a new window with empty parameters.
At onSuccess() method set the URL of the window.
Button someButton = new Button("test");
SelectionListener<ButtonEvent> listener = new SelectionListener<ButtonEvent>()
{
public void componentSelected(ButtonEvent ce)
{
final JavaScriptObject window = newWindow("", "", "");
someService.doSomething(new AsyncCallback()
{
public void onSuccess(Object o)
{
setWindowTarget(window, "http://www.google.com/");
}
});
}
}
someButton.addSelectionListener(listener);
private static native JavaScriptObject newWindow(String url, String name, String features)/*-{
var window = $wnd.open(url, name, features);
return window;
}-*/;
private static native void setWindowTarget(JavaScriptObject window, String target)/*-{
window.location = target;
}-*/;
Found at:
http://groups.google.com/group/google-web-toolkit/browse_thread/thread/574b3b828271ba17
Interesting thing,
chrome will open page in new tab in case if you put window.open(...) instruction into the body of the click handler implementation.
For example:
Button someButton = new Button("test",
new ClickHandler() {
public void onClick(ClickEvent event) {
Window.open(...);
}
});
And a page will be opened in the separate window in case if I will include any Async. request into the mentioned code:
Button someButton = new Button("test",
new ClickHandler() {
public void onClick(ClickEvent event) {
someService.doSomething(new AsyncCallback() {
void onSuccess(Object o) {
Window.open(...);
}
...
});
}
});
The way Chrome looks at it, calling Window.open() is like trying to open a pop-up window in the user's face. That's frowned upon and will trigger the built-in pop-up blocker. Following a link, according to Chrome, should be the result of a user clicking on a good old anchor tag with an href attribute. But here lies the answer you're looking for: you can show a link to the user and change the link target on the fly. That would qualify as a 'proper' link in Chrome's world.
This code works for me:
public static native String getURL(String url)/*-{
return $wnd.open(url,
'target=_blank')
}-*/;
I am attempting to create a Google Web Toolkit (GWT) application that also uses Google Gears, but every time I try to remove the panel, I get an exception and the panel stays there.
Here is an excerpt from the exception I get (I've only included the relevant bits of the call stack, the rest just descends into the included function below):
java.lang.AssertionError: A widget that has an existing parent widget may not be added to the detach list
at com.google.gwt.user.client.ui.RootPanel.detachOnWindowClose(RootPanel.java:122)
at com.google.gwt.user.client.ui.RootPanel.get(RootPanel.java:197)
I'm not sure what the problem is, but I really don't like leaving the button there after they approve the use of Gears.
What am I doing wrong? Or any suggestions on a different way I could do this to make it work?
if(!gearsFactory.hasPermission()) {
HorizontalPanel rightPanel = new HorizontalPanel();
rightPanel.getElement().setId("gearsPrompt");
rightPanel.setVerticalAlignment(HorizontalPanel.ALIGN_MIDDLE);
rightPanel.setSpacing(0);
rightPanel.setHeight("28px");
InlineLabel enableGearsText = new InlineLabel("Enable Gears for off-line access");
enableGearsText.getElement().setId("gearsText");
enableGearsText.addStyleName("titleElement");
rightPanel.add(enableGearsText);
final Button gearsButton = new Button("Use Gears");
gearsButton.getElement().setId("gearsButton");
gearsButton.addStyleName("titleElement");
gearsButton.setHeight("24px");
gearsButton.addClickHandler( new ClickHandler() {
public void onClick(ClickEvent event) {
Factory gearsFactory = Factory.getInstance();
if(gearsFactory != null) {
if(gearsFactory.getPermission()) {
RootPanel gearsPrompt = RootPanel.get("gearsPrompt");
gearsPrompt.removeFromParent();
}
}
}
});
rightPanel.add(gearsButton);
RootPanel titleBarRight = RootPanel.get("titleBarRight");
titleBarRight.add(rightPanel);
}
One solution I've found is to loop through all of the widgets under the "titleBarRight" panel and remove all widgets it contains:
if(gearsFactory.getPermission()) {
RootPanel titleBarRight = RootPanel.get("titleBarRight");
java.util.Iterator<Widget> itr = titleBarRight.iterator();
while(itr.hasNext()) {
itr.next();
itr.remove();
}
}
But somehow this still seems hacky and not quite the "right way to do it."
I know this is old, but how about...
gearsButton.addClickHandler( new ClickHandler() {
public void onClick(ClickEvent event) {
Factory gearsFactory = Factory.getInstance();
if(gearsFactory != null) {
if(gearsFactory.getPermission()) {
Button btn=(Button) event.getSource();
btn.removeFromParent();
}
}
}
});
Is there any reason for using RootPanel.get("gearsPrompt").removeFromParent(); instead of your own rightPanel.removeFromParent();? The reference is already there.
You can do :
theParentWidget.remove(index);
and the first child corresponds to 0;