Routing with crossroads.js + browser history(from backbone.js)

Standard

It’s a very exciting time for developers, especially web developers. There has been a blow out of great cutting-edge web application thanks to the many javascript frameworks and plugins springing up. This is very good because as an engineer, you get to pick and choose what framework/plugin you want to use and the ability to extend it to fit your needs. Per last past, I started work on a personal project. One of my projects required a client-side routing engine. I looked at Backbone.js for its routing api which was great but it come with all the other api I didn’t wont/need.I looked at ¬†Crossroads.js¬† and was just perfect because it did exactly what I was looking for -routing, and no more that that. Apart from client-side routing, I also need a navigation engine to allowing for routing to bookmarks and application states. Backbone.js comes with a supporting api called History. Since I wanted crossroads.js routing but Backbone.js¬†implementation¬†of ¬†application navigation mechanism, I got hacking and in 10 min, had an extended crossroad.js with history support by porting over the implementation from Backbone. You can find and grab the code from github. You will need jquery to use this extension. Another thing you need to know is during hash navigation, crossroads is called with the relative path of the page and not just the hash. Thus if you navigate to “#3:edit” using crossroads.navigator at “www.test.com/people”, you will be navigated to “www.test.com/people#3:edit” and the request passed to crossroads for routing will be “people#3:edit”.

 

Credit: Feature sketch by ekubochan at Odosketch

Advertisements

Conditional Validation in ASP.NET MVC – RangeIf

Standard

Simon Ince made a great post about conditional validation in mvc which he extended in his post conditional validation in asp.net mvc 3. Asp.net mvc validation is one of asp.net mvc’s great extensible points . The framework comes with a decent amount of validations attribute such as range, stringlength etc but sometimes we find ourselves wanting to perform a specify type of validation that the framework doesn’t support and conditional validation is a perfectly good example. This is one of those validation types that most people feel the asp.net mvc team should have included in the framework but hey, they cannot do it all,¬† so we look to ourselves and to good people like Simon to the rescue.

Simon goes into details on how to create a RequiredIf validation so I wont elaborate on that (just dive into the links above for info on RequiredIf validation). In using Simon Requiredif validation, I decided its would be great to build on it to be applicable to other rules like Rangeif, StringLenghtIf, etc, starting with RangeIf. The first thing I needed to do was define the signature of the validation attribute. To keep things consistent with Simon’s, I decided to go with the signature as follows for an age property on the person class-

[RangeIf(11, 25, "IsUKResident", false, ErrorMessage = "If you are not a UK  resident, your age has to be between 11 and 25")]

The next thing to do was to define the RangIf attribute class below , inheriting from RangAttribute
public class RangeIfAttribute : RangeAttribute , IClientValidatable
{
public string DependentProperty { get; set; }
public object TargetValue { get; set; }

public RangeIfAttribute(int minimum, int maximum, string dependentProperty

, object targetValue): base(minimum, maximum)
{
this.DependentProperty = dependentProperty;
this.TargetValue = targetValue;
}

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);

// compare the value against the target value
if ((dependentvalue == null && this.TargetValue == null) ||
(dependentvalue != null && dependentvalue.Equals(this.TargetValue)))
{
// match => means we should try validating this field
if (!base.IsValid(value))
// validation failed - return an error
return new ValidationResult(this.ErrorMessage, new[]

{ validationContext.MemberName });
}
}

return ValidationResult.Success;
}

public IEnumerable<ModelClientValidationRule> GetClientValidationRules

(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "propertydependencyrule",
};

string depProp = BuildDependentPropertyId(metadata, context as ViewContext);
string targetValue = (this.TargetValue ?? "").ToString();
if (this.TargetValue.GetType() == typeof(bool))
targetValue = targetValue.ToLower();

 

rule.ValidationParameters.Add("dependentproperty", depProp);
rule.ValidationParameters.Add("targetvalue", targetValue);
rule.ValidationParameters.Add("rule", "range");
rule.ValidationParameters.Add("ruleparam","["+Minimum+","+Maximum+"]");

yield return rule;
}

 

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;
}
}

The code above is self explanatory so I wont elaborate. Note that we pass on the client rule and its parameters through rule.ValidationParameters in the GetClientValidationRules method. The next thing to do was create my client script (unobtrusive adapter) below
$.validator.addMethod('propertydependencyrule',
function (value, element, parameters) {
var id = '#' + parameters['dependentproperty'];

// get the target value (as a string,
// as that's what actual value will be)
var targetvalue = parameters['targetvalue'];
targetvalue =
(targetvalue == null ? '' : targetvalue).toString();

// get the actual value of the target control
// note - this probably needs to cater for more
// control types, e.g. radios
var control = $(id);
var controltype = control.attr('type');
var actualvalue = "";

switch(controltype)
{
case 'checkbox' :
actualvalue = control.attr('checked').toString(); break;
case 'select' :
actualvalue = $('option:selected',control).text(); break;
default:
actualvalue = control.val(); break;
}

// if the condition is true, reuse the existing
// required field validator functionality
var rule = parameters['rule']
var ruleparam = parameters['ruleparam']
if (targetvalue === actualvalue)
return $.validator.methods[rule].call(
this, value, element, ruleparam);

return true;
}
);

$.validator.unobtrusive.adapters.add(
'propertydependencyrule',
['dependentproperty', 'targetvalue', 'rule', 'ruleparam'],
function (options) {

 

options.rules['propertydependencyrule'] = {
dependentproperty: options.params['dependentproperty'],
targetvalue: options.params['targetvalue'],
rule: options.params['rule'],
ruleparam: eval(options.params['ruleparam']),
};
options.messages['propertydependencyrule'] = options.message;
});

That’s it. We now have our RangeIf validation attribute. Notice I modified Simon’s client side code to a generic propertydependencyrule so you can use propertydependencyrule for other propertydependency validation attributes like StringLenghtIf by passing along the max jquery.validator¬† rule and its parameters. In my next post, I will extend this to RegularExpressionIf, StringLenghtIf, and more. Stay tuned.

The site doesn’t work, I have javaScript & cookies turned on in my browser.

Standard

Problem

it‚Äôs hard resolving issues at a customer‚Äôs end because you don‚Äôt know what the state of their machine is in. You can do your best by gathering information from the client as to the behavior of the problem and go hunting for the solution after politely saying, ‚ÄúI will look into it‚ÄĚ.

After all, the customer is always right.  JavaScript and Cookies are used by  lots of web applications and yet, it amazing how many browser currently in existence don‚Äôt have those features turned on. I understand the security risk of JavaScript but ‚Ķ So in such a situation, what do you do. Customers will always tell you they did exactly what you told them to do but it‚Äôs hard to know if they ‚Äúactually‚ÄĚ followed your steps to rectify the problem.

 

Solution

Relying on the Customer is great but proof is even better. Showing user browser configuration settings in your web application can be very helpful in addressing some of these issues. See example of such a configuration display below.

image 

image

image

This is all great but unfortunately, extracting this information for the browser can be tedious since they are no consistent amongst all browsers. Below is a JavaScript snippet which provides you with the above browser settings for IE, Firefox, Opera and Safari.

 

<script type="text/javascript"> 
  

function showBrowserConfigurationResult() {

    $get("browser_type_check").innerHTML = getBrowserType();
    
    $get("browser_version_check").innerHTML = checkBrowserVersion();

    $get("js_check").innerHTML      = "Yes";

    $get("cookie_check").innerHTML  = getCookieStatus();
    
    $get("platform_check").innerHTML = getPlatformStatus();
    
     $get("screenresolution_check").innerHTML = getScreenResolutionStatus();

}


function getBrowserType() {
   
     if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ //test for MSIE x.x;
       return "Internet Explorer";
     }
     else if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)){ //test for Firefox/x.x or Firefox x.x (ignoring remaining digits);
        return "Firefox";
      }
      else if (/Opera[\/\s](\d+\.\d+)/.test(navigator.userAgent)){ //test for Opera/x.x or Opera x.x (ignoring remaining decimal places);
        return "Opera";
      }
      else if(/Safari/.test(navigator.userAgent)){
      return "Safari";
      }
      else
      {
        return navigator.appCodeName;
      }
    
}

function checkBrowserVersion() {
   
    
    if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ //test for MSIE x.x;
     var ieversion=new Number(RegExp.$1) // capture x.x portion and store as a number
     
         if (ieversion>=8)
          return "8.x";
         else if (ieversion>=7)
         return "7.x";
         else if (ieversion>=6)
         return "6.x";
         else if (ieversion>=5)
          return "5.x";
         else
            return "n/a";
      
      }
     else if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)){ //test for Firefox/x.x or Firefox x.x (ignoring remaining digits);
       var ffversion=new Number(RegExp.$1) // capture x.x portion and store as a number
       
     if (ffversion>=3)
      return "3.x or above";
     else if (ffversion>=2)
      return "2.x";
     else if (ffversion>=1)
      return "1.x"
     else
       return "n/a";
      
    }
    else if (/Opera[\/\s](\d+\.\d+)/.test(navigator.userAgent)){ //test for Opera/x.x or Opera x.x (ignoring remaining decimal places);
     var oprversion=new Number(RegExp.$1) // capture x.x portion and store as a number
     if (oprversion>=10)
      return "10.x or above";
     else if (oprversion>=9)
     return  "9.x";
     else if (oprversion>=8)
      return "8.x";
     else if (oprversion>=7)
      return "7.x";
     else
      return "n/a";
    }
    else if(/Safari/.test(navigator.userAgent)){
      var safversion = /Version\/\d\.\d\.\d*/.exec(navigator.userAgent)
      safversion = /\d/.exec(safversion)
     if (safversion>=3)
      return "3.x or above";
     else if (safversion>=2)
     return  "2.x";
     else if (safversion>=1)
      return "1.x";
     else
      return "n/a";
     
     
    }
    else 
    {
      return  navigator.appVersion;
    }
}


function getCookieStatus() {

   if(navigator.cookieEnabled) 
      return "Yes"; 
   else 
     return "No" ;

}

function getPlatformStatus()
{
   return navigator.platform;
}

function getScreenResolutionStatus()
{
  return screen.width+" x "+screen.height;
}

 </script>

 

$get(‚Äú x‚ÄĚ) is a jquery function that returns the element with id=‚ÄĚx‚ÄĚ. If you are not using jquery, you can replace $get() with the JavaScript function  getElementbyId(‚Äúx‚ÄĚ)  and that should rectify the problem. Enjoy.

Browser Spring is full of great browsers, only one will be kingpin!

Standard

It’s amazing how the web has been ignited again in the name of the best JavaScript engine and browser layout engine. Everywhere I turn, there is talk of Ajax, JavaScript frameworks etc. The web has entered another phase; were application are heavily rendered on the client-side instead of the server-side; hence; the need for better JavaScript and rendering engines. The cloud is everywhere and people want to access it from many different devices. The browser war has even made its way to the mobile platform with contenders like Mobile IE, Safari, Opera etc. All these exciting work comes with the duty to support if not all, the major browsers in our applications.  There are lots of browsers but I will concentrate on the major ones in this post. With that said, Let introduce our contenting fellows.

Meet Mater (alias Internet Explore)

popc3

Take your time to absorb his looks. Not handsome but has been around the block for a long time. Internet Explore 1.0 debuted in 1995 to facilitate the growing hunger of the mass to access the world wide web. The use-to-be-great Netscape battled it out with IE till around 1999. IE won hands down not because of Microsoft strategy to include IE in its OS, but because IE stayed on the edge and was the only browser at that time to support a large part of of W3C Dom and CSS standards. After its success over Netscape, Internet Explorer basically stood still from 1999 to 2003 with not much activities except for the usual patches and updates here and there. It was the kingpin of Browser Spring till 2003 when Apple rebelled with Safari. By then most users were sick and tired of the old IE, for nothing had happened to it in a period of 3 years.

Meet   Lightning McQueen ( Firefox )

popc1

Catchewwww, yep, that‚Äôs the sound of spend and beauty. It‚Äôs lightning mcqueen zipping through browser spring. First released on November 9th 2004, Firefox was the resurrection/rebirth of Netscape but engineered without all the mistakes made by its predecessor. It packed the goody’s on W3C Dom and CSS¬† standards. Better yet, it was free; not like its father, Netscape. The Netscape/Mozilla team had learnt their lesson and had created a monster, formidable to stand toe to toe with IE. Firefox 2.0 push the game much further, introducing great features such as tab browsing which has now become the standard to most browsers and the extension manager, which by far; has become the most used feature set of Firefox. Firefox boost of both rendering speed (using Gecko) as well as JavaScript execution speed. It made it‚Äôs mark, and is hear to stay.

Meet Sally (Google Chrome)

popc2

Fed up with the timeline it takes to release new standards by W3C to support the modern use of browsers, Google decide to spit out Sally with her V8 cafe. V8(Chromes JavaScript engine) and Chrome have been touted as the fastest browser and JavaScript engine as of early 2008 (inception of chrome). Chrome took a different route with JavaScript by building its engine to compile JavaScript to native machine code making it fast. My first impression with Chrome was that of ‚Äď‚Äúhere goes another browser for developers to worry about‚ÄĚ. Well, I will have to say, I have been very impressed with chrome and look forward to more in the future. After all, Google‚Äôs cash making machine primarily comes from search and it‚Äôs web apps. Thus, the better the browser,the better their applications‚Äô performance.

Meet  iHudson (Safari)

popc4

Safari was developed by Apple in 2003, to ship with their flagship OS X 10. Apple boasted that Safari was the fasters browser there was but there had actually been no proof. In 2007, a windows version was released, becoming the second Apple product to trend on Microsoft territory after iTunes. Team Safari just announced a couple of months ago, their new JavaScript engine named SquirrelFish; to be the fastest JavaScript engine at present beating Google chrome’s V8. Sally must not be pleased.

Javascript Benchmarks

On same computer, an average of 10 test run on each browser


Browsers

V8 Benchmark Suite-v1 Sunspider  Javascript Benchmark
Internet Explorer 8 beta 70 7890.8ms +/- 1.3%
Safari (Windows) 3.0 71 browse froze everytime
Firefox 3.0 231
3361.6ms +/- 1.5%
Google Chrome 1.0 3200
1250.4ms +/- 8.8%

War in Browser Spring

Its amazing how all these enhancement to the web has suddenly sprung up. Every browser has to stay on the edge just to be competitive. I, for one, I’m no one to complain. Competition breads the best in everything. In the end, the end user benefits. As a developer for the web (sometimes), I’m pleased to see such excitement. IE has itself to blame; for it stayed in dormant state for way to long. Microsoft has the tendency to do that. They lack innovation in some area and I fear the browser is one of them. I could be wrong with IE 8.  MS is slated to release IE 8 sometime next year which is suppose to be more standard compliant  and supports CSS 2.1.

Who do you think will be kingpin? Let me know your thoughts.

Google Gears

Standard

Google  gearslogo_153x43    which has been greatly talk about since its release by the web giant Google has spurred a lot of talk about how web application will be in the current and near future. Gears offers to provide features that are currently needed to speed up “heavy” (memory and data) intensive web application as well as provide off-line abilities.  Gear provides the following accents for web applications :

Local Database

This is used to stored user application data locally on the users computer, providing if not exactly, close off-line db store to OS desktop applications. Gears uses the open-source db SQLite for this functionality and supports normal SQL query.

 

Local Server

The local Serve allows you to cache application information on the client and and serve them locally instead of going back to the server. It can also to automatic updates for URL resource behind the scene.

  

Applications manage the cache using two classes:

  • ResourceStore – for capturing ad-hoc URLs using JavaScript. The ResourceStore allows an application to capture user data files that need to be addressed with a URL, such as a PDF file or an image.
  • ManagedResourceStore – for capturing a related set of URLs that are declared in a manifest file, and are updated automatically. The ManagedResourceStore allows the set of resources needed to run a web application to be captured.

For both types of stores, the set of URLs captured is explicitly controlled by the web application.

Serving and updating cached resources

The LocalServer intercepts HTTP/HTTPS requests and serves them from the cache when all of these conditions are met:

  • The URL is cached in a ResourceStore or ManagedResourceStore,
  • The store’s enabled attribute is set to true, and
  • If the store has a requiredCookie attribute, the request must have a cookie that matches. For further details read Cookies and the LocalServer.

The LocalServer always serves a cached resource when the conditions are met, regardless of the network connection. The URLs contained in a store are eligible for local serving without requiring the application to open the store.

To disable local serving of stored resources and force URLs to be served using the regular network connection, the application can set the store’s enabled attribute to false.

 

WorkerPool

This allows you application to spin off asynchronies processes (with JavaScript) without halting the browser or slowing its responsiveness.

 

These are all great features that web developer have  been wanting for many year now.  A co-worker asked “This is all great news but why do we need another 3rd party engine in our browser to make this happen. We already have flash and the upcoming Silverlight from MS “. Well, flash and Silverlight offer’s similar features like local data store but they also add the extra hefty runtime engine to make it all happen instead of improving the existing and most widely used tools (HTML , CSS, JavaScript etc) .

That’s not to say that Flash, Silverlight and others are about to be left in the dust. If the is one thing they “still” have over Goggle gears, it’s the fact that the UI presentation is the same in any browser. That take away the hustle of testing web application in multiple browsers due to different implementation of the W3C standards. This might change as  like IE (with IE 8 coming up) are becoming more compliant then ever.

There is a lot of speculation as to what will happen to Gears or flash /Silverlight etc, but for now, a better solution for developing off-line web application (using our long existing knowledge of JavaScript, CSS, HTML ) have arrived and should be well noted. Gears is not for every application but if the features fits what you are looking for in your app, take a good look at it.