2

A form has 2 fields, a selector and a (sometimes) non editable input field. When the user selects something in the selector both fields are filled. The selector shows a date-time and a related label goes to the non editable field. To make the selection more user friendly I need to display in the selector dropdown the data-time concatenated with the label to allow the user to chose the rigth option if two options have the same date but different label. The problem is that after the user chooses an option then the selected value in the selector should have just the date and not the label (this is just shown in its own field). I have added two images to make it clear.

This is the Session Group dropdown with the concatenated date-time and label: enter image description here

When a value is selected the label should be removed from the display value, since it is shown in the Thermal Profile field:

enter image description here

The ng-options code of the selector looks like this:

ng-options="opt.id as ((opt.sessions_datetime | date:'short') + ' (' + (opt.thermal_profiles_label || '') + ')') for opt in selectors.sessions_groups"

How can the label be added only when the dropdown is displayed, but not when the selector shows the selected value?

I have created a simplified Plunker here:

https://plnkr.co/edit/aDVOFuojDhFSV15BdPU0?p=preview

Note: AngularJS 1.5.0

David Casillas
  • 1,801
  • 1
  • 29
  • 57

2 Answers2

3

I think the best solution for your problem is add "group by thermal_profiles_label" in ng-options.

<select ng-model="selected"
        ng-options="opt.id as (opt.sessions_datetime | date:'short') group by opt.thermal_profiles_label for opt in selectors.sessions_groups">
</select>

An alternative solution (not recommended ) could be to hide thermal_profiles_label if selected:

<select ng-model="selected"
        ng-options="opt.id as ((opt.sessions_datetime | date:'short') + (selected != opt.id ? ( '(' + (opt.thermal_profiles_label || '') + ')' ) : '') ) for opt in selectors.sessions_groups">
</select>

Check here an example in plunker: https://embed.plnkr.co/kmgCLaXw9Ixo4nADOzlV/

Mario Padilla
  • 521
  • 5
  • 19
1

Ternary conditions are really helpful getting workaround for these kind of issues. To get a workaround for your requirement, I've used the same approach (ternary conditions). What is happening here is whenever a value is selected, you can save the id of that selected value and then make a decision on the base of that id whether to hide or show the labels.

here is the full code.

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

app.controller('MainCtrl', function($scope) {

  $scope.session = {
    sessions_groups_id: null,
    thermal_profiles_id: null
  }
  $scope.sessions_groups = [{
    id: 0,
    sessions_datetime: '2017-11-17',
    thermal_profiles_id: 0,
    thermal_profiles_label: 'Baseline'
  }, {
    id: 1,
    sessions_datetime: '2017-11-17',
    thermal_profiles_id: 1,
    thermal_profiles_label: '+24h'

  }];
  $scope.thermal_profiles = [{
    id: 0,
    label: 'Baseline'
  }, {
    id: 1,
    label: '+24h'
  }, {
    id: 2,
    label: '+36h'
  }];
  $scope.sessionsGroupsChange = function(thermal_profiles_id) {
     $scope.sessions_groups.map((e)=>{ 
     if(e.id == thermal_profiles_id)
      $scope.session.thermal_profiles_id = e.thermal_profiles_id
   });
  }

});
<script data-require="angular.js@1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
<!DOCTYPE html>
<html ng-cloak ng-app="plunker">

  <head>
    <meta charset="utf-8" />
    <title>AngularJS Plunker</title>
    <script>document.write('<base href="' + document.location + '" />');</script>
    <link rel="stylesheet" href="style.css" />
    
     
  </head>

  <body ng-controller="MainCtrl">
    
    <p><b>Sessions Groups selector</b>
    <br/>
    The dropdown displays the date concatenated with the thermal profile label
    <br/>
    But after selecting a value it should only display the date. The thermal profile label will be visible in the thermal profiles selector 
    </p>
  <select id="sessions_groups_id"
    name="sessions_groups_id"
    ng-model="session.sessions_groups_id"
    ng-change="sessionsGroupsChange(session.sessions_groups_id)">
   <option ng-repeat="r in sessions_groups" value="{{r.id}}" >
     {{r.sessions_datetime }} {{session.sessions_groups_id == r.id ? '' : '(' + r.thermal_profiles_label +')'  }} 
   </option> 
   </select>
   
  <br/>
  
    <p><b>Thermal Profile selector</b>
    <br/>
    Displays the thermal profile label asociated with the value selected in the previuos selector.
    <br/>
    Here it is always disabled but in real app can be enabled under some conditions.
    </p>
  <select id="thermal_profiles_id"
   name="thermal_profiles_id"
   ng-model="session.thermal_profiles_id"
   ng-disabled="true"
   ng-options="opt.id as opt.label for opt in thermal_profiles">
   <option value></option>
  </select> 
  </body>

</html>

Ps. It's always confusing for me to use ng-options angular directive, that's why I prefer to use ng-repeat on <option>. This just makes things more easy to understand.

There was another problem of page/template loading in your application. Please have a look at ngCloak. I've used this app to smoothen up the template loading. What ngCloak does is

The ngCloak directive is used to prevent the Angular html template from being briefly displayed by the browser in its raw (uncompiled) form while your application is loading. Use this directive to avoid the undesirable flicker effect caused by the html template display.

Hope this was helpful.

Muhammad Usman
  • 10,039
  • 22
  • 39
  • I like your approach and it gives me some ideas but there is a minor feature. The thermal profiles label is always hidden for the selected value, both in the selector and in the drop down. The idea was have it hidden only in the input selector, but show it in the drop down no matter if it is the selected value or not. – David Casillas Nov 18 '17 at 09:26