Will2070
Will2070

Reputation: 41

Show / Hide elements dynamically in AngularJs

I'm currently experimenting with Angular and I have an issue, I have a set of questions from my API, some of them rely on other ones to be checked as yes when its a radio button question and will have a value in the property called ReliesOnID.

Once I check yes, the question which relies on the current one being checked needs to show.

I come from a jQuery background so I would do a function passing in the reliesonid as that will be the question number and do something like $('#question' + reliesonid').show().

How can I make the radio buttons show the other question when I click yes as they are in a repeat? Been stuck on this for ages so help is greatly appreciated. Here is my code below:

<div id="question{{question.Number}}" ng-repeat="question in questions" ng-class="question.ReliesOnID == null ? 'here' : 'hidden'">
    <div ng-if="question.QuestionTypeID == 3" >
        <div class="row">
            <div class="col-xs-12">
                <h5>{{question.Question}}</h5>
            </div>
        </div>
        <div class="row">
            <div class="col-xs-2">
                <div class="col-xs-4"></div>
                <div class="col-xs-8">
                    <input type="radio" value="yes" name="{{question.Number}}"  /><label>Yes</label>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-xs-2">
                <div class="col-xs-4"></div>
                <div class="col-xs-8">
                    <input type="radio" value="no" name="{{question.Number}}" /><label>No</label>
                </div>
            </div>
        </div>
    </div>
    <div ng-if="question.QuestionTypeID == 1">
        <div class="row">
            <div class="col-xs-12">
                <h5>{{question.Question}}</h5>
            </div>
        </div>
        <div class="row">
            <div class="col-xs-4">
                <input type="text" class="form-control" />
            </div>
        </div>
    </div>
</div>


EDIT: Data structure is:

{
    "Active": true,
    "Comments": false,
    "DecimalPlaces": 0,
    "F": false,
    "FP": false,
    "Grouped": null,
    "ID": 20500,
    "Length": false,
    "MP": true,
    "Multiline": false,
    "Number": 45,
    "NumericOnly": false,
    "Optional": false,
    "Question": "How long ago was the treatment?",
    "QuestionID": 45,
    "QuestionSectionID": 2,
    "QuestionTypeID": 2,
    "QuestionnaireID": 298,
    "ReliesOnAnswer": true,
    "ReliesOnID": 44,
    "Weight": false
}

Upvotes: 4

Views: 4687

Answers (4)

Mohit Tanwani
Mohit Tanwani

Reputation: 6628

Try this snippet.

Is it something, you're looking for?

I tried to understand your question, and created an example based on your JSON data structure.

Based on the selection of particular question, it will show it's answer only.

Edit-1 : Applied Angular Element

If jQuery is available, angular.element is an alias for the jQuery function. If jQuery is not available, angular.element delegates to Angular's built-in subset of jQuery, called "jQuery lite" or jqLite.

More information angular.element

You can do eliminate jQuery from code, if you want.

You can do the set / get class in Angular by using angular.element as shown over here.

var myApp = angular.module('myApp',[]);

myApp.controller('GreetingController', ['$scope', function($scope) {
  $scope.questions = [
    {
    "Active": true,
    "Comments": false,
    "DecimalPlaces": 0,
    "F": false,
    "FP": false,
    "Grouped": null,
    "ID": 20500,
    "Length": false,
    "MP": true,
    "Multiline": false,
    "Number": 45,
    "NumericOnly": false,
    "Optional": false,
    "Question": "How long ago was the treatment?",
    "QuestionID": 45,
    "QuestionSectionID": 2,
    "QuestionTypeID": 2,
    "QuestionnaireID": 298,
    "ReliesOnAnswer": true,
    "ReliesOnID": 10,
    "Weight": false,
    "Answer": '2 years ago'
    },
    {
    "Active": true,
    "Comments": false,
    "DecimalPlaces": 0,
    "F": false,
    "FP": false,
    "Grouped": null,
    "ID": 20500,
    "Length": false,
    "MP": true,
    "Multiline": false,
    "Number": 45,
    "NumericOnly": false,
    "Optional": false,
    "Question": "Who is God of cricket?",
    "QuestionID": 45,
    "QuestionSectionID": 2,
    "QuestionTypeID": 2,
    "QuestionnaireID": 298,
    "ReliesOnAnswer": true,
    "ReliesOnID": 20,
    "Weight": false,
    "Answer": 'Sachin Tendulkar'
    }
  ]
  
  //Function when radio button clicked
  $scope.flagChange = function(){
    var reliesId = angular.element(event.target).attr('data-reli-id');
    var value = angular.element(event.target).attr('data-value');
    //Based on the condition it will show / hide the respective element
    if(value == "yes")
    {
      $('#'+reliesId).removeClass('hide').addClass('show');
    }
    else
    {
      $('#'+reliesId).removeClass('show').addClass('hide');
    }
  }
}]);
.show
{
  display: block; 
}
.hide
{
  display: none; 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="GreetingController">
  <div ng-repeat="question in questions track by $index">
        {{question.Question}}
        <input type="radio" name="Flag_{{$index}}" ng-click="flagChange($event)" data-value="yes" data-reli-id='{{question.ReliesOnID}}' />Yes
        <input type="radio" name="Flag_{{$index}}" ng-click="flagChange($event)" data-value="no" data-reli-id='{{question.ReliesOnID}}' />No
        <span ng-show="custom_$index">{{question.Answer}}</span>
    <br/>
        <div id="{{question.ReliesOnID}}" class="hide">
            Question based on ReliesOnID : {{question.ReliesOnID}}
        </div>
    <br/>
  </div> 
</div>

Upvotes: 1

taguenizy
taguenizy

Reputation: 2265

You need to use ng-model for your answers like:
<input type="radio" value="yes" ng-model="question.Answer" name="{{question.Number}}"/><label>Yes</label>

And then inside that question you could have sub questions and would just use ng-repeat.

ng-if="question.subQuestions && question.Answer !== undefined" ng-repeat="subquestion in question.subQuestions"

This will all depends on your question structure of course

EDIT
Based on your structure I would say you need an ng-if in your ng-repeat that could go something like this:
ng-if="!question.ReliesOnID || wasAnswered(question.ReliesOnID)"

In wasAnswered function you would need access to the questions array and filter for that ID and check if it was answered and return true or false

Upvotes: 1

Andurit
Andurit

Reputation: 5762

Edit: based on comments below and provided data structure:

If assumed that you want to iterate just that questions which are parent and doesn't related on anything at start. Related should be display only when ratio is set on true:

So replace yourng-repeat with ng-repeat-start which will make you able iterate multiple divs not just on where ng-repeat is on.

In your <div> element add :

 <input type="radio" ng-model="question.subQuestion" value="true"> <br/>
 <input type="radio" ng-model="question.subQuestion" value="false"> <br/>

After that make another <div> below which will display your related questions. It can looks like:

// ng-if here to display only when radio was set to true
<div class="relatedQuestion" ng-repeat-end ng-if="question.subQuestion">
  <div ng-repeat="relatedQ in getRelatedQuestion(question.Number)">
    // Here you display your related questions
  </div>
</div>

So in your controller you need to add a function:

function getRelatedQuestion(number) {
  // logic comes here which filter question
  // which have property relatedOnId === number;
  // it should be an array of objects to iteratee over it.
}


What you present as an option from JQUERY is possible in angular as well. However there is prolly even easier solution.

In your ng-repeat solution you replace your radio input with something like:

 <input type="radio" ng-model="question.subQuestion" value="true"> <br/>
 <input type="radio" ng-model="question.subQuestion" value="false"> <br/>

And then below you add this:

 <div ng-if="question.subQuestion">
     // Your subQuestion code comes here
 </div>

Everything will be inside of your ng-repeat and should work correctly without additional logic in controller.

Upvotes: 0

Ross Rawlins
Ross Rawlins

Reputation: 667

I dont like to use ng-if as that adds and removes the elements to the DOM. Below is a link to the ng-show/hide and a tutorial on how to use it on scotch.io.

https://docs.angularjs.org/api/ng/directive/ngShow

https://scotch.io/tutorials/how-to-use-ngshow-and-nghide

So a quick example would be below where the div element will only show when the variable is_active is true(this check can work with booleans or a text check). And this variable can be set in the controller or in the view. You dont need to toggle this. The div will automaticall hide when the evaluation is not true; so no need for a ng-hide and ng-show on the same element unless you are checking against multiple conditions.

<input type="radio" ng-model="question.subQuestion" value="true"> <br/>
 <input type="radio" ng-model="question.subQuestion" value="false"> <br/>

 <div ng-show="question.subQuestion">
     // Your subQuestion code comes here
 </div>

Upvotes: 0

Related Questions