4/27/14

JavaScript DateDiff Extension Methods

When working with Date types in JavaScript, we often have the need to do date difference calculations. An approach to provide this functionality would be to extend the Date type with functions that can handle the calculations. So let’s talk about how to create these extension methods.

We can create extension methods on any JavaScript object by using the Object.prototype property. This property allows us to associate dynamic properties and functions to an object. This is what we use to associate the following functions to any Date instance.

Extension methods:

/*
Date type Extension Methods
Source: ozkary.blogspot.com
Date: 4/27/2014
*/
//Month difference
Date.prototype.monthDiff = function (dtBefore) {
      var yr = (this.getFullYear() - dt.getFullYear()) * 12;
      var mn = ((this.getMonth() + 1) - (dt.getMonth() + 1));
      return yr + mn;
}

//year difference
Date.prototype.yearDiff = function (dtBefore) {
      var yr = (this.getFullYear() - dt.getFullYear());
      return yr;
}

//date format
Date.prototype.toShortDate = function () {
      var dt = (this.getMonth() + 1) + '/' + this.getDate() + '/' + this.getFullYear();
      return dt;
}

Function name
Description
monthDiff (date)
This extension method expects a date type as a parameter. It uses native functions to calculate the years and months difference between itself (this) and the date parameter.
yearDiff (date)
This extension method expects a date type as a parameter. It uses native functions to calculate the year difference between itself (this) and the date parameter
toShortDate
This extension method uses the native functions to extract the date parts (month, day, year) and return the short date format (mm/dd/yyyy)

Usage:

Now that we have our new functions available, we can work on showing a way to use them. We can do that by comparing a couple of date ranges to display the difference in months and years. In our examples, we use the most recent date as the extended object, and pass the before date as the parameter. This allows us to get positive values for the date difference calculation.

var date1 = new Date('2/16/2014');
var date2 = new Date('09/01/2009');
$('#dates1').text(date1.toShortDate() + ' - ' + date2.toShortDate());
//get the date difference
var m = date1.monthDiff(date2);
var y = date1.yearDiff(date2);
$('#m1').text(m);
$('#y1').text(y);

//get the date difference
date1 = new Date('3/28/2014');
date2 = new Date('12/28/1996');
$('#dates2').text(date1.toShortDate() + ' - ' + date2.toShortDate());
m = date1.monthDiff(date2);
y = date1.yearDiff(date2);
$('#m2').text(m);
$('#y2').text(y);

This script performs the following steps:
  • Create Date instances
  • Display the short date format (mm/dd/yyyy)
  • Calculate the months and year differences

The result should look as shows below. We can also use this JSFiddle sample to see it in action.


Thanks for following and keep an eye for additional entries.

4/20/14

Format Currency with JavaScript and CSS

When working with currency, there is a need to format the data with commas, decimals, currency sign and an indicator for negative amounts. Let’s take a look at one approach that can help us format the data once it is rendered on the user interface.

We start by taking a look at a page that displays several numeric fields with no styles.



As we can see, these numbers are hard to read. It will be much better to just add commas and a different font for negative values. We can do this by using a CSS selector and select all the elements that we want to format.

$('* div').each(function () {   
    var item = $(this).text();
    var num = Number(item).toLocaleString('en');

    if (Number(item) < 0) {
        num = num.replace('-', '');
        $(this).addClass('negMoney');
    } else {
        $(this).addClass('enMoney');
    }

    $(this).text(num);
});

The approach here is to use the Number.toLocaleString function to format the data with commas. This provides the ability to eliminate the use of regular expression to parse the data. Now we need to add the currency sign and use a red font for negative amounts. We do this by applying these CSS classes.

.enMoney::before {
    content:"$";
}
.negMoney {
    color:red;
}
div.negMoney::before {
    content:'($';
}
div.negMoney::after {
    content:')';
}

The script adds the class name to the element. We use the enMoney and negMoney classes to provide the font style. To add the currency sign and parentheses (negative values only), we use the CSS pseudo-element ::before and ::after to apply the special currency format.  The result looks like this:




This looks much better now, and it is a simple approach that uses the browser capabilities, JavaScript and some CSS to get the formatting done.

Use this JSFiddle to play with the script: Format Currency


3/30/14

XDocument Merge XML Documents

In some instances, we may have the need to extend the information in a XML payload by merging multiple documents into one. When using the System.Xml.Linq.XDocument class, there is no method to allow us to do a merge. On this article, we extend the XDocument class to provide the Merge capabilities.

XML Documents:

We first start by showing two XML documents that can be combined into one. The base requirement with this approach is that both documents are similar with the exception of one Element that contains some unique information that is not contained on the other XML.

XML with Annual Data
XML with YTD Data
Merged XML

<Finance>
  <Company>
    <Name>OG-BIT</Name>
  </Company>
  <Annual>
    <col1>100</col1>
    <col2 />
  </Annual>
</Finance>


<Finance>
  <Company>
    <Name>OG-BIT</Name>
  </Company>
  <YTD>
    <col1>100</col1>
    <col2>200</col2>
  </YTD>
</Finance>


<Finance>
  <Company>
    <Name>OG-BIT</Name>
  </Company>
  <YTD>
    <col1>100</col1>
    <col2>200</col2>
  </YTD>
  <Annual>
    <col1>100</col1>
    <col2 />
  </Annual>
</Finance>


The company and annual information needs to be maintained.

From this XML, we need to extract the YTD information

The outcome should be a document with both reports and with single company information.

Extension Methods:

An approach to provide this feature is to create extension methods that implement the merge. This is done by adding the following static class:

    /// <summary>
    /// extension methods to enable the merge of xml documents
    /// </summary>
    internal static class XDocumentExtension
    {
        /// <summary>
        /// merge an element from one document to the root of another
        /// </summary>
        /// <param name="refDoc"></param>
        /// <param name="doc"></param>
        /// <param name="elementName"></param>
        internal static void Merge(this XDocument refDoc, XDocument doc, string elementName)
        {
            if (doc != null && !String.IsNullOrWhiteSpace(elementName))
            {

                //find the element by name
var segment = doc.Descendants().Where(elm => elm.Name.LocalName= elementName).Select(elm => elm).FirstOrDefault();
                //if found add to the original document at the root
                if (segment != null)
                    refDoc.Root.Add(segment);           
            }
        }

        /// <summary>
        /// merge an xml string into a XDocument reference
        /// </summary>
        /// <param name="refDoc"></param>
        /// <param name="xml"></param>
        /// <param name="elementName"></param>
        internal static void Merge(this XDocument refDoc, string xml, string elementName)
        {
            if (!String.IsNullOrWhiteSpace(xml) &&                              !String.IsNullOrWhiteSpace(elementName))
            {
                XDocument doc = XDocument.Parse(xml);
                refDoc.Merge(doc, elementName);
            }
        }

        /// <summary>
        /// returns the xml string with header declaration
        /// </summary>
        /// <param name="doc"></param>
        /// <returns></returns>
        internal static string ToStringWithDeclaration(this XDocument doc)
        {
            return String.Format("{0}{1}", doc.Declaration, doc.ToString());
        }       
    }

This is the description for this class:

Method
Description
Merge (XDocument, string)
Merges two XDocument references by finding an element with the LocalName equal to the parameter value.
Merge (string, string)
Loads the XML string into an XDocument reference and calls the Merge method.
ToStringWithDeclaration
Gets the merged XML string with the Declaration header when found (i.e. <?xml>)

Example:

The following example uses the extension methods to merge the documents and returns the merged XML string:

public static void main()
{
    string xml1 = @"<Finance><Company><Name>OG-BIT</Name></Company><YTD><col1>100</col1><col2>200</col2></YTD></Finance>";
    string xml2 = @"<Finance><Company><Name>OG-BIT</Name></Company><Annual><col1>100</col1><col2/></Annual></Finance>";

   XDocument doc = XDocument.Parse(xml1);
   doc.Merge(xml2, "Annual");
   string xml = doc.ToStringWithDeclaration();
}

This simple example illustrates an approach of how this can be done when using the XDocument class. There are other ways of achieving the same with other classes.


Thanks for reading.