0

Requirement : selection of radio buttons should bring their respective input boxes. Below is the part of my html and controller. I am using ng-change to invoke the function written in controller. The function in controller just shows the div using jquery. fyi, My template is rendering and I don't see any error on console and functions in controller are getting invoked too.

Issue - On the click on radio button, respective div is is not rendering. Any hints are highly appreciated.

<div ng-app="app" ng-controller="FestCtrl">
   <form name="addForm" class="form-horizontal" ng-submit="submitForm(fest)">
      <!-- Options to user to either enter a new role OR select from an existing     one's -->
      <div class="btn-group" data-toggle="buttons">
         <label class="btn btn-primary">
         <input type="radio" name="options" id="option1" autocomplete="off" ng-model="value" ng-change="newfest()"> New
         </label>
         <label class="btn btn-primary">
         <input type="radio" name="options" id="option2" autocomplete="off" ng-model="value" ng-change="existingfest()"> Existing
         </label>
      </div>
      <br>
      <br>
      <!-- Respective input will be presented depending on above selection-->
      <div id="addNewDiv" class="form-group">
         <label class="control-label" for="InputId">New</label>
         <input required type="text" class="form-control" id="groupIdInput" placeholder="Insert new fest" ng-model="fest.role">
      </div>
      <div id="selectExistingDiv" class="form-group">
         <label for="select1">Select</label>
         <select ng-model="fest.role" class="form-control" id="select1" ng-options="val for val in festArray">
            <option value="">Select</option>
         </select>
      </div>
   </form>
</div> 



var app = angular.module('App');
app.controller('FestCtrl', ['$scope', '$state', function($scope, $state) {
    $(function() {
        $("[data-hide]").on("click", function() {
            $(this).closest("." + $(this).attr("data-hide")).hide();
        });
    });
    $("#addNewDiv").hide();
    $("#selectExistingDiv").hide();
    $scope.newRole = function() {
        $("#addNewDiv").show();
    }
    $scope.existingRole = function() {
        $("#selectExistingDiv").show();
    }
}]);
Sachila Ranawaka
  • 39,756
  • 7
  • 56
  • 80
fixit
  • 87
  • 1
  • 9

2 Answers2

2

One of the key problems you're facing in this case is a result of your use of jQuery in combination with Angular. Among other problematic areas, (which are discussed in this question Is that a good practice to use jQuery with AngularJS?) you are interacting with a polluted global scope by referencing the $. Angular uses a lot of $ prefixed methods in it's namespace.

Inside your angular controller, you won't even have a reference to the Window object which is what jQuery attaches it's namespace ($) to. In Angular, if you need a reference to the window object, you can use the $window provider https://docs.angularjs.org/api/ng/service/$window.

Lastly on the subject of using jQuery in combination with angular, there are certainly instances where you need to touch the DOM. Angular's paradigm for handling this is called directives. Directives aren't incredibly easy to understand, and are out of scope of this answer, but I encourage you to read more about them here -> https://docs.angularjs.org/guide/directive.

Here's a working example of how this could work.

function FestController($scope) {

  $scope.state = {
    selected: 0,
    fest: {
      role: ""
    }
  };

}
angular.module("bacon", []);
angular.module("bacon").controller("FestController", FestController);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="bacon" ng-controller="FestController">
  {{state.selected}}
  <input type="number" ng-model="state.selected" />
  <form class="form-horizontal" id="addForm" name="addForm" ng-submit="submitForm(fest)">
    <!-- Options to user to either enter a new role OR select from an existing     one's -->
    <div class="btn-group" data-toggle="buttons">
      <label class="btn btn-primary">
        <input autocomplete="off" id="option1" name="options" ng-model="state.selected" ng-value="0" type="radio"> New</label>
      <label class="btn btn-primary">
        <input autocomplete="off" id="option2" name="options" ng-model="state.selected" ng-value="1" type="radio"> Existing</label>


    </div>
    <!-- Respective input will be presented depending on above selection-->

    <div class="animate-switch-container" ng-switch="state.selected">

      <div class="form-group" id="addNewDiv" ng-switch-when="0">
        <h1>
          {{state.fest.role}}
        </h1>
        <label class="control-label" for="InputId">New</label>
        <input class="form-control" id="groupIdInput" ng-model="state.fest.role" placeholder="Insert new fest" required="" type="text">
      </div>
      <div class="form-group" id="selectExistingDiv" ng-switch-when="1">

        <label for="select1">Select</label>
        <select class="form-control" id="select1" ng-model="state.fest.role" ng-options="val for val in festArray">
          <option value="">
            Select
          </option>
        </select>
      </div>
    </div>
  </form>
</div>

You can see that I've completely removed any reference to jQuery, and any reference to direct DOM manipulation.

I've chosen to use the ng-switch built-in angular directive which you can read up on here https://docs.angularjs.org/api/ng/directive/ngSwitch

Moving the state into an object attached to $scope inside the controller allows those values to be referenced in the template and allows two-way binding to work.

I did also remove your functions on the controller to emphasize the two-way binding using the switch directive. Stuff happens when those values are updated on $scope. Whether you choose to rely on this specific implementation or not is a matter of preference and architecture, but this is one way you can accomplish your task.

Luke Tully
  • 133
  • 8
  • Tolly, Thanks for the much detailed explanation and totally acceptable that one should not use jQuery along with angular. but with your answer am very close to my requirement. Question - demo looks perfect but when am integrating into my application, the click on radio button is not working and when I select in the number in input box () respective div shows up. Please let me know, if am missing anything. I guess we need to remove class="data-toggle="buttons"" – fixit Feb 20 '17 at 22:51
  • Could be a number of things going on there. Easy to miss that I've initialized the value of state.selected to 0 and you may not need the ng-value directive on the inputs. If you could fork the example and show me the code you're now working with I can take a look. – Luke Tully Feb 20 '17 at 23:02
  • After removing the class="data-toggle="buttons"" things works for me. state.selected to 0 is fine as I introduced a default radio button as well and removing the ng-value directive from inputs does not bring up the required div, so ng-model and ng-value needs to be present for it to work (just tried at my end) – fixit Feb 21 '17 at 00:51
  • Glad to hear it. If this is the route you decided to move forward with would you mind accepting my answer? – Luke Tully Feb 23 '17 at 09:02
  • Thanks Luke, I took your above provide guidance :) – fixit Feb 23 '17 at 15:46
  • @PranavVR Could you be more specific? – Luke Tully Jan 19 '18 at 21:44
0

newfest and existingfest methods does not exists in your controller. You have:

    $scope.newRole = function() {
        $("#addNewDiv").show();
    }
    $scope.existingRole = function() {
        $("#selectExistingDiv").show();
    }

change

<input type="radio" name="options" id="option1" autocomplete="off" ng-model="value" ng-change="newfest()">

to

<input type="radio" name="options" id="option1" autocomplete="off" ng-model="value" ng-change="newRole()">
Carlos Arauz
  • 805
  • 6
  • 8