CSS/Html

jLinq – LINQ for JSON

jLinq

Sometimes I stumble accross something and immediately think “where has this been all my life?”. Finding jLinq is one of those moments.
I love Language Integrated Query (LINQ) and have used it for the last couple of years. With LINQ2NHibernate, LINQ2Lucene, LINQ2Amazon and even LINQ2Twitter emerging, it is very clear that LINQ is here to stay.

Enter jLinq from Hugoware

$.getJSON("/Person/All", function(data) {
  var results = jLinq.from(data.users)
      .startsWith("first", "a")
      .orEndsWith("y")
      .orderBy("admin", "age")
      .select();
});

You can view the basics of jLinq from this screencast.
We used jLinq to solve a very complex join operation on our JSON object and found it to be a very simple task…

  var results = jLinq.from(data.users)
    .join(data.locations, "location", "locationId", "id")
    .equals("location.state", "texas")
    .orderBy("location.city")
    .select(function(r) {
    return {
       fullname:r.first + " " + r.last,
       city:r.location.city,
       state:r.location.state
    };
});

jLinq is also very extensible and creating your own extension methods couldnt be easier…

  jLinq.extend({
    name:"startsWithLetterP",
    type:"query",
    count:0,
    method:function(q) {
        return q.helper.match(q.value, /^p/);
    }}); 

//use the new method
var results = jLinq.from(data.users)
    .startsWithLetterP("first")
    .select();

So why wait another minute, head off to experiment here right now!

Yes/No Dropdownlist Extension for ASP.NET MVC

I am not a big fan of using checkboxes for a simple yes/no question on a form. I use checkboxes only for selecting multiple items to perform an action on, or when I am using a checkboxlist. The reason for this is because I believe a yes/no question has three possible states, not only two.

If you are asking a user “Do you agree with our terms?”, the general consensus is to assume that not clicking the box is “forgetting” to make a selection and warning me that “You have forgotten to tick our terms and conditions”. In this situation the case may be so, but what if I did not agree? What if the question was “Do you want to opt out of us sending you loads and loads of spam?” and simply not spotting this question.

I believe that if you did not make a selection it is a valid state. Thus a yes/no question, in my opinion, has the following states; “yes”, “no” and “did not choose”.
Once again, I don’t simply rant, I also offer a solution… a very simple extension method which I love using for all my yes/no questions instead of checkboxes. In this case I made the “not selected” state 0.

public static string YesNoDropDownList(this HtmlHelper helper, string id, string selectedValue)
        {

            var list = new SelectList(new[]
                              {
                                  new {text = "Select", value = "0"},
                                  new {text = "No", value = "1"},
                                  new {text = "Yes", value = "2"}
                              }, "value", "text", selectedValue);

            return helper.DropDownList(id, list);
        }

PS: It also looks a bit neater and more uniform.

Get the contents of an IFrame via JQuery (Wymeditor)

I recently found myself in a scenario where I needed to copy the contents of an iframe to another. Madness you say? Hold on… there is a method to my madness. I am using Wymeditor to help manage my html fields/properties on a form. The client requested that the user should be able to import recently entered contents in a similar field on the same form. When these contents are “imported” only a certain amount of characters should be used. Almost like a short version (synopsis) of another field.

What does this have to do with Iframes I hear you ask? Well, Wymeditor uses an Iframe to box its functionality and mask it as a textarea.
After much searching I came up with the following:

$("#importFromFull").click(function(e) {
        e.preventDefault();
        var text = $("#postBodyTab .wym_iframe iframe")
            .contents()
            .find('body')
            .html();

        $("#longSynopsisTab .wym_iframe iframe")
            .contents()
            .find('body')
            .html(text.substr(0, 255));
    });

Thus, the function for retrieving the contents of any iframe is:

$("#myIframe")
            .contents()
            .find('body')
            .html();

(Please note, this will only work if both iframes are on the same domain. There are security issues for manipulating an iframe’s content)

Splitting your dynamic unordered list into columns

The easiest way to split your unordered list into columns is by assigning css classes.

<ul>
<li class="left">Item 1</li>
<li class="left">Item 2</li>
<li class="right_first">Item 3</li>
<li class="right">Item 4</li>
</ul>
.left {
margin-left: 0px;
}

.right {
margin-left: 50%;
}

.right_first {
margin-top: -40px;
}

If you know the size of the list then you can play around with the top margin of the “right_first” class. In our case, we do not know the size of the list, so we would have to do some black magic…

// First we calculate some variables
// the minimum column length (items / 2) at which to split into columns
var columnSplitLength = 7;
// the current would be column length
var currentColumnLength = Math.round(items.length / 2);
// is the items an odd or even length
var isOdd = (items.length > 2) != currentColumnLength;
// should we split the columns?
var shouldSplitColumns = currentColumnLength > columnSplitLength; 

var count = 1; var myLiHeight = 13; // height of each ListItem

$.each(items, function() {
    var className = shouldSplitColumns &&  (count > currentColumnLength) ? "right":"left";
    if(count == currentColumnLength+1)
        className = "right_first";
    var resultRow = $.stringFormat("<li class='{0}'>{1}</li>", [className, this.name]);
    $(resultRow).appendTo("#myUlList");
    count++;
});

// If the list length is odd, we have to add a phantom item to the right to balance
if(isOdd) {
 $("<li class='right'></li>").appendTo("#myUlList");
count++;
}
// Lastly, reset the first item of the right column to the top
$(".right_first").css("margin-left", "50%");
$(".right_first").css("margin-top", "-"+count*myLiHeight+"px");