Number Field with currency symbol, thousand separator & international support ExtJS4

http://www.sencha.com/forum/showthread.php?147962-Number-Field-with-currency-symbol-thousand-separator-amp-international-support-ExtJS4/page2

 

 

/*
 * GNU General Public License Usage
 * This file may be used under the terms of the GNU General Public  License version 3.0 as published by the Free Software Foundation and  appearing in the file LICENSE included in the packaging of this file.   Please review the following information to ensure the GNU General Public  License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
 *
 * http://www.gnu.org/licenses/lgpl.html
 *
 * @description: This class provide aditional format to numbers by extending Ext.form.field.Number
 *
 * @author: Greivin Britton
 * @email: brittongr@gmail.com
 * @version: 2 compatible with ExtJS 4
 */
Ext.define('Ext.ux.form.NumericField', {
    extend: 'Ext.form.field.Number',//Extending the NumberField
    alias: 'widget.numericfield',//Defining the xtype,
    
    currencySymbol: null,
    currencySymbolPos : 'right', // left , right
    useThousandSeparator: true,
    thousandSeparator: ',',
    alwaysDisplayDecimals: false,
    fieldStyle: 'text-align: right;',
    hideTrigger:true,
    
    initComponent: function(){
        if (this.useThousandSeparator && this.decimalSeparator == ',' && this.thousandSeparator == ',') 
            this.thousandSeparator = '.';
        else 
            if (this.allowDecimals && this.thousandSeparator == '.' && this.decimalSeparator == '.') 
                this.decimalSeparator = ',';
        
        this.callParent(arguments);
    },
    setValue: function(value){
        Ext.ux.form.NumericField.superclass.setValue.call(this, value !=  null ? value.toString().replace('.', this.decimalSeparator) : value);
        
        this.setRawValue(this.getFormattedValue(this.getValue()));
    },
    getFormattedValue: function(value){
        if (Ext.isEmpty(value) || !this.hasFormat()) 
            return value;
        else 
        {
            var neg = null;
            
            value = (neg = value < 0) ? value * -1 : value;
            value = this.allowDecimals && this.alwaysDisplayDecimals ? value.toFixed(this.decimalPrecision) : value;
            
            if (this.useThousandSeparator) 
            {
                if (this.useThousandSeparator && Ext.isEmpty(this.thousandSeparator)) 
                    throw ('NumberFormatException: invalid thousandSeparator, property must has a valid character.');
                
                if (this.thousandSeparator == this.decimalSeparator) 
                    throw ('NumberFormatException: invalid  thousandSeparator, thousand separator must be different from  decimalSeparator.');
                
                value = value.toString();
                
                var ps = value.split('.');
                ps[1] = ps[1] ? ps[1] : null;
                
                var whole = ps[0];
                
                var r = /(\d+)(\d{3})/;
                
                var ts = this.thousandSeparator;
                
                while (r.test(whole)) 
                    whole = whole.replace(r, '$1' + ts + '$2');
                
                value = whole + (ps[1] ? this.decimalSeparator + ps[1] : '');
            }
            
            if (this.currencySymbolPos == 'right') {                 return Ext.String.format('{0}{1}{2}', (neg ? '-' : ''),  value, (Ext.isEmpty(this.currencySymbol) ? '' : ' ' +  this.currencySymbol));             } else {
                return Ext.String.format('{0}{1}{2}', (neg ? '-'  : ''), (Ext.isEmpty(this.currencySymbol) ? '' : this.currencySymbol + '  '), value);             }
        }
    },
    /**
     * overrides parseValue to remove the format applied by this class
     */
    parseValue: function(value){
        //Replace the currency symbol and thousand separator
        return Ext.ux.form.NumericField.superclass.parseValue.call(this, this.removeFormat(value));
    },
    /**
     * Remove only the format added by this class to let the superclass validate with it's rules.
     * @param {Object} value
     */
    removeFormat: function(value){
        if (Ext.isEmpty(value) || !this.hasFormat()) 
            return value;
        else 
        {
            if (this.currencySymbolPos == 'right') {                 value = value.toString().replace(' ' + this.currencySymbol, '');             } else {                 value = value.toString().replace(this.currencySymbol + ' ', '');             }
            
            value = this.useThousandSeparator ? value.replace(new RegExp('[' + this.thousandSeparator + ']', 'g'), '') : value;
            
            return value;
        }
    },
    /**
     * Remove the format before validating the the value.
     * @param {Number} value
     */
    getErrors: function(value){
        return Ext.ux.form.NumericField.superclass.getErrors.call(this, this.removeFormat(value));
    },
    hasFormat: function(){
        return this.decimalSeparator != '.' ||  (this.useThousandSeparator == true && this.getRawValue() !=  null) || !Ext.isEmpty(this.currencySymbol) ||  this.alwaysDisplayDecimals;
    },
    /**
     * Display the numeric value with the fixed decimal precision and  without the format using the setRawValue, don't need to do a setValue  because we don't want a double
     * formatting and process of the value because beforeBlur perform a getRawValue and then a setValue.
     */
    onFocus: function(){
        this.setRawValue(this.removeFormat(this.getRawValue()));
        
        this.callParent(arguments);
    },
    processRawValue: function(value) {
        return this.removeFormat(value);
    }
});

OK, I think I figured out a way to get this to submit the "raw" (i.e. unformatted, numeric-only) value. And I think you were on the right track with processRawValue, brittongr. At least it appears to be working for me. Changes to the source (just the one function override) from the zip file are shown below in bold:
onFocus: function(){
        this.setRawValue(this.removeFormat(this.getRawValue()));
        
        this.callParent(arguments);
    },
    processRawValue: function(value) {
        return this.removeFormat(value);
    }
Ext.define('Teller.ext.CurrencyField', {	
extend: 'Ext.form.field.Number',	
alias: 'widget.currencyfield', 	
hideTrigger: true, 
setValue: function (v) {
	this.callParent(arguments);
 		if (!Ext.isEmpty(this.getValue())) {
			this.setRawValue(Ext.util.Format.currency(this.getValue()));
		}	}, 	removeFormat: function (v) {
		if (Ext.isEmpty(v)) {
			return '';
		} else {
			v = v.toString().replace(Ext.util.Format.currencySign, '').replace(Ext.util.Format.thousandSeparator, '');
			if (v % 1 === 0) {				// Return value formatted with no precision since there are no digits after the decimal 				return Ext.util.Format.number(v, '0');			} else {				// Return value formatted with precision of two digits since there are digits after the decimal	
			return Ext.util.Format.number(v, '0.00');			}		}	}, 	// Override parseValue to remove the currency format	
parseValue: function (v) {		return this.callParent([this.removeFormat(v)]);	}, 	// Remove the format before validating the value	getErrors: function (v) {
		return this.callParent([this.removeFormat(v)]);	}, 	/* Override getSubmitData to remove the currency format on the value 	that will be passed out from the getValues method of the form */ 	getSubmitData: function () {		var returnObject = {};		returnObject[this.name] = this.removeFormat(this.callParent(arguments)[this.name]);
 		return returnObject;	}, 	// Override preFocus to remove the format during edit	preFocus: function () {
		this.setRawValue(this.removeFormat(this.getRawValue()));
 		this.callParent(arguments);	} });