eclipse-ee4j / mojarra

Mojarra, a Jakarta Faces implementation
Other
166 stars 112 forks source link

4.0.x: Cannot remove component dynamically from the tree #5522

Closed vonnai closed 1 month ago

vonnai commented 1 month ago

Describe the bug

It's not possible to dynamically remove component from the tree completely. Let me describe the problem. The method disconnectFromView of the class UIComponentBase has a small bug inside. Setting the flag inView to false at the beggining causes an issue in the StateContext - method handleRemove. HandleRemove method does always nothing, because inView is false.

As I see, you made some changes in this commit, but it doesn't work https://github.com/eclipse-ee4j/mojarra/commit/6fb231aff3a36288c4851bc69fda561e58bbb909, Now, the StateContext::handelRemove does always nothing.

So, is it possible to revert changes, or call setInView after the event?

4.0 branch

private static void disconnectFromView(FacesContext context, Application application, UIComponent component) {

        component.setInView(false);

        if (component.getChildCount() > 0) {
            List<UIComponent> children = component.getChildren();
            for (UIComponent c : children) {
                disconnectFromView(context, application, c);
            }
        }
        if (component.getFacetCount() > 0) {
            Map<String, UIComponent> facets = component.getFacets();
            for (UIComponent c : facets.values()) {
                disconnectFromView(context, application, c);
            }
        }

        application.publishEvent(context, PreRemoveFromViewEvent.class, component);
        component.compositeParent = null;
    }

original

private static void disconnectFromView(FacesContext context, Application application, UIComponent component) {

        application.publishEvent(context, PreRemoveFromViewEvent.class, component);
        component.setInView(false);
        component.compositeParent = null;
        if (component.getChildCount() > 0) {
            List<UIComponent> children = component.getChildren();
            for (UIComponent c : children) {
                disconnectFromView(context, application, c);
            }
        }
        if (component.getFacetCount() > 0) {
            Map<String, UIComponent> facets = component.getFacets();
            for (UIComponent c : facets.values()) {
                disconnectFromView(context, application, c);
            }
        }

    }

To Reproduce

Steps to reproduce the behavior:

  1. Add component c.getChildren().add(a)
  2. c.getChildren().remove(a)
  3. c.getChildren().add(a)
  4. Exception: the component cannot be added twice.

Desktop (please complete the following information):

BalusC commented 1 month ago

Reverted for 4.0.9, without replacement for now.

Thank you very much for reporting this. I'm frankly sad that the Faces TCK apparently didn't cover that. It does not seem to be as complete as I expected it to be.