Category Archives: HTML/CSS

Infragistics WebDataMenu: Enable client-side resize with scrolling

Infragistics WebDataMenu control for ASP.NET has a neat feature: if items for horizontal menu don’t fit in allocated width – it automatically adds scroll buttons:

Scrolling in WebDataMenu

Unfortunately this works only if you set menu width in ASPX markup or server-side code. But what if menu is built dynamically and you don’t know in advance how many items there will be. Or if user resizes browser window and available width changes?

We need to be able to set menu width in client-side JavaScript code. Also we need to check whether all items fit into menu width and if not – enable scroll buttons – on demand. The code below does just that. Continue reading →

Solution for: Value of type ‘System.Web.UI.HtmlControls.HtmlGenericControl’ cannot be converted to ‘System.Web.UI.HtmlControls.HtmlTableRow’ error

If you’re trying to compile an ASP.NET project/website in Visual studio 2012 or 2010 and getting error:

Value of type ‘System.Web.UI.HtmlControls.HtmlGenericControl’ cannot be converted to ‘System.Web.UI.HtmlControls.HtmlTableRow’

chances are you have an HTML table in your ASPX markup with runat="server" attribute set and <tbody> or <thead> tags present. Remove <tbody> and <thead> tags and the error should go away.

WebDataTree: Use custom images for Expand/Collapse

Infragistics WebDataTree control offers variety of styles via supplied StyleSets and each StyleSet has its own Expand/Collapse images for tree branches. Unfortunately the control doesn’t offer built-in way to use your own expand/collapse images, to achieve that you need to replace respective images in the StyleSet currently used by the tree.

But if you’re reluctant to go this way for whatever reason (you’re using your own style or don’t want to change canonical Infragistics style) there’s another way – purely client-side JavaScript.

Note: The method below assumes that all the levels the tree are fully rendered on the client. If you’re employing load-on-demand, the method will require some adjustments.

Place the code below in Tree client-side Init event:

function xwdTree_Init(sender, eventArgs) {
   /// <summary>
   /// Fires when tree is initialized
   /// </summary>

   //{******* Replacing Expand/Collapse images in the tree with custom ones

   // Looping thru images in the tree itself
   var aTreeImages = sender.get_element().getElementsByTagName('img');
   
   for (I = 0; I < aTreeImages.length; I++) {
      if (aTreeImages[I].src.indexOf('Plus') != -1) aTreeImages[I].src = 'images/my_expand.png'
      else if (aTreeImages[I].src.indexOf('Minus') != -1) aTreeImages[I].src = 'images/my_collapse.png'
   }

   // Looping thru images in hidden div used for replacement after click
   var aTreeActionImages = $get(sender.get_id() + '_Images').getElementsByTagName('img');
   
   for (I = 0; I < aTreeActionImages.length; I++) {
      if (aTreeActionImages[I].src.indexOf('Plus') != -1) aTreeActionImages[I].src = 'images/my_expand.png'
      else if (aTreeActionImages[I].src.indexOf('Minus') != -1) aTreeActionImages[I].src = 'images/my_collapse.png'
   }

   //******* Replacing Expand/Collapse images in the tree with custom ones }
        
}

Take a look at Lines 8-14. This code locates Tree control and its respective DOM element. Then it loops thru all the images inside. If it’s an “expand” image (has the word “plus” in its name) – we replace it with our custom expand image. If a tree node already rendered expanded – the code will locate “collapse” image (which has the word “minus” in its name).

This is all good and well for currently rendered nodes. But when you start expand and collapse nodes – images are replaced dynamically (“expand” becomes “collapse” when node is expanded and vice-versa) by Infragistics code. If you only execute code in Lines 8-14 and then expand or collapse tree nodes – your images will get replaced with Infragistics original ones from their secret repository.

Fortunately that secret repository is a plain hidden DIV with the ID “yourTreeID_Images”. Take a look at Lines 16-22. This code locates the DIV that holds replacement images and replaces them with our own similarly to Lines 8-14. After it ran, when Infragistics code needs to grab an image to replace expand/collapse one – it will get yours.

As a result Tree is rendered (both statically and dynamically) with your own beautiful images.

WHDG: Position “Group by” area anywhere on the page

WebHierarchicalDataGrid grouping feature offers handy “Group By” area – a place where columns can be dragged to for grouping. It has one limitation though: by default it can be positioned only on top or the bottom of the grid. But what if you want to place it elsewhere? For example you have a dedicated navigation part of your page where you want to display grouped columns.

DOM to the rescue. As I mentioned in my previous post Group By area is a DIV that can be located by its CSS class name (either assigned by you or, barring that, class of a StyleSet used by the grid control). After the area is located, it can be moved to a location of your choice, for example another DIV by standard appendChild DOM method:

function positionGroupByArea() {
   var aGroupAreas = document.getElementsByClassName('ighg_Office2007BlueGroupArea'); 
   var oDivActionControls = $get('xdivNavigation'); 

   if (aGroupAreas.length > 1) {
      oDivActionControls.removeChild(aGroupAreas[0]);
      oDivActionControls.appendChild(aGroupAreas[1])
   } else {
      oDivActionControls.appendChild(aGroupAreas[0])
   }
}

Lines 2-3 Locate Group By area and target DIV respectfully. Note Line 5: like nature abhors a vacuum – WHDG abhors Group By area missing from its default place, if it is missing – grid will try to recreate it. If this happens you will have 2 Group By areas. If code on Line 5 detects this situation it removes old area and re-adds new one. Otherwise it simple moves original area.

You will have to call this code on initial grid load and after every grid operation (sorting, paging etc.) since grid will try to recreate Group By at the old place. Also, if the grid feels jumpy during this move – hide Group By area initially via it’s CSS class by setting display:none and make it visible again after the move.

Overall effect is quite seamless

WHDG: Give Grouped columns correct captions

If you work with Infragistics WebHierarchicalDataGrid and try to use its grouping features, you may notice that it uses grid column keys instead of column header’s captions to name items in “Group By” area.

To work around this limitation, let’s take a look at how Grouped By area is rendered:

Group By Area in WebHierarchicalDataGrid

Basically a container DIV holds a bunch of SPANs representing grouped columns. Both DIV and SPAN can be located by their CSS class (your own, if it’s assigned or Infragistics StyleSet class name, used by the grid control). Knowing the location of the SPANs we can loop thru them altering their text:

function renameColumnsInGroupByArea() {

   //locating GroupBy area DIV 
   var oGroupArea = document.getElementsByClassName('ighg_IGGroupArea')[0]; 

   //locating GroupedColumn SPANs
   var aGroupedColumns = oGroupArea.getElementsByClassName('ighg_IGGroupedColumn');

   // looping thru SPANS with grouped columns, replacing their text
   for (var I = 0; I < aGroupedColumns.length; I++) {
      aGroupedColumns[I].firstChild.nodeValue = // put your new value here;
   }
}

One way of using this function is generate a JavaScript associative array (ColumnData['ColumnKey'] = 'Column Caption') in ASP.NET server side code. Armed with such array Line 11 in the previous code could be simple

aGroupedColumns[I].firstChild.nodeValue = ColumnData[aGroupedColumns[I].firstChild.nodeValue]

Active CSS selector not working correctly for Input Button in IE

CSS has a cool selector called “:active“, it can be used for example to select a button when it is pressed. Let’s say you have an HTML markup like this:

<input type="button" class="mybutton" value="Click me" />

and you define CSS selector like this:

.mybutton:active {background-color:red}

the button will change its background color to red when clicked and only for the duration of the click (while the mouse button is down) as soon as mouse button is released – background color is reverted to original.

This works fine in all modern browsers and supposed to work in Internet Explorer since version 8. And it works – well kind of – only you click the button but not the button label (text of the button). If you click actual text – style does not change.

Weird, but with IE weird is often normal. To alleviate the problem use button HTML element instead of input:

<button type="button" class="mybutton">Click me"</button>

With this markup CSS described above works universally.

Of course if you need to target browser below IE8, CSS selector approach does not work, you have to resort to JavaScript:

<input type="button" style="background-color:white" value="Click Me" onmousedown="this.style.background='green'" onmouseup="this.style.background='white'" />

Solution: WebDataGrid loses styles after postback

Infragistics WebDataGrid control offers very flexible styling option – you can set font, color, size of almost any element from column to individual cell. Here is an example of basic markup that sets CSS classes of overall grid control, grid header, grid odd row and grid even row:

<ig:WebDataGrid ID="xMyGrid" runat="server"
   CssClass = "GridStyle"
   HeaderCaptionCssClass = "GridHeaderCellStyle"
   ItemCssClass = "GridCellStyle"
   AltItemCssClass = "GridAltCellStyle" 
>

And corresponding example of CSS class for even row:

tbody > tr.GridAltCellStyle > td
{
   font-size:11px;
   font-weight:normal;
   font-family:Verdana, Geneva, sans-serif;
   height:20px;
   padding: 2px 2px 2px 2px;
   border-bottom: none;
   border-right: 1px solid rgb(190,198,178);
   background-color:rgb(240,240,240);
}

(For a complete grid styling reference take a look at this styling guide)

And it all works fine, your grid renders so beautifully, Picasso would cry. But only on initial page load. And here comes dreadful postback. Continue reading →

Position:Absolute within Position:Absolute

Let’s say we have a basic HTML layout: a container DIV and within it another DIV and an image:

<div id="xdivContainer">
   <div id="xdivMenu" style="position:absolute"></div>
   <img id="ximgIcon" src="icon.gif" />
</div>

Inner (child) div is positioned absolutely and we want to place it at the coordinates of the image (think popup menu appearing on icon click). A very basic JavaScript function obtains position of the image:

// Class placeholder for coordinates
function CTopLeft(i_nTop, i_nLeft) {
   this.nTop = i_nTop;
   this.nLeft = i_nLeft;
}

// obtain position of a DOM element
function GetTopLeft(i_oElem) {
   var cTL = new CTopLeft(0, 0);
   var oElem = i_oElem;

   while (oElem) {
      cTL.nLeft += oElem.offsetLeft;
      cTL.nTop += oElem.offsetTop;
      oElem = oElem.offsetParent;
   }
   
   return cTL;
}

As you can see it simple collects offset positions of the HTML element, combining them into absolute coordinates. So to absolutely position our child DIV at the coordinates of the image we can call it like this (I am using $() notation as a shortcut for document.getElementById)

var oPos = GetTopLeft($('ximgIcon'));
$('xdivMenu').style.top = oPos.nTop + 'px';
$('xdivMenu').style.left = oPos.nLeft + 'px'

And it works fine. Until container DIV is in turn absolutely positioned: Continue reading →

UltraWebGrid strange behavior in IE8 when IE=EmulateIE7

If you’re using Infragistics UltraWebGrid in Internet Explorer 8 you may experience strange visual (and other) issues if you have page compatibility set to emulate IE7, e.g.

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />

Issues can range from column moving not working to weird distortion in grouped mode. According to Infragistics this combination is not supported as “unstable”, but you can still make it work.

Infragistics keeps internal flags of what browser is currently in use: ig_shared.IsIE7, ig_shared.IsIE8, etc. The trick is to detect IE8 and make it fall back to IE7:

if (ig_shared.IsIE8) {
    ig_shared.IsIE8 = false;
    ig_shared.IsIE7Compat = true;
}

Place this code on top of your page JavaScript code and when it sees IE8 it will tell grid to use IE7 rendering. This is most definitely a hack, but it works.

HTML Table RowSpan: Autofit spanned cells to content

Let’s say you have created an HTML table with following markup:

<table id="xMyTable" style="width:100%;">
   <tr >
      <td style="vertical-align:top">
         <div style="border: 2px solid black; background-color:red; height: 100px;">
         </div>
      </td>
      <td style="vertical-align:top" rowspan="3">
         <div style="border: 2px solid black; background-color:orange; height: 600px">
         </div>
      </td>
   </tr>
   <tr>
      <td style="vertical-align:top">
         <div style="border: 2px solid black; background-color:green; height: 100px">
         </div>
      </td>
   </tr>
   <tr>
      <td style="vertical-align:top">
         <div style="border: 2px solid black; background-color:blue; height: 100px">
         </div>
      </td>
   </tr>
</table>

It’s very basic, one rowspanned cell that holds a content with large height on the right and 3 corresponding cells with content of smaller height on the left. You’d expect it to look like this:

Desired layout of rowspanned HTML table

Unfortunately as is it works only in Google Chrome. In the rest of the browsers, including Interned Explorer and famed FireFox it looks like this:

Current layout of rowspanned HTML table

What happens is browsers automatically spread spanned cells height to evenly fit height of the cell with rowspan. To rectify this situation we need a little help from JavaScript. Continue reading →