codepuzzler codepuzzler - 30 days ago 10
AngularJS Question

Two items per row in ui-bootstrap drop-down menu

I'm trying to create dropdown menus for a web app using only angularjs and ui-bootstrap. The menu is similar to what you see in a desktop application, the menus should display a left justified label, and the hotkey reminder text should be right justified, and on the same row. I'm looking for something like this:

http://imgur.com/WevtfId

The dropdown buttons also need to be inline elements sitting in a toolbar like configuration. I'm creating a component for reuse, where each dropdown menu is backed by an object, so the menu widths must scale in a manner that's appropriate to the length of the longest row in the dropdown.

Here are some examples I threw together in plunker: https://plnkr.co/edit/RAMgcuVoibeLkHTz4Z3e?p=preview

Example 1.A shows the basic problem. When the first span in the dropdown list gets to long, it displaces the second span onto the next line.

<span class="example-inline" uib-dropdown>
<button type="button" class="btn btn-primary" uib-dropdown-toggle>
A. Autowidth Dropdown
</button>
<ul class="dropdown-menu" uib-dropdown-menu>
<li ng-repeat="item in ctrl.items">
<a>
<span style="float:left">{{item.label}}</span>
<span style="float:right; padding-left: 15px;">{{item.hotkey}}</span>
</a>
</li>
</ul>
</span>


Example 2.B has a dropdown that behaves correctly. Unfortunately, I had to attach the uib-dropdown directive to a block element which means that it won't sit nicely in a toolbar without some extra work.

<span class="example-block" uib-dropdown>
<button type="button" class="btn btn-primary" uib-dropdown-toggle>
A. Autowidth Dropdown
</button>
<ul class="dropdown-menu" uib-dropdown-menu>
<li ng-repeat="item in ctrl.items">
<a>
<span style="float:left">{{item.label}}</span>
<span style="float:right; padding-left: 15px;">{{item.hotkey}}</span>
</a>
</li>
</ul>
</span>

.example-block {
padding: 5px 20px;
display: block;
}


In example 1.D, I put a table in the dropdown menu. This gives me the behavior that I want but would involve a larger refactor of my pre-existing functionality.

<span class="example-inline" uib-dropdown>
<button type="button" class="btn btn-primary" uib-dropdown-toggle>
D. Nowrap Table in Dropdown
</button>
<ul class="dropdown-menu" uib-dropdown-menu>
<table style="white-space: nowrap;" class="dropdown-table">
<tr ng-repeat="item in ctrl.items">
<td style="width:90%">
{{item.label}}
</td>
<td style="width:10%">
{{item.hotkey}}
</td>
</tr>
</table>
</ul>
</span>


Is there a cleaner solution here? I would prefer something like 1.A with a few css tweaks. I would like to avoid a large refactor if necessary. Thanks!

Answer Source

One clean solution is using css3 width max-content value

.width-max-content {
  width: max-content;
  width: -moz-max-content;
  width: -webkit-max-content;
}

Have this class on ul element:

<span class="example-inline" uib-dropdown>
    <button type="button" class="btn btn-primary" uib-dropdown-toggle>
     A. Autowidth Dropdown
    </button>
    <ul class="dropdown-menu width-max-content" uib-dropdown-menu>
      <li ng-repeat="item in ctrl.items">
        <a>
          <span style="float:left">{{item.label}}</span>
          <span style="float:right; padding-left: 15px;">{{item.hotkey}}</span>
        </a>
      </li>
    </ul>
</span>

Plunker

Now this works great in chrome, firefox, safari but not in ie, as max-content still not supported in IE (there's no '-ms-max-content' version for IE).

For IE not so clean way is having margin-right to about maximum width of hotkey strings on anchor tags.

.hotkey-margin {
  margin-right: 6em;
}

in template:

<a class="hotkey-margin">
      <span style="float:left">{{item.label}}</span>
      <span style="float:right; padding-left: 15px;">{{item.hotkey}}</span>
</a>

Have it only when dropdown is on inline element. Also, using both max-content & margin right will cause issue in chrome/moz/safari so add condition like this class will be added only in case of IE. (Or you can use this not so clean solution for all browsers & not use max-content width).

Plunker

P.S. I'm considering Example 1.A only. Else 1.D i.e. 'Nowrap Table in Dropdown' would be perfect I guess.