Pretty auto-layout of 2 ng-grids (master/detail) whose width changes based on content (CSS at runtime)

StackOverflow https://stackoverflow.com/questions/23379575

  •  12-07-2023
  •  | 
  •  

Question

A previous S.O question, is there a way to auto adjust widths in ng-grid? describes how to automatically adjust the width of an ng-grid by adjusting the width of each column to fit the longest data in any row of that column.

I want to do that based on JSON data received periodically from a server, which means that the grid's contents and, therefor, width will change from time to time. The referenced solution should handle that.

However, I have 2 grids (master/detail) which I will to display side by side on the page.

+------------+      +-----------+
| master     |      | detail    |
+------------+      +--------- -+
| customer 1 |      | Order 1,a |
+------------+      +-----------+
| customer 2 |      | Order 1,b | 
+------------+      +-----------+
| customer 3 |      
+------------+      

something like that.

The problem is that I would like to lay them out prettily on the web page. Let's say an equal sized left & right margin, so the the grids don't hot the side of the page, but are indented a little. Then out the grids in the centre, with some space between them.

Perhaps the centres of the grids, regardless of width could be at 25% and 75% of the page respectively (or 30% and 70%, etc)

--------------------------------------------
|                                          |
|      +---+             +_____________+   |
|      |   |             |             |   |
|      +---+             +_____________+   |
|                                          |
--------------------------------------------

I can work out the aesthetics & the mathematics of it, although questions are welcome.

I am sure that I am not the first to do something like this. My question is how?

I am thinking that I may have to naughty and put style="width:{{masterGridthWidth}} type inline CSS directly into my HTML and have something likeng-style="getMasterGridthWidth()" on the element, to allow me to effectively generate CSS at run-time.

Is this even possible (I don't think thatng-class would help)? Is there a better way to do it?


[Update] I agree with @MichalCharemza that 1) it's best to use a pure CSS fix if I can, rather than involving JS, and 2) fixed width grids would be a better UX.

My problem is that the first two grids are both full screen width, appearing above each other, rather than side by side.

Where are these widths of 1198px coming from (it looks like the official ng-grid.css), and how can I override them? I tried adding `style="width:25%" in my partial. I even wrapped the grid in another DIV with width 25%, to no avail.

I am stuck :-(

<div class="ngTopPanel ng-scope" ng-class="{'ui-widget-header':jqueryUITheme, 'ui-corner-top': jqueryUITheme}" ng-style="topPanelStyle()" style="width: 1198px; height: 45px;">
    <div class="ngGroupPanel ng-hide" ng-show="showGroupPanel()" ng-style="groupPanelStyle()" style="width: 1198px; height: 32px;">
        <div class="ngGroupPanelDescription ng-binding" ng-show="configGroups.length == 0">Drag a column header here and drop it to group by that column.</div>
        <ul ng-show="configGroups.length > 0" class="ngGroupList ng-hide">
            <!-- ngRepeat: group in configGroups -->
        </ul>
    </div>
    <div class="ngHeaderContainer" ng-style="headerStyle()" style="width: 1198px; height: 45px;">
        <div ng-header-row="" class="ngHeaderScroller" ng-style="headerScrollerStyle()" style="height: 45px;"><!-- ngRepeat: col in renderedColumns --><div ng-style="{ height: col.headerRowHeight }" ng-repeat="col in renderedColumns" ng-class="col.colIndex()" class="ngHeaderCell ng-scope col0 colt0">
    <div class="ngVerticalBar" ng-style="{height: col.headerRowHeight}" ng-class="{ ngVerticalBarVisible: !$last }">&nbsp;</div>
    <div ng-header-cell=""><div class="ngHeaderSortColumn  ngSorted" ng-style="{'cursor': col.cursor}" ng-class="{ 'ngSorted': !col.noSortVisible() }" draggable="true" style="cursor: pointer;">
    <div ng-click="col.sort($event)" ng-class="'colt' + col.index" class="ngHeaderText ng-binding colt0">Vehicle type</div>
    <div class="ngSortButtonDown ng-hide" ng-click="col.sort($event)" ng-show="col.showSortButtonDown()"></div>
    <div class="ngSortButtonUp" ng-click="col.sort($event)" ng-show="col.showSortButtonUp()"></div>
    <div class="ngSortPriority ng-binding"></div>
    <div ng-class="{ ngPinnedIcon: col.pinned, ngUnPinnedIcon: !col.pinned }" ng-click="togglePin(col)" ng-show="col.pinnable" class="ng-hide ngUnPinnedIcon"></div>
</div>
<div ng-show="col.resizable" class="ngHeaderGrip ng-scope ng-hide" ng-click="col.gripClick($event)" ng-mousedown="col.gripOnMouseDown($event)"></div>
</div>
</div><!-- end ngRepeat: col in renderedColumns --></div>
    </div>
    <div ng-grid-menu=""><div ng-show="showColumnMenu || showFilter" class="ngHeaderButton ng-scope ng-hide" ng-click="toggleShowMenu()">
    <div class="ngHeaderButtonArrow"></div>
</div>
<div ng-show="showMenu" class="ngColMenu ng-scope ng-hide">
    <div ng-show="showFilter" class="ng-hide">
        <input placeholder="Search..." type="text" ng-model="filterOptions.filterText" class="ng-pristine ng-valid">
    </div>
    <div ng-show="showColumnMenu" class="ng-hide">
        <span class="ngMenuText ng-binding">Choose Columns:</span>
        <ul class="ngColList">
            <!-- ngRepeat: col in columns | ngColumns --><li class="ngColListItem ng-scope" ng-repeat="col in columns | ngColumns">
                <label class="ng-binding"><input ng-disabled="col.pinned" type="checkbox" class="ngColListCheckbox ng-pristine ng-valid" ng-model="col.visible">Vehicle type</label>
                <a title="Group By" ng-class="col.groupedByClass()" ng-show="col.groupable &amp;&amp; col.visible" ng-click="groupBy(col)" class="ngGroupIcon"></a>
                <span class="ngGroupingNumber ng-binding ng-hide" ng-show="col.groupIndex > 0">0</span>          
            </li><!-- end ngRepeat: col in columns | ngColumns -->
        </ul>
    </div>
</div>
</div>
</div>
Was it helpful?

Solution

Firstly, as per my comment, I'm not sure whether it's a good idea to have the widths of the grids themselves vary periodically, and automatically, from a user point of view. Secondly, if this can be solved with just CSS, as long as the CSS is maintainable and clear, I would avoid using Javascript for styling.

So...

You don't seem too definite on what you mean by "pretty", but one way to achieve, if not pretty-ness, but neatness, is to ensure spacing between elements is constant (specified in px), but the element widths can be a bit responsive (to browser width, essentially)

There are CSS grid systems that can do this (e.g. Twitter Bootstrap), but if you're targeting modern browsers, then using CSS flexboxes can give a way of doing this with a minimum of code and not additional dependencies.

If you have your HTML structure as simple as it can be:

<div class="window">
  <div class="master">
    <p>Master</p>
  </div>
  <div class="detail">
    <p>Detail</p>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin tellus nisl, tristique a nisi sed, facilisis suscipit ligula. Ut lectus arcu, mollis sit amet faucibus in, hendrerit ac nisl.</p>
  </div>
</div>

Then the CSS to achieve a simple 2 column layout (which is essentially what you're asking for the description above is quite short, using display: flex and the usual width property.

/* Layout */
.window {
  display: -webkit-flex;     /* Safari */
  display: flex;
}
.master {
  width: 25%;
}
.detail {
  width: 75%;
}

/* Spacing */
.window, .master, .detail {
  padding: 20px;
}
.detail {
  margin-left: 20px;
}

You can see a demo of this. One nice benefit is that the default behaviour of the flexbox model is that each of the children (in this case .master and .detail) is that they end up equal height, the height of the tallest one of the 2.

2 column flexbox layout

For integrating with ngGrid, there isn't really much to do. The only thing would be to give the master/detail containers themselves display: flex, so they are also a parent flex container to the ngGrid instances. The gives the ngGrid instances the default behaviour of having their height equal to the height of their flex parent.

You can see a demo of the flexbox integrated with ngGrid

2 column flexbox layout integrated with ngGrid.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top