0 Replies Latest reply on Oct 8, 2008 11:24 AM by Andrew Hart

    Suggestions Pls [Dynamically creating rich:tab components, b

    Andrew Hart Newbie

      Please bear with me on the lengthy problem description. This has been an uphill struggle and I need a breakthrough.

      I have a backing bean used to manage the editing of an object S. In this object, S, I have a list of "service" objects, and in each of these service objects, I have a list of "layer" objects.

      So, I have a modal panel where S objects are added or edited. On this particular page, I have an input field where the user can enter a URL that points to a WMS (GIS mapping) service along with a button. They enter a URL and click the button. I then go and obtain the XML document from the WMS service that describes the available layers in the service. If this succeeds, I construct a new service object, add it to the list of service objects in S, and then dynamically construct a tab to display information about it. This tab contains the title of the WMS service and then lists all of the layers along with a checkbox where the user can select which of the layers they want to to use.

      So, initially, I started out trying to dynamically build this dynamic richtab using iterate or repeat tags nested inside the rich:tabPanel where I would dynamically create tabs for each service object in the list contained in S, and then inside each tab I would iterate through the list of layers outputting a line describing the layer. This didn't work. I finally got it to the point where no errors were generated, but it just didn't do anything. I was stumped by this.

      So, then I decided on a different approach: in the xhtml page I have a panelGrid tag that binds to a panelGrid in a session backing object. So, when the user clicks the button they invoke a method that discovers the service, populates the service list in the S object, and then dynamically builds the entire rich:tabPanel adding tabs for each service listed in S, and outputting a line for each layer listed inside the service. OK, it took a while, but it seems to work. Howerver, now my problem is I can't figure out how to bind the checkbox to a boolean in the layer object so that the user can check off which layers they want. I'm trying to create a valueExpression pointing to boolean attribute in the layer object. I finally have it to the point where no errors are generated, but it doesn't seem to work. I'm not sure if the EL expression I'm trying to create is of the correct form. I'm dumping the ValueExpressions created and they look like this:

      The Value Expression is: ValueExpression[#{manager.s.serverList.get(0).layers.get(0).selected}]
      The Value Expression is: ValueExpression[#{manager.s.serverList.get(0).layers.get(1).selected}]
      The Value Expression is: ValueExpression[#{manager.s.serverList.get(0).layers.get(2).selected}]
      [...]
      The Value Expression is: ValueExpression[#{manager.s.serverList.get(0).layers.get(11).selected}]


      I can see the check boxes created in the output HTML, but since I'm dynamically creating these, it's like flying blind; I don't know of any way to see what I'm creating before faces renders it into HTML.

      The Java code looks like this:

      /**
       * This function is used to dynamically build the tab panels that appear in the
       * richtab component that is placed in the UiState serverPanelGrid.
       *
       * @param server
       * @return
       */
      public HtmlTab buildServerTab(int serviceNumber, WMSServer server) {
       System.out.println("UiState.buildServerTab");
      
       FacesContext context = FacesContext.getCurrentInstance();
       Application application = context.getApplication();
      
       String tabTitle = "Server # " + (serviceNumber + 1);
       // create the new tab component
       HtmlTab tab = (HtmlTab)application.createComponent(HtmlTab.COMPONENT_TYPE);
       tab.setLabel(tabTitle);
      
       // put an outermost panelGrid in it to establish a scrolling pane
       HtmlPanelGrid panelGrid = (HtmlPanelGrid)application.createComponent(HtmlPanelGrid.COMPONENT_TYPE); panelGrid.setStyle("layout:block; margin:0px; padding:0px; width:100%; height:100%;");
       panelGrid.setColumns(1);
      
       // Create the server name and add it to panel
       HtmlOutputText serverNameText = new HtmlOutputText();
       serverNameText.setValue(server.getTitle());
       panelGrid.getChildren().add(serverNameText);
      
       // Put a separator in between the server name and the list of layers...
       HtmlSeparator separator = new HtmlSeparator();
       panelGrid.getChildren().add(separator);
      
       // put an outermost panelGrid in it to establish a scrolling pane...
       HtmlPanelGrid layerPanelGrid = (HtmlPanelGrid)application.createComponent(HtmlPanelGrid.COMPONENT_TYPE); // new HtmlPanelGrid();
       layerPanelGrid.setBorder(1);
       layerPanelGrid.setColumns(3);
       layerPanelGrid.setStyle("layout:block; margin:0px; padding:0px; width:100%; height:200px; overflow:auto!important;");
      
       HtmlOutputText selectLabel = new HtmlOutputText();
       selectLabel.setValue("Select");
       HtmlOutputText enableLabel = new HtmlOutputText();
       enableLabel.setValue("Show");
       HtmlOutputText layerNameLabel = new HtmlOutputText();
       layerNameLabel.setValue("Layer Name");
      
       layerPanelGrid.getChildren().add(selectLabel);
       layerPanelGrid.getChildren().add(enableLabel);
       layerPanelGrid.getChildren().add(layerNameLabel);
      
       // Now, iterate thru the service layers and emit a line for each...
       for (int i=0; i < server.getLayers().size(); i++) {
       WMSLayer layer = server.getLayers().get(i);
       HtmlSelectBooleanCheckbox layerSelectedBox = new HtmlSelectBooleanCheckbox();
       String layerSelectedBoxId = "s" + (serviceNumber) + "l" + i + "Selected";
       layerSelectedBox.setId(layerSelectedBoxId);
       ValueExpression ve = context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(),"#{manager.s.serverList.get(" + serviceNumber + ").layers.get(" + i + ").selected}",Boolean.class);
       System.out.println("The Value Expression is: " + ve.toString());
       layerSelectedBox.setValueExpression("value", ve);
      
       HtmlSelectBooleanCheckbox layerEnabledBox = new HtmlSelectBooleanCheckbox();
       String layerEnabledBoxId = "s" + (serviceNumber) + "l" + i + "Enabled";
       layerEnabledBox.setId(layerEnabledBoxId);
       //layerEnabledBox.setReadonly(!layer.isSelected());
       layerEnabledBox.setDisabled(!layer.isSelected());
       layerEnabledBox.setValue(layer.isEnabled());
      
       // Set onChange script for selected checkbox to enable/disable the Enabled checkbox when clicked
       layerSelectedBox.setOnchange("document.getElementById('" + SERVER_FORM_NAME + layerEnabledBoxId + "').disabled = this.checked;");
      
       HtmlOutputText layerNameText = new HtmlOutputText();
       layerNameText.setValue(layer.getName());
      
       layerPanelGrid.getChildren().add(layerSelectedBox);
       layerPanelGrid.getChildren().add(layerEnabledBox);
       layerPanelGrid.getChildren().add(layerNameText);
       }
       panelGrid.getChildren().add(layerPanelGrid);
       //HtmlSelectManyCheckbox
      
       // Finally, add the panelGrid to the tab and return...
       tab.getChildren().add(panelGrid);
      
       return tab;
      } // buildServerTab



      If my first attempt of using tag iteration had worked, I'd understand how to do this. I'd bind a variable to the server inside the loop that built the tabs, and then bind a variable to the layer inside the loop that emits the layer descriptions and so it would be no problem having a checkbox that set the "selected" attribute inside my WMSLayer object. That approach seemed like it should have worked. With this approach of building in code I can dynamically build the tabs, but getting everything wired to the values they need to display/input in the backing beans seems very hard.

      So, if anybody has any suggestions on how to accomplish this I'd appreciate it. Surely I'm not the first person who has needed to dynamically create rich:tab components and populate them.