Search code examples
angularjsmodal-dialogdefault-value

How to set default value of custom radio button in a modal


Background:

So I am working with a modal box for searching through a list of task entries within a database using a form to narrow results. In this modal box, there is a custom radio button that's used for selecting whether or not the task is in progress (simple "Yes" or "No" option). The goal is to set the "No" option as the default value whenever the modal is called. Currently, I am using data-ng-init; however, this only works the first time the modal is opened. If the user closes the modal and reopens it, the default value is no longer set. Below is a sample of what this custom button looks like:

<div class="col-sm-6">
      <div style="margin-bottom:10px">
      <button type="button" data-ng-init="tr.taskInProgress('No')" 
          title="Task In Progress: No" data-ng-click="tr.taskInProgress('No')"
          style="border:0;background:transparent">
      <img src="../images/selected.png" data-ng-switch-when="No" />
      <img src="../images/Deselect.png" data-ng-switch-when="Yes"  />
      <img data-ng-switch-when="" src="/nc/images/Deselect.png" /></button>
          <text>No
   </div>
   (another similar button, but for 'yes')
</div>

In the accompanying .js file, the following is used to help populate this modal:

/*--------- Get Tasks ---------*/
tr.closeGetTaskModal = closeGetTasModal;
tr.displayGetTaskMessage = true;
tr.selectedStatusType = getStatusType;
tr.trackingId = '';
tr.performGetTask = performGetTask;
tr.isTaskInProgess = isTaskInProgress;

And, in the same .js file, the following function is used to modify the radio:

function isTaskInProgress(newValue) {
    tr.isTaskInProgress = newValue;
}

I have been looking through others iterations on how they handle such cases, but I have been unlucky and have not found anything similar enough to what I am working with that works. I have tried setting the default in the Get Tasks section by modifying isTaskInProgress('No'), but this only locked the modal and I couldn't modify the option. I have tried setting the default inside the isTaskInProgress function; however, this only worked when the button was clicked, it failed to set a default. I tried seeing if data-ng-default would work; however, this didn't seem to be a recognized parameter. Does anyone have suggestions on how to modify this to get the desired results? Thank you all in advance for your help


Solution

  • Small Disclaimer

    I am taking the liberty of assuming you are using UI Bootstrap (since I see bootstrap classes in your sample HTML), so will be using Uib Modal in my example.

    Bootstrap Modal docs: https://angular-ui.github.io/bootstrap/#!#modal


    Resolver / Callback Solution

    You will most likely want to use the controller to set your tr.isTaskInProgress flag rather than using the ng-init directive (a bit more flexibility / readability).

    Set tr.isTaskInProgress to false at the top of your target controller function, then pass its value to your modal as a property in a "Modal Resolve Object".

    Bootstrap's explanation of the Resolve Object: https://angular-ui.github.io/bootstrap/#!#ui-router-resolves


    Code

    function MainController($scope, $uibModal) {
        let vm = this;
        vm.isTaskInProgress = false;
    
        // When you open the modal, pass in the isTaskProgress value
        let modalInstance = $uibModal.open({
             templateUrl: 'myModalContent.html', // Points to the script template
             controller: 'ModalController', // Points to the controller
             controllerAs: 'mc',
             windowClass: 'app-modal-window',
             backdrop: 'static',
             resolve: {
                  isTaskInProgress: function() {
                       // pass the task state to the Modal
                       return vm.isTaskInProgress;
                  }
             }
         });
    
      // handle the value(s) passed back from the modal
      modalInstance.result.then(returnedTaskState => {
        // reassign the returned value of the modal
        if (returnedTaskState !== null) {
          vm.isTaskInProgress = returnedTaskState;
        }
      });
    }
    

    Working Example

    https://plnkr.co/ryK7rG

    In the interest of time, I've changed some of the variable / method names from what you have in your snippets. In the example, you can...

    • Set the In Progress value before you open the modal and the modal reflects the In Progress value.
    • Change the In Progress value inside the modal. On closing the modal, the value will be updated in the main page.

    SO Snippet

    I realize the SO Snippet window is not exactly the best place for this example, but just tossing my example code in here in case Plunker is inconvenient for some reason.

    (function() {
      "use strict";
    
      let app = angular
        .module("myApp", ["ui.bootstrap"])
        .controller("MainController", MainController);
    
      MainController.$inject = ["$scope", "$timeout", "$uibModal"];
    
      function MainController($scope, $timeout, $uibModal) {
        /**
         * John Papa Style Guide
         * https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md
         * */
        let vm = this;
    
        // ==== scoped variables ====
        vm.title = "AngularJS - Passing Toggled Values to a Modal"
        vm.taskInProgress = false;
        vm.taskButtonLocked = false;
    
        // ==== functions hoist ====
        vm.beginTask = _beginTask;
    
        function _beginTask() {
          vm.modalIsOpen = true;
    
          // do work
    
          openModal();
        }
    
        // ==== local functions ====
        function openModal() {
          // open the modal with configurations
          let modalInstance = $uibModal.open({
            templateUrl: 'myModalContent.html', // Points to my script template
            controller: 'ModalController', // Points to my controller
            controllerAs: 'mc',
            windowClass: 'app-modal-window',
            backdrop: 'static',
            resolve: {
              taskInProgress: function() {
                // pass the task state to the Modal
                return vm.taskInProgress;
              }
            }
          });
    
          // handle the value(s) passed back from the modal
          modalInstance.result.then(returnedTaskState => {
            // reset control values after modal is closed
            vm.taskButtonLocked = false;
            vm.modalIsOpen = false;
    
            // reassign the returned value of the modal
            console.log("returnedTaskState: ", returnedTaskState);
    
            if (returnedTaskState !== null) {
              vm.taskInProgress = returnedTaskState;
            }
          });
        }
      }
    
    })();
    
    (function() {
      'use strict';
    
      angular
        .module('myApp')
        .controller('ModalController', ModalController);
    
      ModalController.$inject = ['$scope', '$timeout', '$uibModalInstance', 'taskInProgress'];
    
      function ModalController($scope, $timeout, $uibModalInstance, taskInProgress) {
    
        // Assign Cats to a Modal Controller variable
        let vm = this;
        
        vm.inProgress = taskInProgress;
        
        console.log("taskInProgress", taskInProgress)
    
        $scope.submit = function() {
          $uibModalInstance.close(vm.inProgress);
        }
    
        $scope.close = function() {
          $uibModalInstance.close(null);
        }
      }
    })();
    input[type="radio"]:hover {
      cursor: pointer;
    }
    <!DOCTYPE html>
    <html>
    
    <head>
      <meta charset="utf-8" />
      <title>AngularJS Plunk</title>
    
      <link rel="stylesheet" href="style.css" />
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
    
      <!-- JQuery and Bootstrap -->
      <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    
      <!-- Angular Stuff -->
      <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.8/angular.js"></script>
      
       <!-- UI Bootstrap Stuff -->
      <script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/2.5.0/ui-bootstrap-tpls.min.js"></script>
    
      <!-- Our Angularjs App -->
      <script type="text/javascript" src="app.js"></script>
    </head>
    
    <body ng-app="myApp" ng-controller="MainController as tr">
    
      <!-- ==== MAIN APP HTML ==== -->
      <div class="container" style="padding:1em;">
        <div class="row">
          <div class="col-xs-12">
            <div class="jumbotron text-center">
              <h2>{{ tr.title }}</h2>
              <h4><em><a href="https://stackoverflow.com/questions/55362380/how-to-set-default-value-of-custom-radio-button-in-a-modal" target="_blank">SO Question #55362380</a></em></h4>
              <h4><em><a href="https://angularjs.org/" target="_blank">AngularJS - v1.7.8</a></em></h4>
            </div>
          </div>
          <div class="col-xs-12">
            <form>
              <div class="form-group">
                <h3>Task In Progress</h3>
                <div>
                  <label>Yes:</label>
                  <input type="radio"
                         ng-checked="tr.taskInProgress"
                         ng-click="tr.taskInProgress = true"
                         ng-disabled="tr.modalIsOpen">
                </div>
                <label>No:</label>
                <input type="radio" 
                       ng-checked="!tr.taskInProgress"
                       ng-click="tr.taskInProgress = false" 
                       ng-disabled="tr.modalIsOpen">
              </div>
              <div class="form-group">
                <label>Open the modal:</label>
                <button type="button" 
                        class="btn btn-success" 
                        ng-click="tr.beginTask();" 
                        ng-disabled="tr.taskButtonLocked">
                  <span>Begin Task</span>
                </button>
              </div>
            </form>
          </div>
        </div>
      </div>
      
      <!-- ==== MODAL HTML TEMPLATE ==== -->
       <script type="text/ng-template" id="myModalContent.html">
        <div class="modal-header">
          <h3 class="modal-title" id="modal-title">I'm a modal!</h3>
        </div>
        <div class="modal-body" id="modal-body">
            <form>
              <div class="form-group">
                <label>Task State:</label>
                <div style="padding:1em;background:rgba(200, 214, 229,0.3);">
                  <p>
                    <span ng-show="!mc.inProgress">
                      <span>Task is not in progress...&nbsp;&nbsp;</span>
                      <i class="fa fa-check-square" aria-hidden="true"></i>
                    </span>
                    <span ng-show="mc.inProgress">
                      <span>Task is in progress...&nbsp;&nbsp;</span>
                      <i class="fa fa-spinner fa-spin" aria-hidden="true"></i>
                    </span>
                  </p>
                </div>
              </div>
              <div class="form-group" style="padding-top:1em;">
                <h3>Task In Progress</h3>
                <div>
                  <label>Yes:</label>
                  <input type="radio"
                         ng-checked="mc.inProgress"
                         ng-click="mc.inProgress = true">
                </div>
                <label>No:</label>
                <input type="radio" 
                       ng-checked="!mc.inProgress"
                       ng-click="mc.inProgress = false">
              </div>
            </form>
          </div>
        <div class="modal-footer">
          <button class="btn btn-primary" type="button" ng-click="submit()">OK</button>
          <button class="btn btn-warning" type="button" ng-click="close()">Cancel</button>
        </div>
      </script>
    
    </body>
    
    </html>