I'm trying to integrate TinyMCE into my GWT app and am having problems
with setting and getting ids for my textarea.
TinyMCE works by calling tinyMCE.init() in Javascript, and it goes and
find all of the textareas on your page and turns them into editor
panes. However, this doesn't really work in a dynamic webpage (as with
my GWT app) as the textarea isn't actually created until some time
after you've called init.
Anyway, this can be solved by the use of the next line of Javascript
code:
tinyMCE.execCommand('mceAddControl', true, id);
This means I need to set an id to my textarea. Now, I've done that
through DOM.setAttribute, however, if I follow that up with
DOM.getElementById, I get a null response.
I've attached my JournalEditor class below:
package foo;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.TextArea;
public class JournalEditor extends Composite {
private TextArea ta;
private VerticalPanel panel = new VerticalPanel();
public JournalEditor(String id) {
super();
setWidget(panel);
ta = new TextArea();
ta.setCharacterWidth(65);
ta.setVisibleLines(20);
panel.add(ta);
Window.alert(ta.getElement() + " was the element");
DOM.setAttribute(ta.getElement(), "id", id);
Window.alert(DOM.getElementById(id) + "");
}
}
Can anyone give me a clue as to where I've gone wrong?
Thanks in advance,
Aaron Watkins
----------------------
My Site: http://www.goannatravel.com
My (Test) GWT Page: http://www.goannatravel.com/test/goanna
Override onLoad() and try getting it in there -- in fact you *might*
need to wait for onLoad to set it, but I don't know.
Tom
- I've created an EditorArea object, which subclasses TextArea.
- I now override onLoad (Note: I've tried putting the setAttribute in
the onload as well, but to no avail)
See below:
/*
* Created on 29/05/2006
*/
package org.goannatravel.client;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.TextArea;
public class EditorArea extends TextArea {
private String id;
public EditorArea() {
super();
id = HTMLPanel.createUniqueId();
Window.alert(getElement() + " was the element");
DOM.setAttribute(getElement(), "id", id);
Window.alert(getElement() + " was the element");
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.Widget#onLoad()
*/
protected void onLoad() {
super.onLoad();
Window.alert(DOM.getElementById(id) + " 1");
// setTextAreaToTinyMCE(id);
}
private native void setTextAreaToTinyMCE(String id) /*-{
tinyMCE.execCommand('mceAddControl', true, id);
}-*/;
}
Both alerts that include getElement output the html for the textarea,
the second one with an id set. However, the DOM.getElementById still
returns null.
Interestingly, I noticed that the second alert showed that the id
definition was similar to:
id=HTMLPanel_1
Following Scott's suggestion from
http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/a9db30ead8db9a84/2b6281e2c342e85e?q=getelementbyid&rnum=4#2b6281e2c342e85e
I put quotes around my id:
DOM.setAttribute(getElement(), "id", "'" + id + "'");
This only meant that the definition was now:
id="'HTMLPanel_1'" (note the inclusion of the single quotes
inside the double quotes)
And the getElementById still returns null....
Any other suggestions?
Aaron
On further investigation I have the same problem, and worked around it
by passing the element directly to where it was needed -- you could try
the same thing with tinyMCE, calling
tinyMCE.addMCEControl(tinyMCE._getElementById(value), value);
directly and passing in your element in place of
'tinyMCE._getElementById(value)'.
Apologies for the misdirection.
Tom
Thanks for your help so far. Unfortunately, it's not quite that simple
with tinyMCE. I made the change below:
protected void onLoad() {
super.onLoad();
//Window.alert(DOM.getElementById(id) + " 1");
setTextAreaToTinyMCE(getElement(), id);
}
private native void setTextAreaToTinyMCE(Element e, String id) /*-{
alert(e);
alert(e.id);
alert(document.getElementById(e.id));
$wnd.tinyMCE.addMCEControl(e, e.id);
}-*/;
Passing the element directly in was useful and got me past a bunch of
problems. However, further down in the function, tinyMCE does a
document.getElementById on the id you pass in and unless I was to
change the entire codebase, I'm not going to be able to get past this.
The thing that is really confusing me is the result of those 3 alerts.
1. Output => [object] . Obviously, the element
2. Output => HTMLPanel_1. This is the actual id I set to the element.
So it appears that the id is set correctly.
3. Output => null.
So we can see that DOM.getElementById (in Java) and
document.getElementById (in Javascript) (and also
$wnd.document.getElementById) both return null. However, the id is
actually being set to the object and since I can pass e into the JSNI
function, it must appear in the DOM.
Another possibility... I tried:
e.id = "foo";
alert(document.getElementById("foo"));
and that's still null...
Do you have any last ideas Tom? Anyone else? Anyway, if I manage to
solve this, I'll be sure to put it up here, but it really seems like
some buggy behaviour... Where is the element?
Aaron
The Firefox DOM Inspector can't find my TextArea either!
Aaron
ie.
private native void setTextAreaToTinyMCE(Element e, String id) /*-{
$wnd.foo = e;
alert($wnd.foo.id);
alert(document.getElementById($wnd.foo.id));
$wnd.tinyMCE.addMCEControl($wnd.foo, $wnd.foo.id);
}-*/;
alert results area as before.
Aaron
It looks like you were right in the first place.
At the point at which I was trying to get it, the element didn't exist.
It looks like even at onLoad(), it didn't exist. In fact, I had to add
a DeferredCommand to finally get it to work.
Working code:
protected void onLoad() {
super.onLoad();
DeferredCommand.add(new Command() {
public void execute() {
DOM.getElementById(id); // <-- Returns the element
}
});
}
Finally!
Thanks for your help,
Aaron
I would not say I was right! It would be nice to have more
dicumentation about the lifecycle of components.
Thanks for persisting with this -- your solution will be useful for me
too.
Tom
It was very interesting excercise. Could you please post the complete
working code for the widget?
Thanks.
final TextArea ta = new TextArea();
final String id = "idx";
DOM.setAttribute(ta.getElement(), "id", id);
//Window.alert(ta.getElement() + "");
DeferredCommand.add(new Command() {
public void execute() {
//Window.alert(ta.getElement() + ""); // <-- Returns
the element
Window.alert(DOM.getElementById(id) + "");
}
});
but still null, but DOM.getAttribute(ta.getElement(), "id") return
"idx" (in execute method), still need more investigate
BUT, after final try, my last hope is put ta into panel
"panel.add(ta);" IT WORK, not return null anymore.
my working code is:
public class XXX extends Composite{
private VerticalPanel panel = new VerticalPanel();
public XXX(){
super();
setWidget(panel);
}
public void onLoad(){
super.onLoad();
final TextArea ta = new TextArea();
panel.add(ta);// <----- WORKING CODE FOR ME
Create the TextArea and set it's id in the constructor.
Execute the DeferredCommand in the onLoad.
Cheers,
Aaron