admin管理员组

文章数量:1335386

I would like to simply .show() a div based on a web forms radio button (user) selections.

For brevity lets take below (but note I'm looking for somewhat scaleable advice as my web form will have 7 questions and 5 answers each. And I have 5 results divs)

Note:// So, basically there will be 7 questions and 5 answers each. so I will need an array with 5 possible answer binations via user radio button selection, ideally using the input 'value' field; so I can simply change the values of what value bos would equal what div results screen. The div results screens will just be 5 unique sets of content inside the div, that's it.


Mark-Up:

<div class="page1">
  <form class="sampler">
    <input type="radio" name="sex" value="male" checked>Male
    <br>
    <input type="radio" name="sex" value="female">Female
  </form>
</div>

<div class="page2">
  <form class="sampler">
    <input type="radio" name="food" value="tacos" checked>Tacos
    <br>
    <input type="radio" name="food" value="spicynuts">Rotten Spicy Peanuts
  </form>
</div>

<div id="resultsONE"><!-- one results div is display none by default sample but there would be much more content here  -->
  <p>Congratulations, you are NOT the father</p>
</div>

I know the below is terrible syntax; but this was the logic I was thinking about starting with on JS side. Note I will have 5 unique results #divs.


function resultsdivONE () { 
  if ($input value == "male" & "tacos") {
    $('#resultsONE').show();   
  } else if () {
    // do
  } else {
    // do
  }
}

As I mentioned above; I'm looking for a method where I can simply use the SELECTED input value=""; so they can be changed somewhat easily.

Example.


if ("male" & "tacos" & "nextanswer" & "nextanswerafter") { // etc up to 7
   $('#resultsONE').show(); 
 }  // first results div

May be open to php options.

Thanks for taking a look!

I would like to simply .show() a div based on a web forms radio button (user) selections.

For brevity lets take below (but note I'm looking for somewhat scaleable advice as my web form will have 7 questions and 5 answers each. And I have 5 results divs)

Note:// So, basically there will be 7 questions and 5 answers each. so I will need an array with 5 possible answer binations via user radio button selection, ideally using the input 'value' field; so I can simply change the values of what value bos would equal what div results screen. The div results screens will just be 5 unique sets of content inside the div, that's it.


Mark-Up:

<div class="page1">
  <form class="sampler">
    <input type="radio" name="sex" value="male" checked>Male
    <br>
    <input type="radio" name="sex" value="female">Female
  </form>
</div>

<div class="page2">
  <form class="sampler">
    <input type="radio" name="food" value="tacos" checked>Tacos
    <br>
    <input type="radio" name="food" value="spicynuts">Rotten Spicy Peanuts
  </form>
</div>

<div id="resultsONE"><!-- one results div is display none by default sample but there would be much more content here  -->
  <p>Congratulations, you are NOT the father</p>
</div>

I know the below is terrible syntax; but this was the logic I was thinking about starting with on JS side. Note I will have 5 unique results #divs.


function resultsdivONE () { 
  if ($input value == "male" & "tacos") {
    $('#resultsONE').show();   
  } else if () {
    // do
  } else {
    // do
  }
}

As I mentioned above; I'm looking for a method where I can simply use the SELECTED input value=""; so they can be changed somewhat easily.

Example.


if ("male" & "tacos" & "nextanswer" & "nextanswerafter") { // etc up to 7
   $('#resultsONE').show(); 
 }  // first results div

May be open to php options.

Thanks for taking a look!

Share Improve this question edited Jul 9, 2015 at 14:04 Lieutenant Dan asked Jun 30, 2015 at 19:27 Lieutenant DanLieutenant Dan 8,29428 gold badges97 silver badges215 bronze badges 5
  • Where are the result divs? And based on your function, how are we supposed to know what bination of results should cause the div to be displayed? – j08691 Commented Jun 30, 2015 at 19:31
  • Question has been updated. – Lieutenant Dan Commented Jun 30, 2015 at 19:49
  • Are you still looking for help on this? – Lain Commented Jul 7, 2015 at 17:30
  • Yeah, there's 6 days left on the bounty. I'll close it before then with what works. – Lieutenant Dan Commented Jul 7, 2015 at 17:44
  • Can you indicate what you find wrong about the current answers? I've seen more than one that seems to answer the updated question. It is really, really hard to give a better answer without finding out why the current answers aren't what you are looking for. – Guy Schalnat Commented Jul 8, 2015 at 3:17
Add a ment  | 

7 Answers 7

Reset to default 3 +100

display result divs based on web form radio button selections

What to achieve?

So basically, what is seeked is a simple form containing radio buttons and results which should match a bination of the radio-choices.According to the question, the questions should be easily maintainable and changable, without always touching a script or its initial logic. This votes for outsourcing the questions and the logic - seperate it from the DOM.

How to achieve that?

Shortly mentioned and furthermore visible in the question tags are php and ajax. Given that there might be the wish to outsource the questions pletely and grab them from php by ajax. Another vote for outsourcing.

What is needed to achieve that?

  • Is there any framework and/or library required? Not necessarily, yet it could be usefull
    • To retrieve the JSON
    • To create DOM elements
  • Do we need all the questions and answers in the DOM all time? Not really

For brevity lets take below (but note I'm looking for somewhat scaleable advice as my web form will have 7 questions and 5 answers each. And I have 5 results divs)

  1. I remend to create the DOM on the fly, since - up until now- there is no reason to keep it all the time and it makes the HTML file itself look more slim and neat.
  2. Additionally, it is possible to seperate the layout, structure, logic and the data, which in the end allows you to change the answers and questions by changing one file.
  3. With a method like this, you could create more forms with different questions, yet the same code.
  4. If you are not using any library/framework yet, do not add one just for this script.

Conclusion

To make it easily maintainable, the questions and answers are going to be outsourced into a json file (here JSON.js). Given this, it is also possible to retrieve it by php or any webservice and/or store those in a database. Furthermore the possibility is provided to create multiple forms with yet different questions which all use the same code.

There is a Fiddle available for it

Code

<html>
    <head>
        <!-- optional styles -->
        <style>
            #Container{
                left: 50%;
                position: absolute;
                text-align: center;
                top: 50%;
                transform: translate(-50%, -50%);
            }
        </style>

        <script>
            //This is out simple AJAX routine to not overload it by any framework.
            //If you are already using jQuery, just use $.get()
            ;var AJAX = {
                getXmlDoc: function(){return ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"))},

                //u:=url, f:=callback, c:=any param to pass to callback
                Get: function(u, f, c){
                    var tDoc = this.getXmlDoc();

                    tDoc.open('GET', u, true);
                    tDoc.onreadystatechange = function(){
                        if (tDoc.readyState === XMLHttpRequest.DONE && tDoc.status === 200) f(tDoc, c);
                    };

                    tDoc.send();
                }
            };

            //This is going to be the namespace holding our functionality.
            //In the end one should outsource this to a script file, yet we leave it here in the example for a better overview.
            ;var Quiz = {
                mContainer: null, //In this container the quiz gets created in
                mCurrent: null, //Stores the current displayed question
                mJSON: null, //In here we are going to store the JSON result

                //Handling logical errors, like missing data or json
                _Error: function(m){
                    console.log(m)
                },

                //The event called on the radio change event
                //e:=element
                _onChange: function(e){
                    if (e && this.mJSON.questions[this.mCurrent]){
                        //We are going to those the result of this question in the JSON
                        this.mJSON.questions[this.mCurrent].value = e.value;

                        //If the question is not the last, we are going to display the next one
                        if (this.mCurrent < this.mJSON.questions.length - 1){
                            this.hideQuestions();
                            this.showQuestion(this.mCurrent + 1)
                        }
                        else{
                            //Else we are going to show the result
                            this.hideQuestions();
                            this.showResult()
                        }
                    }
                    else this._Error('_onChange(): Invalid parameters')
                },

                //The function to initialise our quiz.
                //We are going to grab the json data and analyse it.
                //c:=container element || document.body, l:=link || 'JSON.js'
                Init: function(c, l){
                    this.mContainer = (c || document.body);

                    var tL = (l || 'JSON.js');
                    AJAX.Get(tL, function(r, l){
                        Quiz.mJSON = JSON.parse(r.response);

                        if (Quiz.mJSON && Quiz.mJSON.questions)
                            Quiz.showQuestion(0)
                        else
                            Quiz._Error('Init(): No questions found with "' + l + '"')
                    }, tL)
                },

                //Hiding the previously asked questions (remove from dom)
                hideQuestions: function(){
                    while(this.mContainer.firstChild) this.mContainer.removeChild(this.mContainer.firstChild)
                },

                //Going to show the result according to the asked questions
                showResult: function(){
                    var tValues = []; //Storing our answers
                    for(var i=0, j=this.mJSON.questions.length; i<j; i++)
                        if (this.mJSON.questions[i].value) tValues.push(this.mJSON.questions[i].value)

                    //Going to store the result text
                    var tResult = 'No match for ' + tValues.join(',');

                    //Looping through all requirements to get a match
                    for(var i=0, j=this.mJSON.answers.length; i<j; i++){
                        //The requirements which need to match the values
                        var tR = this.mJSON.answers[i].requirement;

                        //For this we filter all the elements which do not match the requirements
                        var tF = tValues.filter(function(e){return tR.indexOf(e) === -1})

                        //If that list is empty, all elements matched and we can stop
                        if (!tF || tF.length === 0){
                            tResult = this.mJSON.answers[i].message;
                            break;
                        }
                    }

                    //Now we are going to dislpay the result
                    var tH = document.createElement('h1');
                    tH.innerHTML = tResult;
                    this.mContainer.appendChild(tH)
                },

                //This creates and shows a question of our question array
                //i:=JSON.questions array index
                showQuestion: function(i){
                    if (i >= 0 && i<this.mJSON.questions.length){
                        this.mCurrent = i;

                        var tQ = this.mJSON.questions[i];
                        var tN = Object.getOwnPropertyNames(tQ)[0]; //The property name is going to bee the radio group name

                        //We are going to create a title (h1) and multiple radios (input & label) for each question
                        var tF = document.createDocumentFragment();

                        //Creating the header
                        var tH = document.createElement('h1');
                        tH.innerHTML = tQ.label;
                        tF.appendChild(tH);

                        //Creating the questions
                        for(var i=0, j=tQ[tN].length; i<j; i++){
                            var tR = document.createElement('input');
                            tR.type = 'radio';
                            tR.value = tQ[tN][i];
                            tR.name = tN;
                            tR.onchange = function(){Quiz._onChange(this)};
                            tF.appendChild(tR);

                            var tL = document.createElement('label');
                            tL.for = tR.name;
                            tL.innerHTML = tR.value;
                            tF.appendChild(tL);
                        }

                        //Now we are going to assign it to the dom.
                        this.mContainer.appendChild(tF)
                    }
                    else{
                        this.mCurrent = null;
                        this._Error('showQuestion(' + i.toString() + '): No such question loaded')
                    }
                }
            };
        </script>
    </head>

    <body onload = "Quiz.Init(document.querySelector('#Container'))">
        <div id = 'Container'>
            <!-- Container for the quiz -->
        </div>
    </body>
</html>

And the JSON.js

{
    "questions": [
        {"sex": ["male", "female"], "label": "What are you?"},
        {"food": ["tacos", "spicynuts"], "label": "What do you eat?"},
        {"team": ["team a", "team b", "team rocket"], "label": "Where do you belong to?"}
    ],

    "answers": [
        {"requirement": ["male", "tacos", "team a"], "message": "one has chosen male, tacos and team a"},
        {"requirement": ["female", "tacos", "team a"], "message": "one has chosen female, tacos and team a"}
    ]
}

Edit:

A small question occured to me while writing my suggestion. Given your explanation "there are seven questions and five results". Do some outes share results or have none?

Changes

To solve the sharing result issue, I though of two ways which I think are the most simple to input and maintain.

We list the result twice

This solution might sound silly and too simple. Yet it is easy to maintain and manage. The obvious downfall is the lack of data integrity.

{"requirement": ["male", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
{"requirement": ["female", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"}

We nest lists on requirements

Another way is to nest requirements (array in array/object), so that one may simply list more requirements with same message. The downfall here is, that even if one never needs it, one had to structure it that way.

{
    "requirement": [
        ["male", "tacos", "team rocket"],
        ["male", "spicynuts", "team rocket"],
        ["female", "tacos", "team rocket"],
        ["female", "spicynuts", "team rocket"]
    ],
    "message": "team rocket rocks my socks!"
}

Conclusion

In the end I decided to let the user decide and support both methods and a bination of initial and solution number two. One can structure it like before, one can repeat answers with equal messages or one can nest requirements.

What do we need to change?

One function in the main code file

//Going to show the result according to the asked questions
showResult: function(){
    var tValues = []; //Storing our answers
    for(var i=0, j=this.mJSON.questions.length; i<j; i++)
        if (this.mJSON.questions[i].value) tValues.push(this.mJSON.questions[i].value)

    //Going to store the result text
    var tResult = 'No match for ' + tValues.join(',');

    //Looping through all requirements to get a match
    var tBreak = false; //We use this to double break both loops
    for(var i=0, j=this.mJSON.answers.length; i<j && !tBreak; i++){
        //The requirements which need to match the values
        var tR = this.mJSON.answers[i].requirement;

        //We put simple arrays in a nested array to keep the same logic/process
        var tRR = (typeof tR[0] === 'string') ? [tR] : tR;

        for(var k=0, l=tRR.length; k<l && !tBreak; k++){
            //For this we filter all the elements which do not match the requirements
            var tF = tValues.filter(function(e){return tRR[k].indexOf(e) === -1})

            //If that list is empty, all elements matched and we can stop
            if (!tF || tF.length === 0){
                tResult = this.mJSON.answers[i].message;
                tBreak = true;
            }
        }

        //If that list is empty, all elements matched and we can stop
        if (!tF || tF.length === 0){
            tResult = this.mJSON.answers[i].message;
            break;
        }
    }

    //Now we are going to dislpay the result
    var tH = document.createElement('h1');
    tH.innerHTML = tResult;
    this.mContainer.appendChild(tH)
},

And here is the sample JSON used for testing

{
    "questions": [
        {"sex": ["male", "female"], "label": "What are you?"},
        {"food": ["tacos", "spicynuts"], "label": "What do you eat?"},
        {"team": ["team a", "team b", "team rocket"], "label": "Where do you belong to?"}
    ],

    "answers": [
        {"requirement": ["male", "tacos", "team a"], "message": "one has chosen male, tacos and team a"},
        {"requirement": ["female", "tacos", "team a"], "message": "one has chosen female, tacos and team a"},

        {"requirement": ["male", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},
        {"requirement": ["female", "spicynuts", "team a"], "message": "one has chosen male, spicynuts and team a"},

        {
            "requirement": [
                ["male", "tacos", "team rocket"],
                ["male", "spicynuts", "team rocket"],
                ["female", "tacos", "team rocket"],
                ["female", "spicynuts", "team rocket"]
            ],
            "message": "team rocket rocks my socks!"
        }
    ]
}

I think it could have been better but here is the start.

Put all logic in array.

http://jsfiddle/1exsro2b/1/

var logics = {
    idOfDiv: [{idOfInput: valueOfInput ,name:'asd',gender:'female'} , {name:'bbb'}],
    ifn2: [{num:1}],
    ifn3: [{gender:'male'}],
    ifn4: [{name:'zxc'}]
};

/*
basically give ids to divs that you want to show conditionally starting with ifn and in array put logic [{formEleId: value, ...},{...or logic..}]
*/

var rules = Object.keys(logics);
var divs = $('div[class^=ifn]').hide();
var form = $("#inputs");

updateForm();

form.on('input change', function () {
    updateForm();
    console.log($('#gender')[0]);
});

function updateForm() {
    divs.hide();
    rules.forEach(function (k) {
        var ele = divs.filter("." + k);
        logics[k].forEach(function(l) {
            applyRules(l,ele);
        });
    });
}

function applyRules(l, ele){
    var ids = Object.keys(l);
    var valid = true;
    ids.forEach(function(id){
        var input = form.find('#'+id);
        if (input.children('input:radio').length>0){
            input = input.children('input[type=radio]:checked');
        }
        if (input.val() != l[id]) valid = false;
    });
    if (valid) ele.show();
}

Try this:

$('input[type=radio]').change(function(){
var val1=$('input[name="sex"]:checked', '#page1').val()
var val2=$('input[name="food"]:checked', '#page1').val()

 if (val1 == "male" && val2== "tacos") {
    $('#resultsONE').show();   
  } else if () {
    // do
  } else {
    // do
  }

});

This is just the sample logic, may need some tweak to make it work for you

How about making use of the data attributes to make the process simpler?

<div class="page1" data-answer-div="results-one">
    <form class="sampler">
        <input type="radio" name="sex" value="male" checked="checked" data-answer="a1" />Male
        <input type="radio" name="sex" value="female" data-answer="a2" />Female
    </form>
</div>

<div id="results-one">
    <div class="a a1">
        <p>Congratulations, you are NOT the father</p>
    </div>
    <div class="a a2">
        <p>Congratulations, you are NOT the mother</p>
    </div>
</div>

Then, when the input is changed, you could hide any div's with the class .a within the answer-div. So, in the above example, you'd hide the div.a's in #results-one, and then show the div with the corresponding a[n] class.

$('input').change(function () {
    var answerDiv = $(this).closest('div').data('answer-div');
    $('#' + answerDiv).find('div.a').hide();
    $('#' + answerDiv).find('div.' + $(this).data('answer')).show();
});

Here's a fiddle, and here's a fiddle with multiple forms.

While there are many ways to answer this, I'm going to add AngularJS into the mix, mostly because it sort of looks like the library that OP may be looking for (without really asking for it).

angular.module('angularSolution', []).controller('angularController', function($scope) {

  // initialize values
  $scope.sex = "male";
  $scope.food = "tacos";
  $scope.hideResultsONE = false;

  // function called when a radio button is clicked
  $scope.radioChange = function() {

    // this could be one line of code, but I find it easier to read using all five lines
    if ($scope.sex == "male" && $scope.food == "tacos") {
      $scope.hideResultsONE = false;
    } else {
      $scope.hideResultsONE = true;
    }

  }
});
<!doctype HTML>
<html data-ng-app="angularSolution">

<body data-ng-controller="angularController">
  <div class="page1">
    <form class="sampler">
      <input type="radio" name="sex" value="male" data-ng-model="sex" data-ng-change="radioChange()">Male
      <br>
      <input type="radio" name="sex" value="female" data-ng-model="sex" data-ng-change="radioChange()">Female
    </form>
  </div>
  <div class="page2">
    <form class="sampler">
      <input type="radio" name="food" value="tacos" data-ng-model="food" data-ng-change="radioChange()">Tacos
      <br>
      <input type="radio" name="food" value="spicynuts" data-ng-model="food" data-ng-change="radioChange()">Rotten Spicy Peanuts
    </form>
  </div>
  <div id="resultsONE" data-ng-hide="hideResultsONE">
    <!-- one results div is display none by default sample but there would be much more content here  -->
    <p>Congratulations, you are NOT the father</p>
  </div>
  <script src="https://ajax.googleapis./ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>

</html>

If you wanted to, you could put the expression to determine whether to show or hide the div inside the data-ng-hide attribute, but I prefer it in code, actually. It's less hidden that way.

Basically, this is the same answer as others have given, but AngularJS has two-way data bound the variables. There is many other things AngularJS will do for you, but that is outside the scope of this question.

If you look back to your original code in the question, this is pretty close. The data binding mean that the variables in $scope are already set up with the values, and showing or hiding merely mean setting another variable, not calling a function directly, but all that is really left in the function is the logic that you described.

Instead of using plicated if statements, I would suggest to add a data attribute on your divs which include the bination of selections you require to have that div show.

I have replaced the values with numeric references to keep the code simple, but it works either way.

Hope I got your requirements right.

http://jsfiddle/kxsb00ps/

HTML:

<div class="page">
    <form class="sampler">
        <input type="radio" name="sex" value="1" />Male
        <br/>
        <input type="radio" name="sex" value="2" />Female</form>
</div>
<div class="page">
    <form class="sampler">
        <input type="radio" name="food" value="1" />Tacos
        <br/>
        <input type="radio" name="food" value="2" />Rotten Spicy Peanuts</form>
</div>
<input id="submitBtn" type="button" value="submit"/>
<div class="results">
    <div data-selection="1,1" >
        <p>You are a male who likes Tacos</p>
    </div>
    <div data-selection="2,1">
        <p>You are a female who likes Tacos</p>
    </div>
    <div data-selection="1,2">
        <p>You are a male who likes Rotten Spicy Peanuts</p>
    </div>
    <div data-selection="2,2">
        <p>You are a female who likes Rotten Spicy Peanuts</p>
    </div>    
</div>

JavaScript (using jQuery for selectors):

$("#submitBtn").click(function(){
    // create an empty array
    var selectedData = [];
    // iterate each page
    $(".page").each(function(){
        // place the selections in an array
        selectedData.push($(this).find("input[type=radio]:checked").val());
    });

    // clear previous results
    $(".results > div").hide();

    // find the div using the data attribute
    $(".results").find("[data-selection='" + selectedData + "']").show();
});

One simple way is to bine the selected values to a div name you want to display. For example if one has the values male and tacos selected the div with the name 'male-tacos' gets displayed.

<html>
    <head>
        <style>
            .result{display: none}
            .page{margin: 10px}
        </style>

        <script>
            //Binding the radio change even on all radio boxes contained in page classes
            function Init(){
                var tL = document.querySelectorAll('.page input[type="radio"]');
                for(var i=0, j= tL.length; i<j; i++) tL[i].onchange = function(){evalAnswers()}
            };

            function evalAnswers(){
                //Getting all checked radio buttons
                var tL = document.querySelectorAll('.page input[type="radio"]:checked');

                //Combining the values to get the result name
                var tS = [];
                for(var i=0, j=tL.length; i<j; i++) tS.push(tL[i].value);

                //Getting the result div
                var tR = document.querySelector('[name="' + tS.join('-') + '"]');

                //If we have no result for the bination showing the __unhandled named div
                if (!tR) tR = document.querySelector('[name="__unhandled"]');

                //Hiding all results again (might not be needed if no replay option)
                var tL = document.querySelectorAll('.result');
                for(var i=0, j=tL.length; i<j; i++) tL[i].style.display = 'none';

                //Showing the result
                if (tR) tR.style.display = 'block';
            }
        </script>
    </head>

    <body onload = 'Init()'>
        <!-- page1 looks more like an id than a class -->
        <div class = 'page' id = 'page1'>
            <input type = 'radio' name = 'sex' value = 'male' checked>Male
            <br>
            <input type = 'radio' name = 'sex' value = 'female'>Female
        </div>

        <div class = 'page' id = 'page2'>
            <input type = 'radio' name = 'food' value = 'tacos' checked>Tacos
            <br>
            <input type = 'radio' name = 'food' value = 'spicynuts'>Spicynuts
        </div>

        <div class = 'page' id = 'page3'>
            <input type = 'radio' name = 'color' value = 'red' checked>Red
            <br>
            <input type = 'radio' name = 'color' value = 'blue'>Blue
        </div>

        <!-- the name is the binations of answers, with this we can select the correct div -->
        <div class = 'result' name = 'male-tacos-red'>
            male-tacos-red
        </div>

        <div class = 'result' name = 'female-tacos-blue'>
            male-tacos-red
        </div>

        <div class = 'result' name = '__unhandled'>
            unhandled result
        </div>
    </body>
</html>

http://fiddle.jshell/31mebxkk/

Like this one may merely change the HTML without worrying about the script itself.

本文标签: javascriptdisplay result divs based on web form radio button selectionsStack Overflow