Archive for January, 2011

JQuery Validate() method for JQueryUI AutoComplete drop down boxes, while using KnockoutJS

It seems to be a rare mix, but on my form I have fields which are bound at client side using KnockoutJS, in drop downs styled using jQueryUI, using the expirmental autoComplete variant, which I then want to validate using jquery Validate method, to ensure someone actually selects something from the drop down!

So my form field looks like this;

<select data-bind='options: lookUps.Titles, optionsCaption: "Select...", value: Title, uniqueName: true'></select>

I have the following javascript to add the combobox autocomplete functionality;

 $("select").combobox({
                selected: function (event, ui) {
                    $(ui.item.parentNode).change();
                }
            });

Again, you’ll notice there’s another hack here to make everything play together nicly (see my blog post here)

Finally, the validation fix;

$.validator.addMethod('selectValueSelected',
          function(value, element) {
              return this.optional(element) ||
                (value.indexOf("__ko.bindingHandlers.options.optionValueDomData__") == -1);
          }, "Please select an option");
        $.validator.addClassRules("mustPopulateDropdown", {
            selectValueSelected: true
        });

All you need do now is add the css class “mustPopulateDropdown” to your select tags and they will be validated.

1 Comment

KnockoutJS won’t bind to fields with numbers at the end?

Maybe this is just me? Almost finished my Sales Entry form I’ve been tinkering with- adding a “Create Customer” dialogue, and every field bound as it should (using Knockout) except for 3; Address1, Address2 and Address3. The moment I changed Address1 to AddressHouseNumber, it started working- so i changed the other, and sure enough they all started working. I tripple checked for typo’s so it wasn’t that- the input fields looked like this;

<input data-bind="value: Address1, uniqueName: true" class=""/>
<input data-bind="value: Address2, uniqueName: true" class=""/>
<input data-bind="value: Address3, uniqueName: true" class=""/>

Weird! has any one else come across something like this?

2 Comments

More Manic Spaceman (8weekgame) documentation done

I promised I would, and I’m finally getting round to documenting the rest of the classes I wrote for my javascript platformer I built for the 8weekgame competition, as well as putting up the sourcecode. There’s still a few more to do, which I shall bash out through the course of the rest of the week. Check them out at www.shawson.co.uk/codeblog/8-week-game-competition/

No Comments

KnockoutJS/ jQuery tmpl with jQuery Validate

Quick post; I found tonight that my jquery validate was letting my knockoutjs viewModel.save() method run, even if the form wasn’t valid. This turned out to be because you need to set “uniqueName: true” on any form fields you want validated. Eg

<input data-bind="value: ChargedShipping, uniqueName: true" class="required number"/>

1 Comment

Unit testing Javascript event handlers or any other asynchronous delegate calls using jsUnit

I had to nock up a test for a simple method I had added to a connection manager class. The class tracks wether the client browser has a current connection to the server, and the method I added was simple “check connection” which wrapped prototypejs Ajax.Request method; you basically call the method with a filename and a success and failure call back. I wanted to confirm that, given an accessible filename, the checker would call the passed delegate for success and set a few flags internal to the class.

We needed to make sure the Ajax.Request had totally completed and the result was ready to be tested before the jsUnit test was executed, which meant some how imposing a delay which coudl be cleared once one of the callbacks had fired.

The solution was simple; add a setUpPage function to the page which is a reserved function name which the jsUnit framework looks for. If this function exists it will hold off executing the tests until the setUpPageStatus variable is set to ‘complete’.

My final test for the success case looked something like this;

status = '';

function setUpPage() {
	myConnectionStatus = new ConnectionStatus();
	myConnectionStatus.checkConnection(
		"test.txt", 
		function() { // success callback
			status = 'success called'; 
			setUpPageStatus = 'complete'; 
		}, 
		function() { // failure callback
			status = 'failure called'; 
			setUpPageStatus = 'complete'; 
		}
	);
}

function test_CheckConnectionCnxOK() {
	assertEquals('The success handler should have been called', 'success called', status);
	assertTrue('Connection should be set to online', myConnectionStatus.isOnLine());
}

1 Comment

Using JQueryUI combobox() with KnockoutJS

This is something I had a great deal of trouble with, but in the end the solution was simple. Basically when using the combobox() autocomplete drop down in jQueryUI (in prototype at time of writing) along side KnockoutJS I found changing your selection in the drop down list didn’t update the viewModel in knockout as expected. This is because knockoutjs attached itself to the change() event of the drop down, and jqueryUI wasn’t raising this event when it changed the drop down. This is easily fixed by adding an event handler to thre jqueryUI combobox which forces the event to be called when the user selects a new option;

$("select").combobox({
            selected: function(event, ui) { 
                $(ui.item.parentNode).change();
            }
        });

Thanks go out to the “Rob on programming” blog, which helped me get my head around what was going on in the events in combobox.

2 Comments

MVC strongly typed view returns a null model on post back

I recently ran into a problem where a form I had built (using the view creation dialogue) would always return a null model on post back.  The code was pretty simple;

        //
        // GET: /StockAdjustment/CreateForPart/{PartId}
        //[RequireRequestValue("id")]
        [Authorize(Roles = "Administrator")]
        public ActionResult CreateForPart(Guid id)
        {
            StockAdjustment sa = new StockAdjustment() {
                Part = parts_repo.GetPart(id)
            };

            return View(sa);
        }

        //
        // POST: /StockAdjustment/CreateForPart/{PartId}
        [Authorize(Roles = "Administrator")]
        [HttpPost]
        public ActionResult CreateForPart(Guid id, StockAdjustment adjustment)
        {
            if (ModelState.IsValid)
            {
                adjustment.AddedBy = User.Identity.Name;
                adj_repo.Add(adjustment);
                adj_repo.Save();

                return RedirectToAction("Details", "Parts", new { Id = id });
            }
            else
            {
                adjustment.Part = parts_repo.GetPart(id);
                return View(adjustment);
            }
        }

The ModelState would always be invalid, despite the the fact that my data was all valid and fine. When I picked into the ModelState error using immediate mode I found the reported error;

ModelState.ToList()[0]
  {[id, System.Web.Mvc.ModelState]}
ModelState.ToList()[0].Value.Errors
  Count = 0
ModelState.ToList()[1].Value.Errors
Count = 1
    [0]: {System.Web.Mvc.ModelError}
ModelState.ToList()[1]
  {[adjustment, System.Web.Mvc.ModelState]}
ModelState.ToList()[1].Value.Errors[0]
{System.Web.Mvc.ModelError}
    ErrorMessage: ""
    Exception: {"The parameter conversion from type 'System.String' to type 
    'SimplyModel.Models.StockAdjustment' failed because no type converter can convert between these types."}

So model state contained the ID which had no errors, and adjustment which has this weird type conversion error. After a bit of hunting around my code I realised the problem- StockAdjustment has a field called adjustment which is an integer, however on my post back handler, i told MVC that my model instance should be called adjustment- so it looks like the MVC binder has got confused and figured the form field “adjustment” must represent the entire StockAdjustment model- i simply changed the method signature to accept the model with another name, and it all started to work;

        //
        // POST: /StockAdjustment/CreateForPart/{PartId}
        [Authorize(Roles = "Administrator")]
        [HttpPost]
        public ActionResult CreateForPart(Guid id, StockAdjustment a)
        {
            if (ModelState.IsValid)
            {
                a.AddedBy = User.Identity.Name;
                adj_repo.Add(a);
                adj_repo.Save();

                return RedirectToAction("Details", "Parts", new { Id = id });
            }
            else
            {
                a.Part = parts_repo.GetPart(id);
                return View(a);
            }
        }

11 Comments