My Super Sneaky MVC Dynamic Resizing Trick

It’s been about a week since I posted last…I know, you thought you were rid of me…but HA!  Nope.  Today I’m going to type about MVC and Javascript stuff.  I really like the layout and flexibility of MVC…I really hate the non-standard world of browsers that MVC has to support…which is probably why I’ve moved more over into the WPF world now…but anyway…

I can whip up something that looks great in Edge, but then when one of my customers goes and uses it in IE, it looks like crap.  Then I solve that problem and a random person with Firefox or Chrome comes along and again it looks all out of whack…which explains my lack of hair from pulling it out in frustration!  😛

Now I know there’s things you can do with css that detect what browser it’s running under and to adjust things accordingly…but honestly I find having to do that annoying.  For big huge sites that are all about grabbing your attention, I can understand the need to customize and tweak the user experience per browser…but I basically make reporting apps…which shouldn’t need to be customized like crazy to make them look nice, clean, and professional.  Anyway…without going on to much more of a rant about my displeasure in browser differences, here’s something I use in my MVC web apps to help dynmically resize my controls.

I work mostly with Telerik controls but my technique should work on any sort of MVC UI Element…since I’m using the class attribute to do my magic…however my examples will be shown with Telerik controls and Javascript.

First I make a little Javascript addition to my _Layout.cshtml document (in case you’re not familiar with MVC…when creating a project in Visual Studio using the MVC template it will generally always create a “Shared” view with a _Layout.cshtml document.  This is a generic shared view that has a placeholder where your custom views are loaded into.  If you’re an expert MVC dev and don’t use a shared layout document…you’re already well beyond this blog posts intended audience, but thanks for checking it out…hehehe).  In general I only put Javascript functions that apply to every other view in my _Layout.cshtml file.  In this case it’s a resizing function that gets called by a couple of events.

Javascript in _Layout.cshtml:

function ResizeElements()
{
    var bodyDiv = document.getElementById('body');
    var contentWrapper = $('#body > .content-wrapper');
    var featuredHeight = $('#body > .featured').outerHeight(true);
    var kendoGrid = $('.KendoGrid');

    // set the height of the overall body container
    bodyDiv.style.height = (window.outerHeight - 180).toString() + 'px';

    // set the width of the content wrapper.  the wrapper inherits it's height from the body container
    contentWrapper.width(window.outerWidth - 200).toString() + 'px';

    // if there is a KendoGrid class element present, set it's height so the
    // bottom is about 10 pixels from the footer
    if (kendoGrid.length > 0)
    {
        kendoGrid.height(window.outerHeight - contentWrapper - featuredHeight - 20);
        kendoGrid.data('kendoGrid').resize(); // this helps re-render the grid
    }
}

Ok, now I’ll go over what’s going on.  First I create objects to work with the elements I care about instead of continuously getting them by ID (the reason I do that is because the lookup to get that object by ID is only done once if I create an object for it and then just use that object over and over…if you always just reference the object by ID…each one of those lookups “could” be a perf hit…so I just got myself into the habit of creating a reference object for these sort of things).

The “bodyDiv” object is for main <body> element of the document which every MVC document will have since they are all HTML docs.

Then I grab the element from the body which has a class of “content-wrapper” into the “contentWrapper” object which is more or less the section I use for navigation bar.

After that I grab the height of the element with a class of “featured” into the “featuredHeight” object.  I’m only grabbing the height because that’s really the only thing I care about in the featured section since the width is controlled by the body it’s contained within…and really I’m not getting it to set the featured section…I’m getting it so I can use the value of whatever it’s set to later.

Again, I want to be clear that the way I’m using the “content-wrapper” and “featured” classes is how a default out of box MVC templated project in Visual Studio is setup…that’s where I learned my MVC skills from so that’s the only reason I keep rolling with the way I do.  If there’s better ways to go, please comment and let me know…I certainly do not know everything and would love pointers on how to do things better.  🙂

Lastly I create an object for whatever the main display element is within my web app.  In my case I use Telerik KendoGrid’s a lot.  Whenever I do I add the following to the grid so it will play nicely within the view it’s in.

HtmlAttributes(new { @class = "KendoGrid" })

This adds the attribute “class=KendoGrid” onto the HTML element for the grid…and my ResizeElements method is trying to create an object out of elements with a class of “KendoGrid”…ahhhh there’s the magic.

So now that I have objects for the things I want to work with…now I start setting the the dimensions.  For the body I force it to be specific size based on the “window”.  In this context “window” refers to the window of whatever browser you’re using to display the web app.  So I set the body’s height to a size I control that is less than the browser windows’s height…now I know my body element will never be longer than what’s showing on the screen.

Next I set the width of the content wrapper which in turn also sets the width of the body.  I think the way I’m doing it could be a little dangerous in that I’m counting on this controlling the width of all my other elements…it works but I can see where property inheritance could cause some troubles…but since I’m the one creating all the custom views it’s not terribly dangerous.  I think if I worked in a big team I’d design something a little more robust…but for now, this works great for me.

Ok, so that’s height and width…however if I just put a grid in my custom view like this…it looks like crap which is where the block of code checking for kendoGrid.length comes into play.  Technically there’s probably a better way to do what I’m doing…but again since I control the custom views, I know there’s always only going to be 1 or less grids in my views so I really just care if “length” is greater than 0…although I should probably write some code to throw an error if there’s more than 1…maybe later.  🙂

So what I’m doing in that “if block” is setting the height of the grid to be less than the windows outer height – the content wrapper – the featured height – an extra 20 pixels just to make sure the grid has some margins and isn’t squishing anything.  Now as soon as the page loads, the grid is alread the correct size…and if there’s more records than fits within the grid, a horizontal scroll bar will display in the grid instead of the web app’s main page…which is a much nicer scrolling experience IMHO.

The last part of the equation is to add a couple more Javascript functions to _Layout.cshtml.  One will fire as soon as the document is finished loading…the other will fire every time the document is resized.  Both just execute the method we created perviously called “ResizeElements()”.

$(document).ready(function ()
{
    ResizeElements();
});

$(window).resize(function()
{
    ResizeElements();
});

So that’s pretty much all there’s to my super sneaky resizing trick.  This is what works for me in my workplace and makes my boss happy…but I’m sure by now you can see what I was doing and apply it to your own beautification techniques.  Hope it helped…Enjoy!  🙂

Advertisements
My Super Sneaky MVC Dynamic Resizing Trick

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s