Handling user input at the source, an example using DUNS numbers and mod 10 check digits with extjs

Right now you must be thinking “what and the hell is a duns number?” or “I can’t believe my luck, I was looking for an easy way to verify duns numbers on the client side in my app!”. If you are in the first camp, then let me elaborate. The D-U-N-S number is a unique identifier used for keeping track of businesses, and a business is actually required to have one if they are to do work for the US Government, Australian Government, the United Nations, or the European Commission, so yes, you could say that it widely used. What’s really cool for UI developers about the D-U-N-S number is the fact that it is set up with a check digit and you can perform some calculations on the data entered in your apps D-U-N-S field to make sure that the entry is valid. I am sure I don’t have to tell you that eliminating bad data entry is critical to ensuring data integrity, and as with most things in life, it is often easier to take care of issues at the source of the problem before they grow, rather than spend time later trying to clean up the mess.

To set this check up in Extjs we will need to create a custom vType (http://docs.sencha.com/ext-js/4-1/#!/api/Ext.form.field.VTypes ).

The code is below.


var dunsNbr     = /\d{2}-?\d{3}-?\d{4}/i;

// vtype for Duns Number including MOD 10 Check
    Ext.apply(Ext.form.field.VTypes, {
        //  vtype validation function
        duns: function(val, field) {
            if(dunsNbr.test(val) == true){
                return mod10CheckDigit(val);
            } else {
                return false;
            }
        },
        // vtype Text property: The error text
        // to display when the validation
        // function returns false

        dunsText: 'The D-U-N-S® number is always' +
            ' presented in a distinct format:' +
            ' two digits, hyphen, three digits,' +
            'hyphen, four digits. ' +
            'For example: 04-997-7473.',
        // vtype Mask property: The keystroke filter mask
        dunsMask: /[\d\-]/i
    });

In the code above note that duns is the vtype, and the dunsText will be displayed in a qTip when the user enters the wrong input. The dunsMask is used to filter out keystrokes that do not match the pattern provided. It is important to realize that the mask is not a regex value that matches the specific string that you would like to see in your duns field, but is actually regex that lists the allowed characters in the field. This is a key point!

Now, take a look at the line of code:

if(dunsNbr.test(val) == true){ …}

. This is the code that performs the regex check on the value that has been entered. dunsNbr is declared at the top of our vType. You can find more information about Ext’s regex features here (http://docs.sencha.com/ext-js/4-1/#!/api/RegExp), but the points to remember are 1) you have to add a / before the regex statement and a /i at the end of the statement and 2) never try to plug your regex into the ‘Mask’ property.

I find that it’s easier to test my regex code on a website like: http://www.zytrax.com/tech/web/regex.htm#experiment before I put it in my javascript.

Now suppose you get through the check above, you will notice that the very next line reads:

                return mod10CheckDigit(val);

In order to check the D-U-N-S number you would take the first 8 digits in the number. Next loop through the numbers and multiply the even numbers by 2. Now the numbers greater than 10 are separated and you write out the ones and tens place and add all of the numbers together.

D-U-N-S with check digit in the 9th place = 0 4 9 9 7 7 4 73

0 4 9 9 7 7 4 7
x1 x2 x1 x2 x1 x2 x1 x2
0+8+9+1+8+7+1+4+4+1+4 = 47

In this example above , the total is 47. Subtract this total, 47 from the next highest multiple of 10, (that is 50 in this case).

50 – 47 = 3

3 = check digit

The code below uses Modulus 10 + 5, meaning if the original check digit calculation is greater than a 4, then add 5 and then subtract 10 to determine the check digit.

That’s it! So with this quick tutorial you have seen how to apply a function and some serious calculations to an Extjs vType, how you can use regex, and what Mask is all about, and how you can ensure that data gets checked at the client side before hitting your database.

The function you need is below:

 function mod10CheckDigit(value) {
        //Strip all characters except numbers
        var v   = value.replace(/[^0-9]+/g,''),
            cd  = v.substr(8,1),
            v   = v.substr(0, 8),
            total = 0,
            temp,
            tens,
            ones,
            modDigit;

        //Get Odd Numbers
        for (i=0; i <= v.length-1; i=i+2) {
            total = total + parseInt(v.substr(i,1));
        }

        //Get Even Numbers
        for (i=1; i<=v.length; i=i+2) {
            temp = parseInt(v.substr(i,1)) * 2;
            if (temp > 9) {
                tens = Math.floor(temp/10);
                ones = temp - (tens*10);
                temp = tens + ones;
            }
            total = total + temp;
        }

        //Determine the checksum
        modDigit = (10 - total % 10) % 10;

        // Now if the original check digit calculation is greater than a 4, then add
        // 5 and then subtract 10 to determine the check digit

        if (modDigit > 4){
            modDigit = ((parseInt(modDigit) + 5) - 10);
        } 

        // Duns Number Expansion OR original MOD 10 check
        if ( modDigit == cd){
            return true;
        } else {
          //  alert(modDigit + ' - ' + cd);
            Ext.Msg.alert('Invalid D-U-N-S® Number', 'The D-U-N-S® number you entered was in the correct format, however, did not pass the D-U-N-S® validation test. Please correct your input. ')
            return false;
        }
    }

Stop the backspace key from going to the previous page in your extjs app

If you have an app with just one view and there is even a small possibility that the user will open the app in a browser that they have been using to cruise around the web and the user will likely use the backspace key in your app then you should think about turning off the backspace == url -1 feature in most browsers.

If you actually want to use the backspace button for its intended purpose and you would like to map ext events to the browser history then a good choice might be using Ext.History, which you can learn about in depth by reading Ed Spencer’ blog post its use. (http://edspencer.net/2009/01/why-you-should-be-using-history-in-your.html )

Turning off the backspace key is pretty straight forward. You would just use Ext’s EventManager and create a listener to check for any keypress events that take place on the page. If the user is not in an input field then you would ignore the default action of the backspace button. Placing the code below right under your Ext.onReady … method will do the trick.

Ext.EventManager.addListener(Ext.getBody(), 'keydown', function(e){
        if(e.getTarget().type != 'text' && e.getKey() == '8' ){
            e.preventDefault();
        }
    });

Dealing with toolbars that go on forever

This should not be a shocker to anyone, but the amount of toolbar that is visible on a users machine varies greatly with screen resolution. Best case scenario, the users that you have in mind all use a computer just like your development machine, and all have the great sense to set their resolution just like yours, then of course you would be guaranteed that they would see every single toolbar item just as you meticulously laid them out. Worst case scenario, well, you could get lucky and they call the help desk asking where that button disappeared to, or maybe they just walk to the competing product, you will never know. Fortunately one simple setting will put your invisible toolbar items in a dropdown menu to the right of the visible toolbar items. The extjs example can be found here (http://docs.sencha.com/ext-js/4-1/#!/example/toolbar/overflow.html).

The code that makes this possible is:

layout: {
      overflowHandler: 'Menu'
}

Help I can’t set values in my Multiselect Combobox in extjs4

Ok, there is a little documented trick to setting multiple values in the extjs4.1 combobox when you have multiselect set to true and you are returning your values as a comma delimted string from the store. I know what you are thinking, and no I don’t mean you are storing your multiple values in the database as a comma delimited string, but let’s say you used STUFF or something like that to get the values back as a nice delimited string.

Your data would look like this if you alerted the value in the record.

Your combobox would look like this after the record was loaded:

But you want the combobox to look like this:

What you will need to do is transform your comma delimited string into an array and then set the value like this:

// this goes right before your form.loadRecord(record) code

var values = rec.get('delimited_string_field').split(',');
Ext.getCmp('your_multiselect_box').setValue(values);   

It’s that easy!

Extjs4 Color Picker in a drop down control for use on forms and in editable grids

Ok so I needed a color picker that I could stick in an editable grid or just use as a form field, but I did not want to render the complete box with the little color squares in the form, and well, a grid is pretty tight on space.

I went ahead and designed a color picker combo box that puts the hex value in the input field and underlines it in the selected color. One of the notable features is the monitorMouseLeave method that is found in Ext.Element, this performs an action after the users mouse leaves an element after a preset amount of time. In the code below it is used to hide the drop down color fields after the user leaves the picker for half a second. This way we don’t force them to make a selection, but do not penalize them for coloring outside of the lines with their mouse.

Ext.define('Ext.ux.ColorPickerCombo', {
	extend: 'Ext.form.field.Trigger',
	alias: 'widget.colorcbo',
	triggerTip: 'Please select a color.',
 	onTriggerClick: function() {
	  var me = this;
	  picker = Ext.create('Ext.picker.Color', {
		pickerField: this,
		ownerCt: this,
		renderTo: document.body,
		floating: true,
		hidden: true,
		focusOnShow: true,
		style: {
            	backgroundColor: "#fff"
        	} ,
		listeners: {
            	scope:this,
            	select: function(field, value, opts){
		me.setValue('#' + value);
		me.inputEl.setStyle({backgroundColor:value});
		picker.hide();
	},
	show: function(field,opts){
		field.getEl().monitorMouseLeave(500, field.hide, field);
		}
        	}
});
       picker.alignTo(me.inputEl, 'tl-bl?');
       picker.show(me.inputEl);
	}
});