surveyjs / survey-library

Free JavaScript form builder library with integration for React, Angular, Vue, jQuery, and Knockout.
https://surveyjs.io/form-library
MIT License
4.11k stars 800 forks source link

Dynamic Panel for each Checkbox selected in the first page #956

Closed ajien closed 6 years ago

ajien commented 6 years ago

Are you requesting a feature, reporting a bug or ask a question?

Asking a question

What is the expected behavior?

In the survey application that I am building, I have a first page that contains several groups of checkboxes. Each group would have anywhere from 3 to 12 checkboxes. In the second page, I would like to be able to show dynamic panels for each item selected in the first page. For example, if Group 1 has 5 items, and items 1, 2 and 3 are selected, then Group 2 has 5 items and item 1 was selected, I'd like to have dynamic panels for each of the selected items.

The second requirement is that the dynamic panel will have a calculation based on the answers selected in the questions. The results for the calculation for each panel will then be passed to the parent group.

I may be able to figure out this second requirement on my own, but the first one is a big challenge. I have seen examples of using dynamic panels, but the implementation is a little bit different. In the examples that I have seen, the first page has dynamic panels where items are added by clicking a button, and corresponding panels are produced in the second page. In my case, I have a fixed set of checkboxes on the first page, but I need to be able to create dynamic panels for each item selected on the first page.

Here's what I have started building using redux-form: http://nben.wpranger.com/

Click "assess this project" button in one of the items listed on the home page. The current form that is showing is the form I would like to convert to surveyjs..

Here's the json for what I am trying to build in surveyjs. json.txt

Test code

your_code_here

Specify your

andrewtelnov commented 6 years ago

@ajien I have created an example. Please take a look at onValueChanged event. It should do close to what you need.

Thank you, Andrew

ajien commented 6 years ago

Thank you so much, Andrew. I was able to take your example code and expanded it so I can have multiple sets of questions on the first page and was able to generate the dynamic panels for each item selected on the first page. I had to use lodash to help me with the nested iteration over the questions and selected items for each question. Check it out and maybe give comments if you think I did something wrong.

I think my question this time is how do I hide the Complete button until after the last question in the last dynamic panel on page 2 has been answered.

andrewtelnov commented 6 years ago

@ajien You are using Panel Dynamic on the first page to get the all question values - smart move. I think it will be better to have a standard panel. However, we are missing getValue() function for a panel/page. It should work similar to "get survey.data" function, but for panel and page only. I will think about adding this function, to make your code clearer a little bit.

Thank you, Andrew

ajien commented 6 years ago

Thank you very much, Andrew. Please let me know once it is already possible to do something like getValue for standard panel. Surveyjs is awesome (and so are you). I was able to build my questionnaires using Surveyjs in a fraction of the time it took me building the same using redux-form. .

andrewtelnov commented 6 years ago

@ajien That is great. I have added panel.getValue() function. It will be availalbe with the next minor update, on this week.

Thank you, Andrew

ajien commented 6 years ago

Hi, Andrew. I saw that you already pushed the latest minor update. Thank you very much. I am already able to build the form almost up to the point that I want it to work except for one thing. I have one page called "risks" which has the checkboxes, followed by another page called "risk_details" with additional questions for each risk item selected. The data that I am getting after submitting the form looks like

"risks": [
    {
        "forests_wildlife": [
            "The landscape"
        ],
        "other": "Something here"
    }
],
"riskDetails": [
    {
        "forests_wildlife": "The landscape",
        "details": "Some stuff",
        "affected_people": "1000-10,000",
        "affected_wildlife": "2-5 wildlife populations",
        "species_affected": "1",
        "area_affected": "100-1000 km2 affected",
        "timeframe": "up to 1 year",
        "groups_affected": [
            "ecosystem"
        ]
    },
    {
        "other": "Custom",
        "details": "something",
        "affected_people": "100-1000",
        "affected_wildlife": "5-10 wildlife populations",
        "species_affected": "2",
        "area_affected": "10-100 km2 affected",
        "timeframe": "up to 1 year",
        "groups_affected": [
            "wildlife"
        ]
    }
],

Ideally, I want the data to look like the following:

"risks": [
    {
        "forests_wildlife": [
            {
                "The landscape" : {
                    "riskDetails": {
                        "details": "Some stuff",
                        "affected_people": "1000-10,000",
                        "affected_wildlife": "2-5 wildlife populations",
                        "species_affected": "1",
                        "area_affected": "100-1000 km2 affected",
                        "timeframe": "up to 1 year",
                        "groups_affected": [
                            "ecosystem"
                        ]
                    }
                }
            }
        ],
        "other": [
            {
                "Custom" : {
                    "riskDetails": {
                        "details": "something",
                        "affected_people": "100-1000",
                        "affected_wildlife": "5-10 wildlife populations",
                        "species_affected": "2",
                        "area_affected": "10-100 km2 affected",
                        "timeframe": "up to 1 year",
                        "groups_affected": [
                            "wildlife"
                        ]
                    }
                }
            }
        ]
    }
],

First, I want "other" answers as an array, but since it is just one question, I only get a string. I tried putting the question inside a panel, but ordinary panels do affect how data are formatted. It would be nice if panels are returned as array, the same way paneldynamic works. Second, I want to be able to merge the risks and risk_details into one, but I am not sure how to approach it. Third is, is it possible to have a space in a question's name (not the label)?

andrewtelnov commented 6 years ago

@ajien I am afraid the dynamic panel will not be able to understand your desired structure. The only solution that I see now, is to modify the results onComplete event and build the json you need before posting the data into the server. You will have to write the code that will convert survey.data into json object that you need and send your json into server. It should not take a lot of code.

Thank you, Andrew

ajien commented 6 years ago

I understand. I can just probably do that. By the way, the new function that you added, panel.getValue(), how would I be able to use that? Is it possible to use inside an onValueChanged event? Do I just pass the name of the panel to getValue(), like panel.getValue('question1')? or is it ('question1').getValue()? I am sorry I am a little confused.

var test = panel.getValue('panel_details');
        console.log('test', test);

gives me undefined when called inside onValueChanged(), because panel has not been defined.

andrewtelnov commented 6 years ago

@ajien Unfortunately it is not as intuitive, as I thought it should be. Here is the example I will have to add couple more functions, to have a better API. survey.getPanelByName and element(question).hasAsParent(panel)

Thank you, Andrew

ajien commented 6 years ago

This function ( getParentPanel() ) in your example actually helped a lot. I never thought of doing it like that. I was reading the docs and could not find anything like it and did try to figure out to do something similar.

I found a bug that recently surfaced on my end. Adding the panels dynamically works for me, as it worked the past few days, but the issue I just encountered today is that I am no longer able to switch from one dynamic panel to the next. The error I am getting is: Uncaught TypeError: Cannot read property 'panelCounter' of null. This is happening both to the jquery and react tests that I have been doing.

On Wed, Feb 28, 2018 at 4:47 PM, Andrew notifications@github.com wrote:

@ajien https://github.com/ajien Unfortunately it is not as intuitive, as I thought it should be. Here is the example https://plnkr.co/edit/4TeVbEXxx7SmSjxirNhv?p=preview I will have to add couple more functions, to have a better API. survey.getPanelByName and element(question).hasAsParent(panel)

Thank you, Andrew

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/surveyjs/surveyjs/issues/956#issuecomment-369163059, or mute the thread https://github.com/notifications/unsubscribe-auth/ADdgUwlRjNwdIhZ2x5SGtCG1SvQAapKJks5tZRKNgaJpZM4SR1E1 .

andrewtelnov commented 6 years ago

@ajien Could you please provide us with steps to reproduce the bug. so we can fix it?

Thank you, Andrew

ajien commented 6 years ago

Here https://plnkr.co/edit/7kkPtOjQAFt1UxoWk6yB it is.

Select multiple items from the first page, then in the second page, try to move to next panel. That's when the error shows up in the console.

On Wed, Feb 28, 2018 at 5:34 PM, Andrew notifications@github.com wrote:

@ajien https://github.com/ajien Could you please provide us with steps to reproduce the bug. so we can fix it?

Thank you, Andrew

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/surveyjs/surveyjs/issues/956#issuecomment-369178656, or mute the thread https://github.com/notifications/unsubscribe-auth/ADdgU7lhcrRKhGyDzdiz_1690V8Anq_Fks5tZR2XgaJpZM4SR1E1 .

andrewtelnov commented 6 years ago

@ajien I was able to reproduce the error.I will take a look at it today.

Thank you, Andrew

andrewtelnov commented 6 years ago

@ajien I have fixed the issue. For some reason state is null in the react object. I was not figure out why does it happen. I have tried the same example with the current knockout and jQuery versions. They are working just fine. The bug is related to react version only. The fix will be available in the next minor version.

Thank you, Andrew

ajien commented 6 years ago

Thank you very much, Andrew. You will ha e to let me know how to buy you a 6-pack or two.

By the way, is it possible to do if-else in expression field?

On Feb 28, 2018 7:12 PM, "Andrew" notifications@github.com wrote:

@ajien https://github.com/ajien I have fixed the issue. For some reason state is null in the react object. I was not figure out why does it happen. I have tried the same example with the current knockout and jQuery versions. They are working just fine. The bug is related to react version only. The fix will be available in the next minor version.

Thank you, Andrew

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/surveyjs/surveyjs/issues/956#issuecomment-369207296, or mute the thread https://github.com/notifications/unsubscribe-auth/ADdgU8oRjMmRPqSvPzb-b7N214kzlyrgks5tZTSKgaJpZM4SR1E1 .

andrewtelnov commented 6 years ago

@ajien :) you are very welcome! Sure, there is iif function: iif(booleanexpression, trueValue, falseValue)

Here is the related issue

Thank you, Andrew