Telerik MVC sorcery!

Ok, maybe that is totally link-bait, but I did do some semi-cool stuff with Terlerik MVC in the NopCommerce admin.

I reworked the entire order edit page, including adding knockout.js to wire up all the total and tax calculations – something I think should have been automatic within the admin, but I digress…

I setup an event consumer to tap in to add/edit/deletes or OrderProductVariant entities. I did not want the extra traffic of updating the OrderNote grid every time something happened with an order item, so I decided that I’d refresh the grid whenever the user selected the order notes tab. But how to do this? I found these two helpful links in the Telerik forums:

With these two posts I was given all the info I needed. I could tap into the tab select client event, then perform an ajax request for the order note grid.

Twitter Bootstrap and Font Awesome

http://www.flickr.com/photos/blentley/5387467938/in/photostream/

http://www.flickr.com/photos/blentley/5387467938/in/photostream/

I started my little “todo” list in backbone (it is a rule that you have to create a todo list for your initial foray into backbone, apparently) and I decided to use Twitter Bootstrap. I like that it has a nice, clean look, but I also don’t like that I see it used in every example. Pretty soon every site on the net will look the same, and I don’t necessarily think that is a good thing…

I wanted to add a “delete” icon, and it was really simple. however, I think that a delete icon should be red. Unfortunately bootstrap doesn’t work this way. I did a quick google and found a post on StackOverflow about using bootstrap and colored icons. The marked answer mentions Font Awesome.

Font Awesome is… well, awesome! It uses @font-face so you can use CSS to style the icons. Ima ’bout to get on that right now…

Massive

I finally had a good situation to use Massive, so I took it.

I was working on some functionality of a web service, and I needed to refactor some data access code. We were using SubSonic, and that is great and simple (typically), but this data access code is in a library, so changing meant opening up the project, making changes, building, pulling the new DLL over, etc. Not a huge amount of work, but too much work for a web service that is basically working with a single table.

There was minor learning curve, but Massive is pretty darned simple. It was mostly my mistakes in not paying attention, or old ASP classic-style blunders like using the wrong name for the column. Overall, it was a lot of fun.

My favorite bit was when I needed to get a SUM and a GROUP BY. If I were using EF or SubSonic, I may have struggled a bit with the proper LINQ syntax to do this (I need to increase my LINQ-FU skills, they are not strong), but with Massive I simply… wrote SQL… GASP!

I made a custom object with the 2 properties I needed, and then I looped over the returned values, pushed ’em into a list and returned it as an array. Here is the code:

[WebMethod, SoapHeader("Authorization")]
public DownloadDetail[] GetOrderDownloadCounts(object orderId, 
                                               object profileId) {
    var list = new List<DownloadDetail>();

    dynamic table = new DownloadAuthorization();
    object[] queryargs = { orderId, profileId };
    var auths = table.Query(@"SELECT Id, SUM(DownloadCount) AS Total
FROM Downloads
WHERE TagString=@0 AND ProfileID=@1
GROUP BY Id", queryargs);
    foreach (dynamic auth in auths) {
        list.Add(new DownloadDetail { Id= auth.Id, 
                                      DownloadCount = auth.Total });
    }

    return list.ToArray();
}

I am thinking I could have done some sort of LINQ-y extension to eliminate the foreach loop, but maybe not? I don’t really know much (read: anything) about dynamic, so maybe it would not work? Not really sure. I guess I am showing my Intellisense crutch dependency here.
🙁

Backbone.js

We have decided to use backbone.js for a project at work, so I have been soaking up everything I can find about it. Tekpub has a great series (currently in development) that I am really digging, and it has got me pretty excited.

I recently checked out the Peepcode preview and it looks pretty promising. A co-worker also pointed me to a great book hosted on Github. I’d also like to check out the NetTuts backbone/.NET videos. Can you tell I like video learning?
🙂

I started thinking that WebAPI would probably work really well with backbone rather than a full-blwon MVC site. I started searching and I have been finding some great links, so I thought I’d compile a list of them here:

I am (obviously) a little late to jump on the backbone bandwagon, so there is a ton of great content out there. I would really like to find a project that can allow C# code to be converted into backbone models, but that may be a bit difficult. It would be great to use the strongly-typed models and then add some spice for backbone and have some Nuget-able library that can convert the C# model/spice to backbone for you to save some of the javascript work. Don’t get me wrong – I am not afraid of javascript. Quite the contrary – I have grown to really love javascript. What I don’t like is doing things twice. Writing the backbone views and then writing a lot of the same type of code on the server-side (for the data persistence) just doesn’t sound appealing.

One thing that could maybe make it all a little easier is to use Massive. I recently swapped out some data access code that was using SubSonic to use Massive (eliminating some other DLLs along the way too) and it is pretty cool. Of course, it uses the dreaded dynamic keyword, so no fancy-pants Intellisense, but that is okay. Methinks that a properly coded backbone app using WebAPI would result in very little server-side code anyway, so some dynamic objects pushing and pulling to and from a db would be no big deal.

SVG CSS Injection

Through some random occurence I stumbled upon PJ Onori’s blog. I noticed a post titled “SVG CSS Injection” – that seemed pretty interesting, so I clicked. I was pleasantly surprised.
🙂

I have always thought vector graphics were really cool. I like the concept of SVG, but I haven’t gotten much into it. I still don’t know what tool to use to make the SVG graphics, but once made, PJ’s technique seems like a pretty cool concept. Basically, he “injects” the SVG graphics in the page where he can then manipulate them with javascript. He can change the color on-the-fly, etc. There is a nice demo page to show off his work.

The code is available on Github, so you can fork it if you think it is awesome. I hope to have a chance to play with it. I may not get to use it at work, but maybe I can sprinkle some SVG goodness on this blog. We’ll see…

Restrict form access and set a hidden input

There was a question I just ran across on Stack Overflow asking how to set a hidden input with js, and also to restrict access to one form from another. Setting the hidden input value is pretty simple, and I figured this would be a breeze. Overall it was, but I scrapped the guys code and rewrote it from scratch. It was easier for me to do that than to figure out his code. I wanted to share what I did here:

It isn’t the most robust thing, but it works. Once you select one answer on form A or B, you have to select only from that form. Annoying alerts are used, but it is just a prototype – the real deal would need to be much slicker.

I added simple validation; if there aren’t 3 checked radio buttons the form is not complete. Also, the validation triggers the submit button enable, so it’s a two-fer
🙂

Here is the code (in case jsFiddle ever blows up):

<h2>Table A</h2>
<table id="tableA" border="1">
    <tr>
        <td>
            A1
        </td>
        <td>
            <input type="radio" name="a1" value="1" /> Yes
            <input type="radio" name="a1" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            A2
        </td>
        <td>
            <input type="radio" name="a2" value="1" /> Yes
            <input type="radio" name="a2" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            A3
        </td>
        <td>
            <input type="radio" name="a3" value="1" /> Yes
            <input type="radio" name="a3" value="0" /> No
        </td>
    </tr>
</table>

<h2>Table B</h2>
<table id="tableB" border="1">
    <tr>
        <td>
            B1
        </td>
        <td>
            <input type="radio" name="b1" value="1" /> Yes
            <input type="radio" name="b1" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            B2
        </td>
        <td>
            <input type="radio" name="b2" value="1" /> Yes
            <input type="radio" name="b2" value="0" /> No
        </td>
    </tr>
    <tr>
        <td>
            B3
        </td>
        <td>
            <input type="radio" name="b3" value="1" /> Yes
            <input type="radio" name="b3" value="0" /> No
        </td>
    </tr>
</table>

<p>
    <button id="submit">Submit</button>
    <button id="reset">Reset</button>
</p>

<input type="hidden" id="activeTable" />
​
window.ns = {};
ns.activeTable = null;
ns.validate = function() {
    // Simple validation
    // If we don't have 3 checked radio buttons, it is invalid
    var checked = $("#" + ns.activeTable).find("input[type=radio]:checked");
    var valid = (checked || []).length === 3;
    $("#submit").prop("disabled", !valid);
    return valid;
};

ns.validate();

$("#submit").click(function() {
    var valid = ns.validate;
    if (valid == false) {
        alert("You must complete the form!");
        return;
    }
    
    var results = $("#" + ns.activeTable).find("input[type=radio]:checked");
    var output = ns.activeTable + " Results\n";
    $.each(results, function(idx, data) {
        output += "\t" + $(this).prop("name") + 
            " - " + $(this).val() + "\n";
    });
    alert(output);
    $("#activeTable").val(ns.activeTable);
});

$("#reset").click(function() {
    $("input[type=radio]").prop("checked", false);
    ns.activeTable = null;
    ns.validate();
});

$("input[type=radio]").click(function() {
    var selectedTable = $(this).closest("table");
    if (ns.activeTable != null && 
        selectedTable.prop("id") != ns.activeTable) {
        alert("Invalid form selection. Onlye selections from " + 
              ns.activeTable + " are allowed");
        $(this).prop("checked", false);
    } else {
        ns.activeTable = selectedTable.prop("id");
    }
    ns.validate();
});​
html { margin: 10px; }
table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
table td { border: 3px solid #CCC; padding: 5px; }
table td:nth-child(1) { width: 75%; }
table td:nth-child(2) { text-align: center; }
h2 { font-size: 1.8em; font-weight; bold }
button { padding: 5px; border-radius: 15px; background-color: #CCC; 
         width: 100px; }​

FluentValidation AddToModelState

HOORAY FOR THIS!

I was working on some admin functionality, and I added a validator to a model. The problem is the forms are contained within Telerik MVC Extensions tabs, so the validators for one tab are applied even if you are on a different tab. No dice! I really wanted to offer some nice error messages though, so I refused to quit! 🙂

I thought, “why can’t I just new up my validator manually”. I did this, and at first I wasn’t seeing what I needed. I eventually found that I had to get the result of validator.Validate(model) and then check result.IsValid. I was originally assuming I’d just be checking validator.IsValid. Anyway, here is what I had to that point:

var validator = 
    new Nop.Admin.Validators.Catalog
        .AddProductRelationshipAttributeValidator(_localizationService);
var result = validator.Validate(model);
if (result.IsValid == false) {
    // Do some error stuff here
}

The only thing now was how to get the result errors into the model state? I found a great thread on the FluentValidation discussion board that was asking the same thing – do I have to iterate the errors and manually add them to the ModelState? It turns out the answer is “yes”, but there is the handy extension method mentioned in the subject! TADA! So now, I have this nice bit of code:

var validator = 
    new Nop.Admin.Validators.Catalog
        .AddProductRelationshipAttributeValidator(_localizationService);
var result = validator.Validate(model);
if (result.IsValid == false) {
    Response.StatusCode = 400;
    result.AddToModelState(ModelState, "");
    return ModelState.JsonValidation(JsonRequestBehavior.AllowGet);
}

The ModelState.JsonValidation bit is another extension method I have to put the ModelState into a standardized JSON result that I then pass through a couple of js functions. Those functions make sure the validation passes, and if the validation does not pass it puts the errors in the validation summary manually. It is all pretty handy stuff.

If anyone has any better ideas, I am all ears!

Recent gists

I have saved a couple of code snippets lately and just wanted to add them to the blog too. This one enables “focus out” unobtrusive validation. I use this in a couple of forms on the site. Part of this gist also has a little code where I was messing around with “remote” validation to get it to work with the focus out validation – of course, I wasn’t thinking, just geeking out. The remote stuff is already baked in to jquery validation and I already had code to handle the focus out portion, so it wasn’t really worth the time, but I didn’t spend much on it. Anyway, the code:

window.Em = window.Em || {};

Em = {
    setFocusOutValidation: function (form) {
        var s = $.data(form, "validator").settings;
        s.onfocusout = function (element) {
            if ($(element).val().length > 0) {
                $(element).valid();
            }
        };
        s.showErrors = function (map, list) {
            this.defaultShowErrors();
            if (list && list.length > 0) {
                for (prop in map) {
                    $("#" + prop).focus();
                }
            }
            Em.displayValidationSummaryErrors(list);
        };
        return s;
    },
    displayValidationSummaryErrors: function (list) {
        $("[data-valmsg-summary]")
            .removeClass("validation-summary-valid")
            .addClass("validation-summary-errors");
        $("[data-valmsg-summary] ul").html("");
        $.each(list, function (idx, data) {
            $("[data-valmsg-summary] ul").append($("<li></li>")
                .html(data.message));
        });
    }
}

The focus out validation will check if the field is valid (also remotely) and if not, the focus will stay on the invalid field. Sometimes it can get a little wonky, but for the most part it works well. Typically when it doesn’t seem to “work” it is because the validation is setup backwards, like comparing a “new password” to the “confirm password”, rather than the other way around.

Gist

The next gist is a Telerik MVC grid extension I started messing with to handle filtering. Turns out I was making it harder than necessary, and there was already an extension method in the NopCommerce codebase. Oh well, here it is anyway:

public static IList<T> ApplyFilter<T>(this IList<T> list, 
                                      FilterDescriptor filter) {
 
    // We wont allow filtering on anything but string type properties
    if (filter.MemberType != typeof(string)) 
        throw new ArgumentException(@"Filtering is only allowed 
            for properties with a type of 'string'.");
 
    var value = filter.Value.ToString();
    switch (filter.Operator) {
        case FilterOperator.IsEqualTo:
            list = list.Where(x => {
                var propertyValue = x.GetType()
                    .GetProperty(filter.Member)
                    .GetValue(x, null);
                return String.Equals((string)propertyValue, value, 
                    StringComparison.InvariantCultureIgnoreCase);
            }).ToList();
            break;
 
        case FilterOperator.IsNotEqualTo:
            list = list.Where(x => {
                var propertyValue = x.GetType()
                    .GetProperty(filter.Member).GetValue(x, null);
                return String.Equals((string)propertyValue, value, 
                    StringComparison.InvariantCultureIgnoreCase) == false;
            }).ToList();
            break;
 
        case FilterOperator.StartsWith:
            list = list.Where(x => {
                var propertyValue = x.GetType()
                    .GetProperty(filter.Member).GetValue(x, null);
                return ((string)propertyValue).StartsWith(value, 
                    StringComparison.InvariantCultureIgnoreCase);
            }).ToList();
            break;
 
        case FilterOperator.Contains:
            list = list.Where(x => {
                var propertyValue = x.GetType()
                    .GetProperty(filter.Member).GetValue(x, null);
                return ((string)propertyValue).IndexOf(value, 
                    StringComparison.InvariantCultureIgnoreCase) > -1;
            }).ToList();
            break;
 
        case FilterOperator.EndsWith:
            list = list.Where(x => {
                var propertyValue = x.GetType()
                    .GetProperty(filter.Member).GetValue(x, null);
                return ((string)propertyValue).EndsWith(value, 
                    StringComparison.InvariantCultureIgnoreCase);
            }).ToList();
            break;
    }
 
    return list;
}

Gist

The last one is just a little quickie example of how to select data attributes with jQuery:

var d = $("input[data-toggle-class]");
$.each(d, function (idx, data) {
    console.log(idx, data);
});

Gist

I was originally looking for a way to select a wildcard in the data attribute, but I couldn’t get it working. Anyway, this works fine – though I did not actually end up using it. 🙂

FluentValidation NotEqual client-side validation

I wanted client-side validation for NotEqual. I started out writing my own and got 90% of the way there, then I got a little stuck. A quick Google revealed an existing Gist – however, the original implementation was only for NotEqual property comparison and I need a value compariosn. So, I forked it and made it work for my needs.

(function ($) {
    $.validator.addMethod("notequal", function (value, element, param) {
        if (param.indexOf("#") == -1) return value != param;
        return value != $(param).val();
    }, $.validator.messages.notequal);

    $.validator.unobtrusive.adapters.add("notequal", ["field"], 
    function (options) {
        options.rules["notequal"] = options.params.field;
        if (options.message) options.messages["notequal"] = options.message;
    });
})(jQuery);
FluentValidationModelValidatorProvider.Configure(provider =>
{
    provider.Add(typeof(NotEqualValidator), 
        (metadata, context, description, validator) => 
        new NotEqualClientRule(metadata, context, description, validator));
});
@model Test.Models.PersonModel
@using (Html.BeginForm())
{
    @Html.TextBoxFor(x => x.First)
    @Html.ValidationMessageFor(x => x.First)
    @Html.TextBoxFor(x => x.Last)
    @Html.ValidationMessageFor(x => x.Last)
    <button type="submit">OK</button>
}
[Validator(typeof(PersonValidator))]
public class PersonModel
{
    public string First { get; set; }
    public string Last { get; set; }
}
public class PersonValidator : AbstractValidator<PersonModel>
{
    public PersonValidator()
    {
        RuleFor(x => x.First).NotEqual(x => x.Last);
    }
}

Gist

When I look back at it, the whole hash check bit in the js just feels icky, so I think I’d go back and fix it up – probably just check to see if the jQuery selector exists, and if so compare .val() otherwise just compare the value. Whatever, it works for now even if it isn’t perfect…