0

I have a survey builder that I have set up to trigger questions based on whether the question is yes or no. For example I have one form that goes like this.

Thanks any feedback would be great. :)

  1. Have you recently experienced any technical issues while using our software? YES NO

If no, no more questions should be asked, but the last child question pops when it shouldn't, if yes the next question should come up and for some reason using the below JavaScript, it returns false for the question but then loops back through again until it is false.

$(function(){
  $('body').on('change', '.parent_question select, .parent_question input', function(){
    var child_input = $('[name="' + $(this).data('child-name') + '"]');
    console.log(child_input);
    var child_question = child_input.closest('.survey_answers');
    var trigger_on = $(this).data('trigger-on');
    var show = $(this)[0].selectedIndex == undefined ? ($(this).closest('.survey_answers').find('input').index($(this)) + 1) == trigger_on : $(this)[0].selectedIndex == trigger_on;
    if (show) {
      child_question.show();
    } else {
      child_question.hide();
      child_input.val('');
      child_input.attr('checked', false);
      console.log(child_input);
      child_input.trigger('change');
    }
  });
});
  • So do you want to hide all other questions unless `Yes` has been selected? – Twisty Dec 29 '15 at 16:15
  • please format your code properly... it looks crap – Amar Singh Dec 29 '15 at 16:16
  • Yeah @Twisty that is exactly what I want :) – Jorden T Schreck Dec 29 '15 at 16:22
  • the only thing is that I know the child_input.trigger('change'); line is what is making it loop but I'm trying to target only the child input and for some reason any change on the question makes it loop until it returns true. – Jorden T Schreck Dec 29 '15 at 16:23
  • Working on it here: https://jsfiddle.net/Twisty/16tw7q3j/ – Twisty Dec 29 '15 at 16:29
  • Thanks @Twisty I appreciate you helping me with this. :) – Jorden T Schreck Dec 29 '15 at 16:32
  • So far, only made very minor changes (`$('#survey_page').on()`): https://jsfiddle.net/Twisty/16tw7q3j/1/ but this seems to be working the way you described? – Twisty Dec 29 '15 at 16:44
  • Not yet, I don't want the last question to show on no, I want that to be triggered on the result of the third embedded questions answer only. – Jorden T Schreck Dec 29 '15 at 16:48
  • 1
    So as I see it, you have 6 questions, 1, 2, 3, 4, 5, & 6. A Yes for 1, exposes 2. A Yes 2 for exposes 3, A No for 3 exposes 4? Am I following the logic right? – Twisty Dec 29 '15 at 16:50
  • Yeah that is correct :) – Jorden T Schreck Dec 29 '15 at 16:52
  • Ok, what exposes 5 or 6? – Twisty Dec 29 '15 at 16:53
  • those questions stand alone. They are revealed automatically. The other ones are revealed for relevance to the answer. – Jorden T Schreck Dec 29 '15 at 16:55
  • Well Actually 5 is shown automatically, and on not at all satisfied should pop the 6 question :) – Jorden T Schreck Dec 29 '15 at 16:57
  • 5 and 6 seem to work just fine though. – Jorden T Schreck Dec 29 '15 at 16:58
  • All my testing so far has worked with the logic you're suggesting. What am I missing? – Twisty Dec 29 '15 at 17:06
  • If you reload the page at the beginning, you will see the "have you recently experienced any technical issues while using kadince?" If that answer is yes the the question "Do you feel the issue was resolved in a timely manner?" if no "Any comments you'd like us to know shows up, but I don't want it to show up on no to that first question it should show up only on the answer to the third question. – Jorden T Schreck Dec 29 '15 at 17:08
  • Why would a user reload the page? Also this would suggest something is either removing the `.hidden` or triggering `change`. – Twisty Dec 29 '15 at 17:09
  • Its not when they reload. I was just saying so you could see it from the start. – Jorden T Schreck Dec 29 '15 at 17:10
  • I think it is something to do with child_input.trigger('change'); but I need that to clear the child questions input if they select a different answer on the parent question. – Jorden T Schreck Dec 29 '15 at 17:11
  • @Twisty do you have any ideas with that? I have tried using triggerHandler instead and it resolves that, but if someone select yes for the first question and then selects yes for the second and then changes the answer for the first question, the third question stays on the page. So I'm using trigger to make sure that when a answer is change make sure the right things are shown but it also shows the wrong question with that :( – Jorden T Schreck Dec 29 '15 at 17:31
  • I don't see why we are triggering `change`, and thus creating the loop. I think maybe we should refine the selection to radio buttons and make a second function for the question 4, when a change is made to the `textarea`, so that 5 & 6 are exposed when a users enters a comment. – Twisty Dec 29 '15 at 17:40
  • well the reason its radio buttons or select is because I have a survey builder on the back end that creates surveys and the team in charge of customer happiness wants the ability to have radio and select but I want 5 exposed and 6 is working correctly, its 4 that is showing if you select no on 1, 2, or 3 but I only want it to show on no for 3 – Jorden T Schreck Dec 29 '15 at 17:45
  • child_input.attr('checked', false); should be child_input.prop('checked', false); for reference: stackoverflow.com/questions/5874652/prop-vs-attr – Mark Schultheiss Dec 29 '15 at 20:41

2 Answers2

0

After our comment,s I think I have things working the way you want. No changes to HTML, but the JQuery I used is as follows:

$(function() {
  $('#survey_page').on('change',
    '.parent_question select, .parent_question input',
    function() {
      console.log($(this).attr('name') + " selected: " + $(this).val());
      var child_input = $('[name="' + $(this).data('child-name') + '"]');
      //console.log(child_input);
      var child_question = child_input.closest('.survey_answers');
      var trigger_on = $(this).data('trigger-on');
      var show = $(this)[0].selectedIndex == undefined ? ($(this).closest('.survey_answers').find('input').index($(this)) + 1) == trigger_on : $(this)[0].selectedIndex == trigger_on;
      console.log("Show child (" + $(this).data('child-name') + "): " + show);
      if (show) {
        child_question.show();
      } else {
        child_question.hide();
        child_input.val('');
        child_input.attr('checked', false);
        console.log(child_input);
        if (child_input.is("textarea")) {
          console.log("Next item is textarea, triggering change.");
          child_input.trigger('change');
        }
      }
    });
});

Here is a working example: https://jsfiddle.net/Twisty/16tw7q3j/4/

If the users selects specific answers, conditionally, more questions are exposed. If the users goes back and changes an answer, it should reset the conditions on children item.

I moved the change event away from the body to #survey_page, yet either should work. I also conditionally trigger change if the child input is textarea, which I think helps prevent looping. Feel free to test and comment if it's not working as you wanted. Not sure if my test Fiddle matches your environment exactly.

Update

This might be overkill at the moment, but it works: https://jsfiddle.net/Twisty/16tw7q3j/9/

$(function() {
  $('body').on('change', '.parent_question select, .parent_question input', function() {
    var current_input_name = $(this).prop('name');
    var current_input_id = parseInt(current_input_name.substring(24, 26));
    var last_input_name = $(".parent_question:last [name^='survey[answers]']").prop('name');
    var last_input_id = parseInt(last_input_name.substring(24, 26));
    console.log("Change " + current_input_name + "/" + last_input_name + ", " + current_input_id + "/" + last_input_id);
    var child_input = $('[name="' + $(this).data('child-name') + '"]');
    var child_question = child_input.closest('.survey_answers');
    var trigger_on = $(this).data('trigger-on');
    var show = $(this)[0].selectedIndex == undefined ? ($(this).closest('.survey_answers').find('input').index($(this)) + 1) == trigger_on : $(this)[0].selectedIndex == trigger_on;
    if (show) {
      child_question.show();
    } else {
      child_question.hide();
      child_input.val('');
      child_input.prop('checked', false);
    }
    for (var i = current_input_id + 2; i <= last_input_id; i++) {
      console.log("Clearing survey[answers][question" + i + "]");
      var nextElem = $("[name='survey[answers][question" + i + "]']");
      nextElem.parents("div.survey_answers").hide();
      nextElem.val('');
      nextElem.prop('checked', false);
    }
  });
});

I create the scope between the current changed element, skip the child, since that is handled conditionally already, and clear out all the other selections.

Twisty
  • 30,304
  • 2
  • 26
  • 45
  • That is very similar to my solution right now but that brings up a separate issue. For instance in our example, if you go to the link and you answer question 1 with 'yes' and then question 2 with 'yes'. Now go back and change answer 1 to 'no'. That should clear the value for question 2 and question 3 but it only clears and hides question 2. – Jorden T Schreck Dec 29 '15 at 20:19
  • So then we need to clear all inputs that are NOT the one that was just changed, correct? – Twisty Dec 29 '15 at 20:25
  • Yeah :) I'm not sure how to do that in javascript – Jorden T Schreck Dec 29 '15 at 20:25
  • Well all inputs tied to that question we don't want to clear 5 and 6 – Jorden T Schreck Dec 29 '15 at 20:26
  • 1
    `child_input.attr('checked', false);` should be `child_input.prop('checked', false);` for reference: http://stackoverflow.com/questions/5874652/prop-vs-attr – Mark Schultheiss Dec 29 '15 at 20:38
  • Well that works unless I have created multiple questions. The problem is it's a survey that will have multiple first level questions and then child questions based on that. Does that make sense? – Jorden T Schreck Dec 29 '15 at 23:31
  • Yes, and this was designed to be more flexible. Since I do not know the whole scope, I could not know what else would be done. If you want to make a Fiddle that has an example of all the types of elements, then that would have been easier. This is only working with what data I could gleam. – Twisty Dec 30 '15 at 01:15
  • okay. @Twisty I created a jsfiddle with more questions. you can find it here. https://jsfiddle.net/jorden15/9yz45bz8/ – Jorden T Schreck Dec 31 '15 at 21:44
  • @JordenTSchreck this Fiddle appears to have questions 1, 2, & 3, and then repeats question 1 and 2. – Twisty Dec 31 '15 at 23:12
  • Yes it does, but they were generated from my survey builder and they have different names for the second rounds of questions. I only created the same question because it is one of my more in depth questions they want to ask so I need the jquery to work with that. @Twisty – Jorden T Schreck Jan 04 '16 at 16:23
0
$(function(){
  $('body').on('change', '.parent_question select, .parent_question input', function(){
    var child_input = $('[name="' + $(this).data('child-name') + '"]');
    var child_question = child_input.closest('.survey_answers');
    var trigger_on = $(this).data('trigger-on');
    var show = $(this)[0].selectedIndex == undefined ? ($(this).closest('.survey_answers').find('input').index($(this)) + 1) == trigger_on : $(this)[0].selectedIndex == trigger_on;
    if (show) {
      child_question.show();
    } else {
      child_question.hide();
      child_input.val('');
      child_input.prop('checked', false);
    }
  });
});

This code solves the issue I was having but now I want to clear all child_questions values and hide all child questions if someone changes there answer. @Twisty any ideas?

  • Trying to find a way to select all the other inputs based on the element that was changed, and then can use `$.each()` to iterate them all and remove any selections. – Twisty Dec 29 '15 at 21:22
  • Yeah, I still haven't been able to come up with a solution for this. :/ – Jorden T Schreck Dec 29 '15 at 22:30