Search code examples
javajsfprimefacesjsf-2jsf-2.2

Problem with p:dashboard model dynamically update


I'm trying to develop a particular Dashboard. I want to create an initial empty dashboard, and dynamically fill it with elements.

First of all, I create an empty dashboard: XHTML --->

 <p:dashboard id="dash" model ="#{homeReceptionDashboardBck.model}">
            <c:forEach 
                  items="#{homeReceptionDashboardBck.widgets}" 
                  var="widgetsElement">
                <p:panel id = "widgetsElement.idWidget" header="widgetsElement.name">
                    <c:forEach 
                           items="#{homeReceptionDashboardBck.uploadBooking(widgetsElement)" 
                           var="bookings">
                                <h:outputText value="#{booking.owner.ragioneSociale}"> 
                                </h:outputText>
                    </c:forEach>
                </p:panel>
            </c:forEach>
    </p:dashboard>

This is the code that i used to popolate and create dynamically every panel by using .

  1. Fist foreach to verify how many widget the user insert into the MODEL
  2. Second foreach to popolate every panel with different element called "booking".

I create an empty model that is loaded ad the application startup :

for(i = 0;i<officesList.size();i++) {
    DashboardColumn columnTmp = new DefaultDashboardColumn();
    model.addColumn(columnTmp);

    columnDashboard.add(columnTmp);
    List<MeetingRoom> tempMeetingRoom = new ArrayList<>();
    tempMeetingRoom = meetingmr.getAllByOffice(
                            officesList.get(i).getId(), 
                            true, 
                            JSFUtil.getActiveUser());
    for(x = 0;x<tempMeetingRoom.size();x++)
    {
        //popolo la lista che mi serve all'inizio per la lista dei Panel da inserire
        meetingRoomByOffice.add(tempMeetingRoom.get(x));
    }

    officePositionAndColumn[i][0] = (int) (long) officesList.get(i).getId();
    officePositionAndColumn[i][1] = i;

}

In this part of the code, I'm doing a lot of things but the important one is "create" and add a new empty column. I create a List of DashboardColumn to use inside the java code, called columnDashboard.


I create a particular menu to add a widget inside the model : XHTML --->

<smifn:actionsMenu id="tableAddMeetingRoom" styleClass="col-xs-8 col-md-12 text-right"
                    title="#{msg['booking.add_meeting_room']}">
    <c:forEach items="#{homeReceptionDashboardBck.meetingRoomByOffice}" 
                var="meetingRoomElement">
        <p:menuitem id="#{homeReceptionDashboardBck.getMenuItemId(meetingRoomElement)}" 
                    actionListener="#{homeReceptionDashboardBck.onAddPanel(meetingRoomElement)}" 
                    process="@this" partialSubmit="true"
                    value="#{meetingRoomElement.name}" 
                    icon="icon-add-3" 
                    iconPos="left"
                    >
            <p:ajax process="widgetBookingReception" update="widgetBookingReception"/>
        </p:menuitem>       <!--  oncomplete="PF('bookingSelect').show()"-->
    </c:forEach>
</smifn:actionsMenu>

When someone decide to add a Widget, I modify the model with the method onAddPanel

JAVA ---->

public void onAddPanel(MeetingRoom panelSelected) {
    int i;
    //splitto il nome per creare l'id
    String [] nameMeetingRoom = panelSelected.getName().split(" ");
    String idWidget = nameMeetingRoom[0]+"_"+nameMeetingRoom[1];
    //oggetto di tipo DashboardWidget
    DashboardWidget tmp = new DashboardWidget();
    //imposto l'id, nome della stanza e l'ufficio relativo
    tmp.setIdWidget(idWidget);
    tmp.setName(panelSelected.getName());
    tmp.setOffice(panelSelected.getOffice());
    //aggiungo alla lista dei widget l'oggetto relativo
    widgets.add(tmp);
    //stringa per la posizione della colonna
    int columnPosition = -1;
    //faccio un for per passare tutte le colonne relative
    for(i = 0;i<officePositionAndColumn.length;i++)
    {
        //se l'id che era stato impostato è uguale a quello passato 
        if(officePositionAndColumn[i] [0] == panelSelected.getOffice().getId())
            //posizione della colonna che va da 0 a n.
            columnPosition = officePositionAndColumn[i][1];
    }
    //se è stato trovata la posizione della colonna
    if(columnPosition>=0) {
        //mi ricavo la colonna 
        DashboardColumn columnSelected = new DefaultDashboardColumn();
        columnSelected = columnDashboard.get(columnPosition);
        //imposto l'id al widget
        columnSelected.addWidget(idWidget);
        //sovrascrivo la colonna con quella modificata
        columnDashboard.set(columnPosition, columnSelected);
        //reimposto il modello e ricarico le colonne
        setModel(new DefaultDashboardModel());
        for(i = 0;i<columnDashboard.size();i++)
        {
            this.model.addColumn(columnDashboard.get(i));
        }

        for(i = 0;i<meetingRoomByOffice.size();i++)
        {
            if(meetingRoomByOffice.get(i).equals(panelSelected))
            {
                meetingRoomByOffice.remove(i);
            }
        }}

I already verify this method, but I can't visualize the result. How can i UPDATE the model of the Dashboard? I already try this, but I think that this shouldn't work ;(

public void createDashboardDinamically() {

    int i;
    FacesContext fc = FacesContext.getCurrentInstance();
    Application app = fc.getApplication();

    dashboard = (Dashboard) app.createComponent(
                                    fc, 
                                    "org.primefaces.component.Dashboard",
                                    "org.primefaces.component.DashboardRenderer");
    dashboard.setId("dash");
    dashboard.setModel(model);

    Panel panel1 = (Panel) app.createComponent(
                                fc, 
                                "org.primefaces.component.Panel", 
                                "org.primefaces.component.PanelRenderer");
    panel1.setId("Sala_Demo");
    panel1.setToggleable(true);
    panel1.setClosable(true);
    panel1.setHeader("Sala Demo");

    for(i = 0;i<widgets.size();i++)
    {
        Panel panel = (Panel) app.createComponent(
                                    fc, 
                                    "org.primefaces.component.Panel", 
                                    "org.primefaces.component.PanelRenderer");
        panel.setId(widgets.get(i).getIdWidget());
        panel.setToggleable(true);
        panel.setClosable(true);
        panel.setHeader(widgets.get(i).getName());
        getDashboard().getChildren().add(panel);

    }

Can somebody help me? If it works, I'll share the entire code to dinamically popolate a PrimeFaces Dashboard. Thanks a lot guys, i'm stuck :(


Solution

  • I found this solution :

    this is an example for anyone who will find the same difficulty that I met in the creation of a Dynamic Dashboard (everything is dynamic).

    My problem question

    The project is : Display an empty dashboard, the user will visualize a menu in the right side of the FORM with a list of Meeting Room avaiable. After the click of one Meeting Room, the model will be update and the panel visualized in the right column (pre - assigned with its ID). I assign dynamically every ID, numer of column, number of panel and number of element visualized inside each panel.


    First of all, popolate a Java DashboardModel with empty column :

        private DashboardModel model;
        private List<DashboardColumn> dashboardColumn;
    
        DashboardColumn columnTmp = new DefaultDashboardColumn();
        model.addColumn(columnTmp);
        columnDashboard.add(columnTmp);
    

    Logically you have to create getter and setter for the model. I create a List of DashboardColumn for an easy management of each column.

    Popolate a list of meetingRoom object called meetingRoomByOffice. This list will be necessary to the actionMenu to create dynamic element inside the menu.

    for(x = 0;x<tempMeetingRoom.size();x++)
                    {
                    meetingRoomByOffice.add(tempMeetingRoom.get(x));
                    }
    

    I popolate a bidimensional Array to save the ID of each column ( column1 = 1 office ID) with the real position inside the list (ID : 450 - position inside the list 0 etc)

    for(i = 0;i<officesList.size();i++) {
                officePositionAndColumn[i][0] = (int) (long) officesList.get(i).getId();
                officePositionAndColumn[i][1] = i;
    
                }
    

    After this, create the element inside the XHTML The first one is the actionMenu

    NOTE I'VE GOT A PERSONALIZED ONE, NO PARTICULAR MODIFICATION

    <smifn:actionsMenu id="tableAddMeetingRoom" styleClass="col-xs-8 col-md-12 text-right"
                        onclick="@this.update()"
                        title="#{msg['booking.add_meeting_room']}">
                        <c:forEach items="#{homeReceptionDashboardBck.meetingRoomByOffice}" var="meetingRoomElement">
                            <p:menuitem id="#{homeReceptionDashboardBck.getMenuItemId(meetingRoomElement)}" 
                                action="#{homeReceptionDashboardBck.onAddPanel(meetingRoomElement)}" 
                                process="@this"
                                value="#{meetingRoomElement.name}" 
                                icon="icon-add-3" 
                                iconPos="left"
                                update ="widgetBookingReception">
                            </p:menuitem>       <!--  oncomplete="PF('bookingSelect').show()"-->
                        </c:forEach>
                    </smifn:actionsMenu>
    
    1. First foreach ---> get a List of element and browse them one by one with the "name" of meetingRoomElement
    2. To get the ID, I have done a particular method call getMenuItemId that generate an ID with the name of the meeting room, splitted. Something like this : Name : Sala Demo --> ID : Sala__Demo
    3. action call the main method to modify the model, I'll explain it after this list.
    4. update ="widgetBookingReception"> is important to update the entire FORM

    Method onAddPanel

    I have a special class with two main object :

    • idWidget that it is a string
    • meetingRoom that it is an object MeetingRoom

    First of all, I create the ID with one underscore

        String [] nameMeetingRoom = panelSelected.getName().split(" ");
        String idWidget = nameMeetingRoom[0]+"_"+nameMeetingRoom[1];
    

    Create, and add it into a TMP object, after that insert the "widget" inside a list of widget insert in the model by the user. This is important to avoid lost widgets.

        DashboardWidget tmp = new DashboardWidget();
    
        tmp.setIdWidget(idWidget);
        tmp.setName(panelSelected.getName());
        tmp.setOffice(panelSelected.getOffice());
    
        widgets.add(tmp);
    

    Now i'll find the position inside the list, update the model and the listOfMeetingRoom avaible inside the menu.

    for(i = 0;i<officePositionAndColumn.length;i++)
        {
            //se l'id che era stato impostato è uguale a quello passato 
            if(officePositionAndColumn[i] [0] == panelSelected.getOffice().getId())
                //posizione della colonna che va da 0 a n.
                columnPosition = officePositionAndColumn[i][1];
        }
        //se è stato trovata la posizione della colonna
        if(columnPosition>=0) {
            //mi ricavo la colonna 
            DashboardColumn columnSelected = new DefaultDashboardColumn();
            columnSelected = columnDashboard.get(columnPosition);
            //imposto l'id al widget
            columnSelected.addWidget(idWidget);
            //sovrascrivo la colonna con quella modificata
            columnDashboard.set(columnPosition, columnSelected);
            //reimposto il modello e ricarico le colonne
            setModel(new DefaultDashboardModel());
            for(i = 0;i<columnDashboard.size();i++)
            {
                this.model.addColumn(columnDashboard.get(i));
            }
    
            for(i = 0;i<meetingRoomByOffice.size();i++)
            {
                if(meetingRoomByOffice.get(i).equals(panelSelected))
                {
                    meetingRoomByOffice.remove(i);
                }
            }
    

    This is how I update the entire model. But now we have to update it into the XHTML.

    I create a full dynamic dashboard, this is the code :

    <p:dashboard widgetVar="dash" model ="#{homeReceptionDashboardBck.model}">
    <c:when test="not empty #{homeReceptionDashboardBck.widgets}">
                <c:forEach items="#{homeReceptionDashboardBck.widgets}" var="Element">
    
                    <p:panel id="#{Element.idWidget}" header="#{Element.name}">
                    <c:when test="not empty #{homeReceptionDashboardBck.uploadBooking(Element)}">
                        <c:forEach items="#{homeReceptionDashboardBck.uploadBooking(Element)}" var="row">
                                    <h:outputText value="#{homeReceptionDashboardBck.getEventGeneralInfo(row)}"> </h:outputText>
                                    <h:outputText> <br/></h:outputText>
                        </c:forEach>
                    </c:when>
                    <c:otherwise>
                        <c:when test="#{homeReceptionDashboardBck.uploadBooking(Element)}">
                                <h:outputText value="Nessun evento prenotato"> </h:outputText>
                                <h:outputText> <br/></h:outputText>
                            </c:when>
                    </c:otherwise>
                    </p:panel>
                </c:forEach>
    
    </c:when>
        </p:dashboard>
    

    Be careful, inside the foreach you can't pass null List or empty List. I use WHEN to prevent that.

    If you have any question, I'm happy to answer and share part of my code. See you soon :D