2009-07-16 11 views
11

Tôi đang viết một ứng dụng GWT liên quan đến việc tương tác với một tài liệu bên ngoài trong khung nội tuyến. Như một bằng chứng về khái niệm, tôi đang cố gắng đính kèm một trình xử lý nhấp chuột vào một nút.Gắn một sự kiện GWT vào một phần tử trong khung nội tuyến ngoài

Các tác phẩm sau đây trong javascript

var iframe = document.getElementById("rawJSIFrame"); 
var doc = iframe.contentDocument; 
var body = doc.body; 
var button = doc.getElementsByTagName("input").namedItem("submit"); 
button.onclick = function() { 
    alert("Clicked!"); 
}; 

Đang cố gắng để làm tương đương trong GWT, tôi đã làm như sau:

public void addClickHandlerToSubmitButton(String buttonElementName, ClickHandler clickHandler) { 
    IFrameElement iframe = IFrameElement.as(frame.getElement()); 
    Document frameDocument = getIFrameDocument(iframe); 
    if (frameDocument != null) { 
     Element buttonElement = finder(frameDocument).tag("input").name(buttonElementName).findOne(); 
     ElementWrapper wrapper = new ElementWrapper(buttonElement); 
     HandlerRegistration handlerRegistration = wrapper.addClickHandler(clickHandler); 
    } 
} 

private native Document getIFrameDocument(IFrameElement iframe)/*-{ 
     return iframe.contentDocument; 
}-*/; 

Sau đây là lớp ElementWrapper:

public class ElementWrapper extends Widget implements HasClickHandlers { 

    public ElementWrapper(Element theElement) { 
     setElement(theElement); 
    } 

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


} 

Mã để tìm nút hoạt động tốt nhưng trình xử lý sự kiện nhấp chuột thực tế không được gọi. Có ai đã có một vấn đề tương tự trước đây, và làm thế nào bạn giải quyết nó?

Cảm ơn trước,

Tín

Trả lời

10

Hilbrand là đúng về vấn đề này là rằng phương pháp GWT onAttach() không được gọi.

tôi thực hiện giải pháp ban đầu của bạn, thêm các phương pháp sau đây để ElementWrapper:

public void onAttach() { 
    super.onAttach(); 
    } 

Và gọi thêm wrapper.onAttach() sau ElementWrapper được tạo ra. Làm việc như một say mê!

+0

Cảm ơn bạn! Tôi biết phải có một cách sạch hơn :) – triggerNZ

0

Bạn có thể sử dụng để tái sử dụng JSNI mảnh JavaScript của bạn mã. Mã javascript của bạn sẽ gọi một phương thức gwt trên một đối tượng sẽ ném nó thay mặt cho nút trong khung nội tuyến.

Vì sao mã GWT không hoạt động - tôi đoán đó là vì chúng sử dụng một số lớp trên các sự kiện trình duyệt thông thường có thể không thể mở rộng quá 1 khung. Đó chỉ là một đoán mặc dù. Bạn có thể gửi yêu cầu tính năng/lỗi này một lần nữa cho nhóm GWT. Nếu tôi đúng mã của bạn có vẻ tốt.

+0

Thật tuyệt, cảm ơn bạn đã trả lời. Tôi đoán tôi sẽ khám phá con đường JSNI, mặc dù tôi muốn tránh xa việc viết javascript tùy chỉnh càng nhiều càng tốt. – triggerNZ

1

Sau khi nghiên cứu thêm về điều này, tôi thấy rằng iframe không liên quan. Hành vi tương tự không hoạt động trên một nút bình thường trên trang chủ.

Tôi về cơ bản đã sửa nó bằng cách sử dụng JSNI để tái tạo một phần cơ chế xử lý sự kiện của GWT. Các công trình sau đây:

Element buttonElement = DOM.getElementById("externalButton"); 
new CustomElementWrapper(buttonElement).addClickHandler(new ClickHandler() { 
public void onClick(ClickEvent event) { 
     Window.alert("GWT hooked into button"); 
    } 
}); 

đâu CustomElementWrapper là:

public class CustomElementWrapper extends Widget implements HasClickHandlers { 
    private ClickEventManager clickEventManager; 

    public CustomElementWrapper(Element theElement) { 
     setElement(theElement); 
     clickEventManager = new ClickEventManager(theElement); 
    } 

    public HandlerRegistration addClickHandler(ClickHandler handler) { 
     //The 'right' way of doing this would be the code below. However, this doesn't work 
     // A bug in GWT? 
     //  
     //    return addDomHandler(handler, ClickEvent.getType()); 
     return clickEventManager.registerClickHandler(handler); 
    } 


    void invokeClickHandler() { 
     clickEventManager.invokeClickHandler(); 
    } 

    public boolean isClickHandlerRegistered() { 
     return clickEventManager.isClickHandlerRegistered(); 
    } 
} 

Cuối cùng, ClickEventManager, nơi mà các công việc thực tế xảy ra là:

public class ClickEventManager { 
private boolean clickHandlerRegistered = false; 
private ClickHandler clickHandler; 
private Element element; 

public ClickEventManager(Element element) { 
    this.element = element; 
} 

public void invokeClickHandler() { 
    //This shouldn't really be null but we are bypassing GWT's native event mechanism 
    //so we can't create an event 
    clickHandler.onClick(null); 
} 

public boolean isClickHandlerRegistered() { 
    return clickHandlerRegistered; 
} 

HandlerRegistration registerClickHandler(ClickHandler handler) { 
    clickHandler = handler; 

    if (!clickHandlerRegistered) { 
     registerClickHandlerInJS(element); 
     clickHandlerRegistered = true; 
    } 
    return new HandlerRegistration() { 
     public void removeHandler() { 
      //For now, we don't support the removal of handlers 
      throw new UnsupportedOperationException(); 
     } 
    }; 
} 
private native void registerClickHandlerInJS(Element element)/*-{ 
    element.__clickManager = this; 
    element.onclick 
     = function() { 
      var cm = this.__clickManager; 
      [email protected]::invokeClickHandler()(); 
     } 
}-*/; 
} 

Cá nhân, tôi ghét giải pháp này bởi vì tôi xuất hiện để nhân đôi sự kiện xử lý sự kiện của GWT và có thể giới thiệu các rò rỉ bộ nhớ javascript khó chịu. Bất kỳ ý tưởng nào về lý do tại sao bài đăng đầu tiên của tôi không hoạt động (nhớ rằng khía cạnh iframe là một cá trích đỏ), sẽ được đánh giá cao.

Cảm ơn,

Tín

+0

Cảm ơn bạn, cảm ơn bạn! Đây chính xác là những gì tôi cần để làm cho nó hoạt động trong IE7! – SorcyCat

4

Tôi hy vọng vấn đề là phương pháp GWT onAttach() không được gọi khi bạn sử dụng các gói như trong ví dụ đầu tiên của bạn. Bạn có thể thử sử dụng phương thức tĩnh wrap trên tiện ích Nút. Mặc dù sử dụng số input này phải thuộc loại button. Hoặc có một cái nhìn tại việc thực hiện các phương pháp wrap.Đây là mã sửa đổi khi sử dụng phương pháp wrap:

Element buttonElement = finder(frameDocument).tag("input").name(buttonElementName).findOne(); 
Button button = Button.wrap(buttonElement); 
HandlerRegistration handlerRegistration = button.addClickHandler(clickHandler); 
0

Vui lòng xem câu trả lời trước của tôi. Một sửa đổi nhỏ cho giải pháp ban đầu của bạn sẽ làm cho nó hoạt động.

1

Bạn có thể tìm thấy điều này hữu ích:

import com.google.gwt.dom.client.Element; 
import com.google.gwt.event.dom.client.ClickEvent; 
import com.google.gwt.event.dom.client.ClickHandler; 
import com.google.gwt.event.dom.client.HasClickHandlers; 
import com.google.gwt.event.shared.HandlerRegistration; 
import com.google.gwt.user.client.ui.AbsolutePanel; 

public class DirectPanel extends AbsolutePanel implements HasClickHandlers { 
     public DirectPanel(Element elem) { 
       super(elem.<com.google.gwt.user.client.Element> cast()); 
       onAttach(); 
     } 

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

Sau đó bạn sẽ có thể làm cho container tùy vào thùng chứa phụ tùng:

Element root = Document.get().getElementById("target"); 
    DirectPanel p = new DirectPanel(root); 
    Button register = new Button("Register"); 
    register.addClickHandler(new ClickHandler() { 
    @Override 
    public void onClick(ClickEvent event) { 
     // ... 
    } 
    }); 
    p.add(register); 

Và kết các sự kiện để các thành phần tùy ý:

Element root = Document.get().getElementById("target"); 
    DirectPanel p = new DirectPanel(root); 
    p.addClickHandler(new ClickHandler() { 
    @Override 
    public void onClick(ClickEvent event) { 
     // ... 
    } 
    }); 

Cụ thể trong trường hợp của bạn, hãy thử cách này:

IFrameElement frm = Document.get().createIFrameElement(); 
Document d = frm.getContentDocument(); 
NodeList<Element> inputs = d.getElementsByTagName("input"); 
InputElement target = null; 
for(int i = 0; i < inputs.getLength(); ++i) { 
    Element e = inputs.getItem(0); 
    if (e.getNodeName().equals("submit")) { 
    target = InputElement.as(e); 
    break; 
    } 
} 
if (target != null) { 
    DirectPanel p = new DirectPanel(target); 
    p.addClickHandler(new ClickHandler() { 
    @Override 
    public void onClick(ClickEvent event) { 
     // TODO Auto-generated method stub 
    } 
    }); 
} 

Nó luôn làm tôi băn khoăn rằng GWT làm việc này rất khó khăn và kém tài liệu.

1

Thay vì sử dụng iframe, tôi khuyên bạn chỉ cần thực hiện yêu cầu http từ GWT qua com.google.gwt.http.client.RequestBuilder. Giống như vậy:

private void getHtml(String url) { 
     RequestBuilder rb = new RequestBuilder(RequestBuilder.GET, url); 

     rb.setCallback(new RequestCallback() { 

      @Override 
      public void onResponseReceived(Request request, Response response) { 
       HTMLPanel html = new HTMLPanel(response.getText()); 

       // Now you have a widget with the requested page 
       // thus you may do whatever you want with it. 
      } 

      @Override 
      public void onError(Request request, Throwable exception) { 
       Log.error("error " + exception); 
      } 
     }); 

     try { 
      rb.send(); 
     } catch (RequestException e) { 
      Log.error("error " + e); 
     } 
    }