You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by Simon Kitching <sk...@obsidium.com> on 2005/11/29 01:55:04 UTC
Re: behavior of findComponent [or why forceId is a bad idea]
Dennis Byrne wrote:
> Have I misunderstood findComponent() this whole time?
>
> In JSP:
>
> <t:inputHidden
> forceId="true"
> id="id"
> value="#{siteCrudBacker.unit.id}" />
>
> In Java (finds the component w/ for loop, but can't find it
> w/ findComponent method):
>
> private void displayChildren(UIComponent ui){
> Iterator iterator = ui.getChildren().iterator();
> for(;iterator.hasNext();){
> UIComponent uiChild = (UIComponent) iterator.next();
> if("id".equals(uiChild.getId())){
> log.info(" child w/ id of ->" + uiChild.getId());
> UIComponent sameChild = FacesContext
> .getCurrentInstance()
> .getViewRoot().findComponent("id");
> if(sameChild == null)
> log.info("how can this be null?");
> }
> displayChildren(uiChild);
> } // end of for
> } // end of method
>
> In console:
>
> INFO SiteNumberValidator - child w/ id of ->id
> INFO SiteNumberValidator - how can this be null?
FindComponent works just like finding a file in a filesystem.
Given:
/home/someuser/foo/file.txt
/home/someuser/bar/file.txt
When current working dir = "/home/someuser/foo", the command "ls
file.txt" will show the first file.
When current working dir = "/home/someuser/bar", the command "ls
file.txt" will show the second file.
When current working dir is "/", the command will show no files. But "ls
foo/file.txt" will show it.
In your debugging, you're at some arbitrary base component and find that
there is a child with some particular id. Trying to then find that same
id by asking the viewroot for it won't work if there is any intervening
NamingContainer.
That's a fundamental flaw with "forceId"; it's a Tomahawk concept, not a
JSF concept. Character NamingContainer.SEPARATOR_CHAR (ie ":") functions
in exactly the same way as "/" in a file path, and NamingContainer
components are like directories.
Setting forceId will cause the renderer to output a particular id into
the generated page. And because "decoding" is done by asking each
component to inspect the input parameters it works for submitted data.
But because UIComponent.findComponent is part of the JSF spec, and the
JSF spec mandates that clientId values contain absolute paths from the
view root to the component it can quite reasonably look to see whether
the id provided has NamingContainer.SEPARATOR_CHAR in it, and if so
assume that there is no point in descending into any NamingContainer in
the search for that component.
The forceId concept is like a filesystem that does away with
directories. Imagine if "file.txt" was the same file, no matter where in
the directory path you are. "rm file.txt", "rm foo/file.txt", "rm
bar/baz/file.txt" would all affect the same file. Such a system would be
unmanageable because name conflicts would occur; you'd never know
whether a particular name was safe for use or not. And forceId is the
same; it makes it impossible to compose pages from fragments because the
namespacing feature of NamingContainer is ignored.
Of course for small pages where there is no attempt to "compose" the
page from parts the forceId approach can work. But bring in things like
Tiles or portlets and....hmm.
Corrections/rebuttals very welcome; if my argument is flawed I'm happy
to hear about it.
Regards,
Simon