nested dynaForm issue

Community Driven Extensions Project
evaleah
Posts: 44
Joined: 10 Jul 2012, 20:26

08 Aug 2012, 20:09

I have a DynaForm that contains backing bean generated DynaForms:

Code: Select all

 <p:panel id="pnlEntry" visible="#{incidentController.questionsVisible}" header="#{incidentController.questionSetName}">
                <script type="text/javascript">
                    #{incidentController.conditionals}
                </script>
                <p:panelGrid id="newSurvey">
                    <p:row>
                        <p:column colspan="2">
                            <p:messages/>
                        </p:column>
                    </p:row>
                    <p:row>
                        <p:column colspan="2">
                            <h:outputText value="#{msgs['incidents.new.description']}" style="font-weight: bold"/>
                            <br/>
                            <p:inputTextarea value="#{incidentController.survey.description}" id="surveyDescription"
                                         title="#{msgs['incidents.new.description.title']}" style="width: 95%;" />
                        </p:column>
                    </p:row>
                    <p:row>
                        <p:column>
                            <h:outputText value="#{msgs['incidents.new.dateOccurred']}" style="font-weight: bold"/>
                            <br/>
                            <p:calendar value="#{incidentController.survey.dateOccurred}" id="DateOccurred" showOn="button" pattern="MM/dd/yyyy hh:mm a">
                                <f:converter converterId="DateToCalendarConverter" />
                            </p:calendar>
                        </p:column>
                        <p:column>
                            <h:outputText value="#{msgs['incidents.new.location']}" style="font-weight: bold"/>
                            <br/>
                            <p:selectOneMenu id="ddlLocation" value="#{incidentController.selectedLocationId}">
                                <f:selectItems value="#{incidentController.locations}" var="location"
                                               itemValue="#{location.id}" itemLabel="#{location.name}"/>
                            </p:selectOneMenu>
                        </p:column>
                    </p:row>
                    <p:row>
                        <p:column colspan="2">
                            <pe:dynaForm widgetVar="formGroup" value="#{incidentController.groupPanel}" var="groupModel">
                                <pe:dynaFormControl type="panel" for="questionGroupPanel">
                                    <p:panel id="questionGroupPanel" header="#{groupModel.group.name}">
                                        <pe:dynaForm widgetVar="formQuestion" value="#{groupModel.model}" var="questionResponse">
                                            <pe:dynaFormControl type="inInt" for="txtInt">
                                                <p:inputText id="txtInt" value="#{questionResponse.response}"/>
                                            </pe:dynaFormControl>
                                            <pe:dynaFormControl type="inDec" for="txtDec">
                                                <p:inputText id="txtDec" value="#{questionResponse.response}"/>
                                            </pe:dynaFormControl>
                                            <pe:dynaFormControl type="select" for="sel" styleClass="select">
                                                <p:selectManyCheckbox value="#{questionResponse.multiResponses}" id="sel">
                                                    <f:selectItems value="#{questionResponse.question.responseOptions}"
                                                                   var="option" itemLabel="#{option.response}" itemValue="#{option.id}"
                                                                   itemDescription="#{option.description}"/>
                                                </p:selectManyCheckbox>
                                            </pe:dynaFormControl>
                                            <pe:dynaFormControl type="calendar" for="cal" styleClass="calendar">
                                                <p:calendar value="#{questionResponse.calendar}" id="cal" showOn="button" pattern="MM/dd/yyyy hh:mm a">
                                                    <f:converter converterId="DateToCalendarConverter" />
                                                </p:calendar>
                                            </pe:dynaFormControl>
                                            <pe:dynaFormControl type="area" for="tarea">
                                                <p:inputTextarea id="tarea" value="#{questionResponse.response}" style="width: 95%"/>
                                            </pe:dynaFormControl>
                                            <pe:dynaFormControl type="radio" for="rselect">
                                                <p:selectOneRadio value="#{questionResponse.response}" id="rselect">
                                                    <f:selectItems value="#{questionResponse.question.responseOptions}"
                                                                   var="option" itemLabel="#{option.response}" itemValue="#{option.id}"
                                                                   itemDescription="#{option.description}"/>
                                                </p:selectOneRadio>
                                            </pe:dynaFormControl>
                                        </pe:dynaForm>
                                    </p:panel>
                                </pe:dynaFormControl>
                            </pe:dynaForm>
                        </p:column>
                    </p:row>
                    <p:row>
                        <p:column style="text-align: right;" colspan="2">
                            <p:commandButton action="#{incidentController.addSurvey}" value="#{msgs['common.button.save']}"
                                             title="#{msgs['incidents.new.submit']}" style="font-weight: bold;"
                                             update=":incidentNew:pnlEntry :incidentNew:pnlComplete"/>
                        </p:column>
                    </p:row>
                </p:panelGrid>
            </p:panel>
The page is generated correctly but if I have any more than one model in the dynaForm the data is not set in the controls. In other words, only one dynaForm in the mix, works perfectly, can't ask for better. More than one dynaForm in the mix and the data set on the client is not returned to the backing bean. The code that generates the form is:

Code: Select all

                List<QuestionSetGroup_LinkDTO> questionGroups = (List<QuestionSetGroup_LinkDTO>)questionSet.getQuestionGroups();
                Collections.sort(questionGroups,  QUESTIONSETGROUP_COMPARE_ORDINAL);
                for (QuestionSetGroup_LinkDTO groupLink : questionGroups)
                { 
                    QuestionGroupDTO group = groupLink.getQuestionGroup();
                    //add panel for group
                    DynamicGroupModel groupModel = new DynamicGroupModel(group, new DynaFormModel());
                    DynaFormRow row = groupPanel.createRegularRow();
                    DynaFormControl gPanel = row.addControl(groupModel, "panel", 1, 1);
                    gPanel.setKey(group.getInternalCode());
                    //set conditionals, if applicable
                    if (group.getConditionals() != null && group.getConditionals().size() > 0)
                    {
                        //initial hiding of controls as default
                        hideConditionals = hideConditionals +
                                ("$('div[id*=\"" + group.getInternalCode() + "\"]').closest('tr').hide(); ");
                        //begin building of function to show control
                        //INDEPENDENT VISIBILITY CHECKING FUNCTION, CALLED BY CHANGE FUNCTIONS ON SELECT ELEMENTS
                        String function = "function updateGroup" + group.getId() + "(){ ";
                        //loop through conditional records adding each value to visibility logic
                        //for both the independent function and the change event on the element
                        for (QuestionGroupConditionalDTO con : group.getConditionals())
                        {
                            if (con.getQuestionSetId().toString().equalsIgnoreCase(selectedQuestionSetId))
                            {
                                //CHANGE FUNCTION, part of hideConditionals
                                hideConditionals = hideConditionals + " $('input[id*=\"dynaControl-" + con.getQuestionId() +
                                        "\"]').change(function() { updateGroup" + group.getId() + "(); });";
                                //parse through answer options that cause visibility of question
                                String[] options = con.getResponseOptionIds().split(",");
                                for (String option : options)
                                {
                                    //ADD TO INDEPENDENT VISIBILITY CHECKING FUNCTION
                                    if (!function.contains("if"))
                                        function = function + " if ($('table[id*=\"dynaControl-" + con.getQuestionId() +
                                                "\"]').find('.ui-state-active').siblings('.ui-helper-hidden-accessible').find('input').val() == '" +
                                                option + "' ";
                                    else
                                        function = function + "|| $('table[id*=\"dynaControl-" + con.getQuestionId() +
                                                "\"]').find('.ui-state-active').siblings('.ui-helper-hidden-accessible').find('input').val() == '" +
                                                option + "' ";
                                }
                            }
                        }
                        //close out the independent visibility function with complete visibility logic and ending syntax
                        buildConditionals = buildConditionals + function +
                                (") $('div[id*=\"" + group.getInternalCode() + "\"]').closest('tr').show(); ") +
                                ("else $('div[id*=\"" + group.getInternalCode() + "\"]').closest('tr').hide(); }");
                    }
                    //generate subForm
                    groupQuestions.clear();
                    groupQuestions.addAll(questionSetModel.QuestionsByGroup(group.getId()));
                    Collections.sort(groupQuestions, QUESTION_COMPARE_ORDINAL);
                    buildConditionals = buildConditionals + (generateDisplayPanel(groupQuestions, groupModel.getModel()));
                }

 private String generateDisplayPanel(List<QuestionDTO> groupQuestions, DynaFormModel displayPanel)
    {
        QuestionResponse questionResponse;
        String function = "";

        for (QuestionDTO question : groupQuestions)
        {
            //create questionResponse object to hold all the data in one place
            DynaFormRow row = displayPanel.createRegularRow();
            //question label
            DynaFormLabel labelQuestion = row.addLabel(question.getOrdinal() + ". " + question.getText(), 1, 1);

            //create controls based on question type
            QuestionType questionType = QuestionType.values()[Integer.parseInt(question.getQuestionType().getId().toString())];
            switch (questionType)
            {
                case Multiple_Select:
                    questionResponse = new QuestionResponse(question, new ArrayList<String>());
                    DynaFormControl selectManyCheckbox = row.addControl(questionResponse, "select", 1, 1);
                    selectManyCheckbox.setKey("dynaControl-" + question.getId().toString());
                    labelQuestion.setForControl(selectManyCheckbox);
                    break;

                case Single_Select:
                    questionResponse = new QuestionResponse(question, "");
                    DynaFormControl selectOneRadio = row.addControl(questionResponse, "radio", 1, 1);
                    selectOneRadio.setKey("dynaControl-" + question.getId().toString());
                    labelQuestion.setForControl(selectOneRadio);
                    break;

                case Text:
                    questionResponse = new QuestionResponse(question, "");
                    DynaFormControl textArea = row.addControl(questionResponse, "area", 1, 1);
                    textArea.setKey("dynaControl-" + question.getId().toString());
                    labelQuestion.setForControl(textArea);
                    break;

                case Date:
                    questionResponse = new QuestionResponse(question, new ArrayList<String>());
                    DynaFormControl calendar = row.addControl(questionResponse, "calendar", 1, 1);
                    calendar.setKey("dynaControl-" + question.getId().toString());
                    labelQuestion.setForControl(calendar);
                    break;

                case Integer:
                    questionResponse = new QuestionResponse(question, "");
                    DynaFormControl intBox = row.addControl(questionResponse, "inInt", 1, 1);
                    intBox.setKey("dynaControl-" + question.getId().toString());
                    labelQuestion.setForControl(intBox);
                    break;

                case Decimal:
                    questionResponse = new QuestionResponse(question, "");
                    DynaFormControl decBox = row.addControl(questionResponse, "inDec", 1, 1);
                    decBox.setKey("dynaControl-" + question.getId().toString());
                    labelQuestion.setForControl(decBox);
                    break;
            }

            if (question.getConditionals() != null && question.getConditionals().size() > 0)
            {
                //Set row to display:none as default.  Row will appear when selection is made, if applicable.
                hideConditionals = hideConditionals + ("$('label[for*=\"dynaControl-" + question.getId() +
                        "\"]').closest('tr').hide(); ");
                //INDEPENDENT VISIBILITY CHECKING FUNCTION, CALLED BY CHANGE FUNCTIONS ON SELECT ELEMENTS
                String buildConditionals = "function updateQuestion" + question.getId() + "(){ ";
                //loop through conditional records adding each value to visibility logic
                //for both the independent function and the change event on the element
                for (QuestionConditionalDTO con : question.getConditionals())
                {
                    if (con.getQuestionSetId().toString().equalsIgnoreCase(selectedQuestionSetId))
                    {
                        //CHANGE FUNCTION, part of hideConditionals
                        hideConditionals = hideConditionals + "$('input[id*=\"dynaControl-" + con.getQuestionId() +
                                "\"]').change(function() { updateQuestion" + question.getId() + "(); });";
                        //parse through answer options that cause visibility of question
                        String[] options = con.getResponseOptionIds().split(",");
                        for (String option : options)
                        {
                            //ADD TO INDEPENDENT VISIBILITY CHECKING FUNCTION
                            if (!buildConditionals.contains("if"))
                                buildConditionals = buildConditionals + " if ($('table[id*=\"dynaControl-" + con.getQuestionId() +
                                        "\"]').find('.ui-state-active').siblings('.ui-helper-hidden-accessible').find('input').val() == '" +
                                        option + "' ";
                            else
                                buildConditionals = buildConditionals + "|| $('table[id*=\"dynaControl-" + con.getQuestionId() +
                                        "\"]').find('.ui-state-active').siblings('.ui-helper-hidden-accessible').find('input').val() == '" +
                                        option + "' ";
                        }
                    }
                }
                //close out the independent visibility function with complete visibility logic and ending syntax
                buildConditionals = buildConditionals +
                        (") $('label[for*=\"dynaControl-" + question.getId() + "\"]').closest('tr').show(); ") +
                        ("else $('label[for*=\"dynaControl-" + question.getId() + "\"]').closest('tr').hide(); }");
                //add new conditional to entire conditional statement
                function = function + buildConditionals;
            }
        }
        
        return function;
    }
Is there a better way to do this to allow the ability to have nested dynaForms?

Thanks!
PrimeFaces 3.5 | Glassfish 3.1.2 | IntelliJ IDEA 12.1.4 | Windows 7, Firefox 14.0.1

User avatar
Oleg
Expert Member
Posts: 3803
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

09 Aug 2012, 10:50

Hi,

Wow, you're building the entire UI in Java :-) I have never tried to use nested DynaForm, but I'm aware of possible shortcomings with nested DynaForm. UIData has a special handling for that. I left the logic for nesting because I didn't need it. You can create an issue in our issue tracker if you think the nesting is not working. I will look deeper into this later.

By the way, why do you call setKey() on DynaFormControll manually? E.g. gPanel.setKey(group.getInternalCode()). This method is called internally in DynaFormControll

Code: Select all

	public DynaFormControl(Object data, String type, int colspan, int rowspan, int row, int column, boolean extended) {
		super(colspan, rowspan, row, column, extended);

		this.data = data;
		if (type != null) {
			this.type = type;
		} else {
			this.type = DEFAULT_TYPE;
		}

		generateKey();
	}

	private void generateKey() {
		StringBuilder sb = new StringBuilder();
		sb.append(KEY_PREFIX_ROW).append(getRow()).append(KEY_PREFIX_COLUMN).append(getColumn());
		if (isExtended()) {
			sb.append(KEY_SUFFIX_EXTENDED);
		} else {
			sb.append(KEY_SUFFIX_REGULAR);
		}

		setKey(sb.toString());
	}
Please don't call it self.
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

evaleah
Posts: 44
Joined: 10 Jul 2012, 20:26

09 Aug 2012, 13:34

I call setKey because I need to have a definite value I can refer back to later when I set the rows to invisible. Before I was using setKey there was nothing in the generated id that referred back to the item in the database so I couldn't figure out which row I wanted to set visible and invisible based on clicks. Once I added the setKey pieces I had the unique piece of code I needed and could now refer to in my javascript code. I didn't include the whole building of the dynamic javascript blocks here since they are actually working perfectly. In other words, setKey works to do what I need to do and it was all there was. It made me happy :) In this case, absolutely, I SHOULD set it!

And yes, the entire form, the javascript blocks, basically everything that gets spit out in the end as HTML is coming from that backing bean. I am looking into the nested thing for a tiny bit more and will likely post an issue...
PrimeFaces 3.5 | Glassfish 3.1.2 | IntelliJ IDEA 12.1.4 | Windows 7, Firefox 14.0.1

evaleah
Posts: 44
Joined: 10 Jul 2012, 20:26

09 Aug 2012, 13:39

One other question, what is the time frame on an issue like this? I ask because if the data is not going to persist, despite this all appearing to work now I may have to abandon the whole thing and do it some other way if I cannot persist the data :(
PrimeFaces 3.5 | Glassfish 3.1.2 | IntelliJ IDEA 12.1.4 | Windows 7, Firefox 14.0.1

User avatar
Oleg
Expert Member
Posts: 3803
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

09 Aug 2012, 15:27

Time frame? No time frame. I think the release 0.7.0 sounds good, but it will happen in 2-3 months, not earlier. We're developing this project in our free time and don't earn many. We're trying to do our best to fix issues. New features can be added later, on demand and if our time allows to do this. If we would earn money, we would implement all user requests immediately.

For now, I would recommend you place all DynaForm below each other in separate panels, without nesting. Why do you need nesting? Can you not use ui:repeat or whatever with DynaForm inside?
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

evaleah
Posts: 44
Joined: 10 Jul 2012, 20:26

09 Aug 2012, 20:26

I am actually building it differently without the nesting. Thanks for an general guess of the timeline. I am SO sorry if I seemed to rush you! My goodness, this control is brilliant! I was just hoping to also reach the stars :) No hurry AT ALL!!! Thank you for doing what you do! And for all the assistance you have given me in these forums!!!
PrimeFaces 3.5 | Glassfish 3.1.2 | IntelliJ IDEA 12.1.4 | Windows 7, Firefox 14.0.1

User avatar
Oleg
Expert Member
Posts: 3803
Joined: 02 Oct 2009, 09:41
Location: Germany, Black Forest

09 Aug 2012, 22:34

Oh, thank you very much for these words, very pleasant to hear this. As I said, you can create an issue ticket for nested forms if it makes sense. Good luck!
PrimeFaces Cookbook (2. edition): http://ova2.github.io/primefaces-cookbook/ Learning Angular UI Development with PrimeNG: https://github.com/ova2/angular-develop ... th-primeng Blog: https://medium.com/@OlegVaraksin

nileshbchauhan
Posts: 3
Joined: 20 Feb 2017, 12:06

17 Apr 2017, 16:48

Dear,

I am also facing the same issue of nested dyna form. Can you please let me know the way-forward for the same.

Many thanks,
Nilesh Chauhan

User avatar
Melloware
Posts: 318
Joined: 22 Apr 2013, 15:48

17 Apr 2017, 19:08

What version of PF and Extensions are you using?
PrimeFaces Extensions Developer
GitHub Profile: https://github.com/melloware
PrimeFaces 6.1.X / PF Extensions 6.1.5

nileshbchauhan
Posts: 3
Joined: 20 Feb 2017, 12:06

18 Apr 2017, 08:45

I am using Primefaces version 6.0 and Primefaces-extensions-4.0.0. I have verified the same with Primefaces-extensions-6.0.0 and there also it is just binding the value to last nested dyna form model but other previous nested model has null values.

I could see the browser is sending the request parameters correctly and also accessing with "FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap()" show the submitted values but the dyna model controls are showing null values.

Post Reply
  • Information
  • Who is online

    Users browsing this forum: kumar_swarup and 1 guest