Azure table to json with jQuery

I have been working with Azure quite a bit lately. We are looking to move all our hosted servers “into the cloud” – wherever that may be… Anyway, I have been working on a simple asset management system and I just started to implement the Azure Search API. I wanted to seed the index with existing data about the assets but I couldn’t see any easy way to export a list of the files in the container. Google to the rescue!

My search found a great post by Dave Ward on extracting data from an HTML table using jQuery. It is a pretty simple little snippet but it works quite well:

var data = $('#__fx-grid3 tbody tr').map(function() {
  // $(this) is used more than once; cache it for performance.
  var $row = $(this);

  return {
    name: $row.find('td:nth-child(1)').text(),
    url: $row.find('td:nth-child(2) .fxs-copybutton-value').text(),
    creationTime: $row.find('td:nth-child(3)').text(),
    size: $row.find('td:nth-child(4)').text(),
  };
}).get();

Use the snippet in the container details page and it will pull the name, url, etc. from the table. Now you’ve got the table data stored nicely in a local variable named data – but how to easily get at it? A little more googling found another simple little trick:

copy(data);

This will copy the data variable value to the clipboard. Now it is a simple paste into whatever text editor you favor. The above may be Chrome-specific, but if you are a web dev then you are likely using Chrome anyway – or at least have it at your disposal…

jQuery Download Plugin

jQuery Download Plugin

I was in need of an “export” button to export some data to a CSV file, but the data changes based on some other choices. I added my js to export the file and then – DUH! You cannot use ajax to return a file. Silly me… 🙂

I figured I could wrap a form around the button and set a hidden input and blah blah blah. I googled and found the above, which basically does all that for me and gives me a convenient 1 liner to work much like an ajax call would but allow for a “save as” dialog. It is pretty neat-o!

jQuery finds

I just ran across a couple of cool things to solve some problems. I needed a small pub/sub solution, and I found a tiny one:

jQuery Tiny Pub/Sub

It is a pretty slick little implementation and, more importantly, helped me solve my problem.

I needed to lazy load images, and there are a few solutions out there, but I was looking for something small (do you see a theme?) and I found this:

Unveil.js

This takes a very nice lazy load plugin and strips it down to the most basic of functionality resulting in a great lazy load plugin that comes in under 1k.

Wijmo

I just found out about Wijmo. Wijmo is a javascript widget library that utilizes jQuery, jQuery UI and knockoutjs. Using jQuery UI allows the widgets to be themed easily with any of Wijmo’s premium themes, the canned jQuery UI themes, or rolling your own with theme roller.

Wijmo costs if you want to use it in a commercial application, but they do have an open source option that allows for use in GPLv3 projects.

Select2 and Chosen

I was looking at my options for including an image in a select list – why is this not easier?

Anyway, I found some good Stackoverflow Q & A’s, and one mentions Select2. This is a pretty slicklooking jQuery extension, and it is based on another really cool plugin, Chosen.

The Select2 site uses Bootstrap, and the more I see examples in Bootstrap the more I <3 Bootstrap! I have discussed moving our company site over to Bootstrap to take advantage of the goodness that it offers (especially responsive UI) and the Select2 would be a great addition.

So much to do and so little time… 🙂

More remote jQuery validation

In my previous post, I lament the troubles I had with remote validation. I got it working, but I am a stickler and a perfectionist, so I had to have more. I wanted unobtrusive validation and I wanted my error messages to show up properly. I also did not want to use the Remote annotation because I needed to use localization, which I have not been able to get working (it needs static strings).

I did some more banging my head on the keyboard, then I realized I could just emulate what was going on with the Remote annotation. So, I made a new FluentValidation rule and went about it. I realized soon I was missing someattributes, but when I tries to add attributes with dashes MVC balked. “WTF?” I thought. Thanks to the power of the googles, I am now no longer left wondering. I found this great post that gave me just what I needed. The gist is that when you define a rule, if you add additional validation parameters, they will be preceded by the original rule name. For example, I made a rule for data-remote, and I needed data-remote-url. If I added a ValidationParamter for “url”, it would append that to “data-remote-” and all would work as planned. HOORAY!

Remote jQuery validation

I just spent too much time banging me head against the wall trying yo get remote validation working. Each of the examples I found just did not seem to work, until I found this post from jquery4u.com. It used an interesting syntax that I had not seen anywhere. Until I found that post, all the examples used remote as an attribute under “rules”, but I could not seem to get it to work. The jquery4u syntax worked.

When I see multiple examples that I cannot get to work, I can never seem to let it go, so I started trying to get that syntax to work. I finally realized that, even though I had seen examples where data was passed, the way to get it to work was just to specify the URL and let jQuery validation do the rest. It creates a query param using the name you specify in the validator (so essentially your input name) as well as the value of the input. I finally got that working. This post from develoq.net helped set me straight.

My final struggle was to get unobtrusive validation working as well as an error message in my validation summary. I found how you can decorate an attribute on your model, but we use localization, and that just doesn;t work. We use FluentValidation, and that allows us to use our localization strings, so I wanted to see if FV could handle remote. It turns out it isn’t out of the box, but I found this post where a user created his own RemoteValidator.

It too me a while, but I knew it would and should all work!

MultiSelect with checkboxes

More work on my nopCommerce plugin. This time, I wanted to offer more than the standard multi-select listbox. I thought it would be nice if the list had checkboxes. There are an infinite number of smarter people out there than myself, so I Googled knowing someone had some javascript goodness. I found the jQuery UI MultiSelect Widget. This is an awesome little plugin that is themable using jQuery UI. I know that nopCommerce doesn’t use jQuery UI in the admin (it is a Telerik MVC “shop”), but I still appreciate the ability since I really love the jQuery UI stuff.

Conditional validation

Related to my recent post about cascading drop down lists, I needed to do some conditional validation based on a drop down list selection. I found a great post on Simon Ince’s blog about conditional validation in MVC 3. He even has a new project to wrap up some of the conditional functionality that he blogged about, but I decided to roll my own since I would learn more going that route.

Using the project attached to his post, I started dissecting what he was doing. After a while, I got the client validation working, but I realized I was so focused on the client/server validation piece that I did not get my conditions correct! After a few tweaks, I finally got everything working. Here is the custom attribute:

public class ConditionalMaximumWeightAttribute : ValidationAttribute, 
                                                 IClientValidatable {

    private const string ERRORMSG = "Weight must not exceed {0} lbs.";

    public string DependentProperty { get; set; }
    public string DependentValue { get; set; }
    public int MaximumWeight { get; set; }

    public ConditionalMaximumWeightAttribute(string dependentProperty, 
                                             string dependentValue, 
                                             int maximumWeight) {
        this.DependentProperty = dependentProperty;
        this.DependentValue = dependentValue;
        this.MaximumWeight = maximumWeight;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(
                         ModelMetadata metadata, ControllerContext context) {
        var rule = new ModelClientValidationRule() {
            ErrorMessage = String.Format(ERRORMSG, this.MaximumWeight),
            ValidationType = "maximumweight",
        };

        string depProp = BuildDependentPropertyId(metadata, context 
                                                            as ViewContext);

        rule.ValidationParameters.Add("dependentproperty", depProp);
        rule.ValidationParameters.Add("dependentvalue", this.DependentValue);
        rule.ValidationParameters.Add("weightvalue", this.MaximumWeight);

        yield return rule;
    }

    protected override ValidationResult IsValid(object value, 
                                        ValidationContext validationContext) {
        // get a reference to the property this validation depends upon
        var containerType = validationContext.ObjectInstance.GetType();
        var field = containerType.GetProperty(this.DependentProperty);

        if (field != null) {
            // get the value of the dependent property
            var dependentvalue = 
                field.GetValue(validationContext.ObjectInstance, null);

            var weight = 
                containerType.GetProperty(validationContext.DisplayName);
            int weightvalue = 
                (int)weight.GetValue(validationContext.ObjectInstance, null);

            // compare the value against the target value
            if (dependentvalue == this.DependentValue && 
                                  weightvalue > this.MaximumWeight) {
                // validation failed - return an error
                return new ValidationResult(String.Format(ERRORMSG, 
                                            this.MaximumWeight));
            }
        }

        return ValidationResult.Success;
    }

    private string BuildDependentPropertyId(ModelMetadata metadata, 
                                            ViewContext viewContext) {
        // build the ID of the property
        string depProp = viewContext.ViewData.TemplateInfo
                         .GetFullHtmlFieldId(this.DependentProperty);
        // unfortunately this will have the name of the current field appended 
        // to the beginning,
        // because the TemplateInfo's context has had this fieldname appended 
        // to it. Instead, we
        // want to get the context as though it was one level higher (i.e. 
        // outside the current property,
        // which is the containing object (our Person), and hence the same 
        // level as the dependent property.
        var thisField = metadata.PropertyName + "_";
        if (depProp.StartsWith(thisField))
            // strip it off again
            depProp = depProp.Substring(thisField.Length);
        return depProp;
    }
}

Gist

To put this in context, I need to restrict a maximum weight allowed for a carrier. At a certain point, we may as well go with another carrier because it is cheaper. However, I don’t want to restrict the maximum weight if the carrier that has been selected is the cheaper carrier.

The attribute is used like so, where PropertyName is the name of the related property to check, PropertyValue is the conditional value of the property, and MaximumWeight is an integer representing the maximum weight for the conditional:

public class ...

    [ConditionalMaximumWeight("PropertyName", "PropertyValue", MaximumWeight)]
    [Required(ErrorMessage = "Weight required")]
    public int? Weight { get; set; }

    ...
}

Here is the client-side implementation:

<script type="text/javascript">
    $.validator.addMethod("maximumweight",
        function (value, element, parameters) {
            var carrier = $("#" + parameters["dependentproperty"]).val();
            var carriervalue = parameters["dependentvalue"].toString();
            var weightvalue = Number(parameters["weightvalue"]);
            if (carrier == carriervalue && value > weightvalue) {
                return false;
            }
            return true;
        }
    );

    $.validator.unobtrusive.adapters.add(
    "maximumweight",
    ["weightvalue", "dependentproperty", "dependentvalue"],
    function (options) {
        options.rules["maximumweight"] = {
            weightvalue: options.params["weightvalue"],
            dependentproperty: options.params["dependentproperty"],
            dependentvalue: options.params["dependentvalue"]
        };
        options.messages["maximumweight"] = options.message;
    });
</script>

Gist

I should probably do a little null checking in on the client-side, but I may just find that out the hard way! 🙂

ASP.NET MVC Cascading drop down lists

Found this great post on how to create cascading drop downs in ASP.NET MVC.

I created a page for looking up shipping rates by carrier, weight and zip code. For my particular usage, I had 2 lists: Carrier and ShipMethod. I wanted the cascading list to be disabled when the initial list selection had yet to be made. I created functions to populate the target list as well as enable/disable the target list. I made the js into a reusable Razor helper which should allow me to use it anywhere I need this functionality.

Here is the helper code:

@helper DynamicDropDowns() {
<script type="text/javascript">
    function listChanged($list, $target, url) {
        var listId = $list.val();
        if (listId == "") { // User selected first option, 
                            // so clear and disable the list
            $target.empty();
            enableList($target, false);
            return;
        }
        $.getJSON(url, { id: listId }, function (data) {
            $target.empty(); // Clear the list
            $.each(data, function (idx, item) { // Add the data
                $target.append($("<option/>",
                {
                    value: item.Value,
                    text: item.Text
                }));
            });
            enableList($target, true); // Enable the list
        });
    }

    function enableList($list, enabled) {
        $list.attr("disabled", enabled ? null : "disabled");
    }
</script>
}

Gist

And here it is in action:

<script type="text/javascript">
    $(function () {
        var $carrier = $("#Carrier");
        var $ship = $("#ShipMethod");
        enableList($ship, false);
        $carrier.change(function () {
            listChanged($(this), $ship, "/Tools/GetShipMethodsByCarrier");
        });
    });
</script>