Quantcast
Channel: iPROFS Technology Blog » mcbeelen
Viewing all articles
Browse latest Browse all 8

AngularJS: A checkbox with radio button behavior

$
0
0

Did you ever needed to have a group of option in which just one item could be selected, but the user did need to have the option to deselect any chosen option in HTML?

It can’t be done just by HTML checkboxes or radio buttons and the user experience of a select with options isn’t sufficient.

We did have to provide such a solution in a recent project.

Real world scenario

In a recent project our customer wanted us to make an application, which could be used to register for upcoming events.
Each events consists of multiple time slots.
In each time slot the user could select only one session which he would attend.
The session had to be presented grouped by the track in which they belong.

Sound like a typical conference like Devoxx or so.

Our first impression was to create a list of radio buttons for each time slot.

One additional requirement was given:

When the user selected a session within a time slot, he should be able to deselect his choice in order unregister for that session
and schedule some additional time off.

Oops, radio-bttons can’t be deselected.

The solution

The model

An event as a list of Timeslot, which has a list of Tracks, which has a list of Session.

Constructing the view for this model can be done with the following Angular HTML code:

<div ng-repeat="timeslot in event.timeslots">
  <div class="timeslot">
    <h4>{{ timeslot.name }}</h4>
      <div ng-repeat="track in timeslot.tracks" class="track">
        <h5>{{ track.name }}</h5>
       <div ng-repeat="session in track.sessions" class="session">
         <input type="checkbox" value="{{ session.sessionGuid}}" />
         {{ session.name }}
      </div>
    </div>
 </div>

Managing the state of the checkbox.

Model binding

In order to keep track of the state of the checkbox it needs te be mapped to some model object in the Angular controller.

With the controller we created a map of sessions with each time slot, which could be use to store the boolean to bind the model on for the checked-state:

function CheckboxAsRadioCtrl($scope) {
  $scope.selectedSessions = {};
 
  $scope.initializeCheckboxModel= function() {
    for(timeslot in $scope.event.timeslots) {
      $scope.selectedSessions[$scope.event.timeslots[timeslot].name] = {}

      for(track in $scope.event.timeslots[timeslot].tracks) {
        for (session in $scope.event.timeslots[timeslot].tracks[track].sessions) {

          var timeSlotName = $scope.event.timeslots[timeslot].name;
          var sessionId = $scope.event.timeslots[timeslot].tracks[track].sessions[session].sessionGuid;

          $scope.selectedSessions[timeSlotName][sessionId ] = false;
        }
      }
    }
  } 
}

This enables us to add the ng-model to the checkbox:

<input type="checkbox"
    ng-model="selectedSessions[timeslot.name][session.sessionGuid]"
    value="{{ session.sessionGuid }}" />

Enforce ‘radio’ behavior

Cool, it is starting to get together, but we needed to enforce the rule that just one session within each time can be selected.
Basically it boils down to: When a session is selected, then all other sessions within the same timeslot need to be deselected.

The trigger for this routine is a change of the state of a checkbox, so we added an changeListener:

<input type="checkbox"
    ng-model="selectedSessions[timeslot.name][session.sessionGuid]"
    ng-change="changeSessionStatus(timeslot.name, session.sessionGuid)"
    value="{{ session.sessionGuid }}" />

This bind any change of the checkbox to a function in the controller, which sets the checked state of all session in the current time slot to false:

    $scope.changeSessionStatus = function(timeSlotName, sessionGuid) {
        for(session in  $scope.selectedSessions[timeSlotName]) {
            if (session != sessionGuid) {
                $scope.selectedSessions[timeSlotName][session] = false;
            }
        }
    }  

The Two-Way Data Binding of AngularJS will remove the check marks from the view.

This method does nothing with the model value bound to checkbox being changed. The new value for that session is determined by the view and updated automatically.

Summary

It would be nice if the HTML input would allow for a ‘native’ solution for this by allowing radio’s to be deselected, but a solution is available.
Check a fully working example at http://jsfiddle.net/m3jK7/


Tagged: angular, checkbox, javascript, radio

Viewing all articles
Browse latest Browse all 8

Latest Images

Trending Articles





Latest Images