Watch jQuery Calculation Plug-in in action!

Posted by Dan on Feb 20, 2008 @ 8:41 AM

A few weeks ago I posted a blog entry on my jQuery Calculation Plug-in. However, I never think I do an adequate job of describing what it does so I thought a little video might be more useful. Since I just installed Jing a few days ago, I thought this plug-in made a perfect candidate for my first Jing post!

Something I forgot to specifically mention in my demo, but which I think is really significant, is that the dynamic calculation code would work regardless of how many rows were in your table. If you only had 1 item in your basket or 20 items, the exact same code is used. The key is to use a naming convention that is consistent and easy for jQuery to parse.

My original post goes into the technical details behind the demo above, so make sure to read the post for the detailed information on what's going on.

Categories: jQuery

73 Comments

  • Very cool! Both the plugin and the interactive demo!! Things like this really shine when you can see them in action!
  • I've just been getting into jquery lately, so it's cool to see more plugins like this get created.

    Just remember to never rely on client side code for important values that get sent BACK to the server!
  • @Kevin:

    Your absolutely correct in that you should never rely on values, like price, which are passed from the client to the server. This script is to help you implement better UI controls, not to be as an aid for any server-side logic that's needed.

    There are many use cases for needing to calculate values based upon your DOM layout and this is the reason I created the plug-in.
  • Excellent demo video, Dan! Great plugin, too. It was really fun to see it in action.
  • @Dan

    Exactly, Sorry to make it sound like you wouldn't know better. I guess my comment was for the google searcher / passer byer that was looking for scripts to copy / paste.
  • @Kevin:

    It's a point always worth preaching. I've done a lot of presentations at User Groups and Conferences on JavaScript--which tend to focus on the subject of Form Validation (since that's typically one of the first things people want to do with JavaScript.) While I'm a huge advocate of implementing JS-based validation because it improves the UI, I always make sure to re-iterate throughout my presentation that you can not use JS-based validation as your only method of validating data.

    Client-side technologies (such as JS) should only be used to enhance the user's experience, but the server-side is where you must validate all input to ensure that the data your receiving is valid.
  • Nice plugin but has one flaw, it is not versatile enough to be used in multiple tables. There will be a conflict from grandTotal. Another thing, maybe an option were you used checkbox and radio should be implemented. Lets say you click on radio; somehow the price should be included in the calculation. all in all nice plugin.
  • @Njau:

    There's no problem using this with multiple tables, you just need to invoke 2 different unique instances. Also, there shouldn't be a problem implementing radio buttons into the equation--provided the elements have valid numeric values.
  • Dan, would you mind showing with an example how to implement multiple tables and the radio button with values.Would be interesting to know for a rookie like me.

    Thanks
  • I'm also looking for an example of this being used with radio buttons.. Where would I find an example like that or even some documentation that step by steps it??
  • Brilliant plugin, Dan! Thank you very much!
    Since I am not the superadvanced poweruser... Is there a way to allow only integer numbers or the "." to be ignored?
  • @Daniel:

    You could change the regex used to parse the numbers if you wanted just integers to something like:

    $.Calculation.setDefaults({
     reNumbers: /(\d+(,\d{3})/g
    });
  • Thank you, Dan! ;)
  • I'm also trying to get this to work with radio buttons, seems to add all the options up and not only the selected ones.
  • @Phil:

    What do your selectors look like? I suspect your selectors are wrong for picking the value from the selected radio element.
  • Sorry, been away from this project for a little while.

    jQuery(function( $ ){
       $("input[@name='processor'], input[@name='memory'], input[@name='hard_drive']").sum('click','#total');
    });


    Code sample:
    <dt>Memory</dt>
    <dd>
    <div class="configurator_option">
    <input type="radio" name="memory" value="16"/>
    <label>1GB DDR2 667Mhz (1-1GB) - $16 | $25</label>
    </div>
    <div class="configurator_option">
    <input type="radio" name="memory" value="38"/>
    <label>1GB ECC DDR2 667 (1 - 1GB) - $38 | $60</label>
    </div>
    <div class="configurator_option">
    <input type="radio" name="memory" value="38"/>
    <label>2GB DDR2 667Mhz (1-2GB) - $38 | $50</label>
    </div>
    <div class="configurator_option">
    <input type="radio" name="memory" value="64"/>
    <label>2GB ECC DDR2 677 (1 - 2GB) - $64 | $100</label>
    </div>
    </dd>

    I fully admit that javascript/jquery are quite new for me so I could be 100% guilty of making an error a more experienced person wouldn't make.
  • @Phil:

    Use this instead for your jQuery call:

    $("input[@name='processor'], input[@name='memory'], input[@name='hard_drive']").sum({bind: 'click', selector: '#total'});

    There appears to be a bug detecting the bind parameter unless you use the object notation.
  • @Phil:

    I've just updated the code so that your original syntax should work.
  • Thanks, I will see if I can make it work now!
  • It still seems to add all the options rather than only the ones selected. In my example above it would add all 4 of the Memory options rather than only the selected one.

    I did update to the latest version. The sum is working, just not quite how I thought it should.
  • @Phil:

    Make sure you're loading the Field Plug-in:
    http://jquery.com/plugins/project/field

    Otherwise the val() function will return the value for each element (since you're not filtering to only the checked items.)
  • I am using the Field plug-in. I also switched the selector to

    $("input[@type=radio][@checked]").sum('click','#total');

    Which seems to have done the trick. But now, again likely due to my inexperience with this, the total doesn't update when I click a different radio button.

    Thanks for all your help so far. It is very much appreciated.
  • @Phil:

    You can't use the "checked" attribute selector, because then only the originally checked item gets the behavior applied to it.

    When I do:

    $(document).ready(
        function (){
            $("input[@name='processor'], input[@name='memory'], input[@name='hard_drive']").sum('click', '#total');
        }
    );

    <dt>Memory</dt>
    <dd>
        <div class="configurator_option">
            <input type="radio" name="memory" value="16"/>
            <label>1GB DDR2 667Mhz (1-1GB) - $16 | $25</label>
        </div>
        <div class="configurator_option">
            <input type="radio" name="memory" value="38"/>
            <label>1GB ECC DDR2 667 (1 - 1GB) - $38 | $60</label>
        </div>
        <div class="configurator_option">
            <input type="radio" name="memory" value="38"/>
            <label>2GB DDR2 667Mhz (1-2GB) - $38 | $50</label>
        </div>
        <div class="configurator_option">
            <input type="radio" name="memory" value="64"/>
            <label>2GB ECC DDR2 677 (1 - 2GB) - $64 | $100</label>
        </div>
    </dd>

    <div>
        <strong>Total:</strong>
        $<span id="total">0</span>
    </div>

    Only the memory item that is checked has it's value copied to the #total element.
  • Hooray! The difference was in our functions. I pasted yours in place of mine and it worked.

    Me: function( $ )

    You: function ()

    Like I said, I'm new and dysfunctional with jquery.

    Thanks much. Your plugin does exactly what I needed.
  • Hi,

    It's a great plugin, just one question.

    I'm programming an german onlineShop, so I have to use , instead of . for decimals,
    what do I have to change in the source to keep the calculation working?
  • @Philipp:

    All you need to do is to change the default regex used for finding numbers and modify the cleanse function:

    $.Calculation.setDefaults({
        // a regular expression for detecting European-style formatted numbers
        reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
        // define a procedure to convert the string number into an actual usable number
        , cleanseNumber: function (v){
            // cleanse the number one more time to remove extra data (like commas and dollar signs)
            // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
            return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
        }
    })

    The above has been tested and verified to work. I've also added this information to the example page.
  • Hi

    THX for ur reply.
    I tried it but it's still the same, I cleared the cache etc..

    It's still calculating but I get a point instead of a comma.
    My prices are using commas.

    what else can I try?
  • @Philipp:

    Are you sure you're running the latest version? Also, as my note above stated I didn't actually test the regex, but it looks like I missed escaping the "." Try this instead:

    reNumbers: /(-|-\$)?(\d+(\.\d{3})*(\,\d{1,})?|\,\d{1,})?/g

    That escapes the period to actually capture the period instead of a wildcard character.

    Let me know if that works and I'll update my comment above.
  • Hi Dan,

    I've been following your comments with Phil, and have been doing every last thing in my hopeless search to just get your plug-in working. I'm very limited with Javascript jargon, and jQuery in general. If you wouldn't mind, please have a look at my page, I've been at this for quite some time now with no luck.

    http://www.yurtsofhawaii.com/site/calc.html

    Thanks in advance!
  • @Trever:

    You need to load jQuery before loading any jQuery plug-in. That's the reason it's not working.

    Also, while it may not make a difference, I know jQuery 1.3.0 had a number of issues that have been fixed, so you might want to use v1.3.2 instead.

    Google hosts jQuery on their CDN for the public to use. The url of v1.3.2 is:
    http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/...
  • Dan,

    I've was calling jQuery from the Google server, so I've just changed that up again for you to see that it still won't work.

    After I left this post last night I experimented for another hour. I copied your entire demo page, and tried calling your exact scripts in the header. That worked. When I called the field, and calculation plug-in from my server, it stopped working.

    I'm now calling the jQuery from the Google server in the header, at:
    http://www.yurtsofhawaii.com/site/calc.html but it's not working.

    Thanks again Dan!
  • @Trever:

    The "@" was depreciated a while back, change your selector to match the format "input[name='memory']" instead of "input[@name='memory'] and it should work fine. I just ran this code in Firebug:

    $("input[name='memory']").sum('click', '#total')

    And your page began working fine.
  • Hi

    Sorry I wasn't online for a while.

    Finally I transferred my project on a testserver.
    Till now I wasn't able to get it running with commas.

    U can see it here:
    http://dev.fotosemrad.at/index.php?idcatside=4&...

    What if I just reformat the output? Would the total Sum then still work???

    THX Philipp
  • @Phillip:

    I don't see where you're using the setDefaults() method in your code. If you use that code, it should work fine with European formatting.
  • Hi

    I changed the code in here:

    http://admin.dev.fotosemrad.at/plugins/shop/inc/js...

    is that wrong??
  • @Phillip:

    I advice against changing the source code, because then it becomes more difficult to upgrade if a new version is released. That's the reason it's better to use the setDefaults() to change the behavior. Then hopefully upgrading is as simple as dropping in a new script.
  • Hi Dan,

    I'm looking to try and do something a little different with your plug-in and wondering whether it is possible in some way.

    I have a number of INPUT fields with multiple values attached to various attributes. Depending on the situation, instead of taking the usual VALUE attribute, I need to be able to chose the actual attribute from which to SUM.

    eg
    <input id="item1" name="item1" value="3" value2="1.67" value3="3.5" />
    <input id="item2" name="item2" value="4" value2="2" value3="5" />

    I was hoping to be able to do something like:
    $(#item1").attr("value2").sum();

    but unfortunately that doesn't work.
    Any ideas?

    Thanks,
    Simon
  • @Simon:

    No, that won't work. What I would recommend doing instead is changing the value attribute to the correct value based on your condition. That way the correct value gets sent to the server on a post as well.
  • That might work. I'm not too bothered about the posted values as all the calculation is happening client side, and any posting in happening via Ajax in the background. Here's me trying to overly complicate things. Thanks for your thoughts!
  • @Simon:

    I'm sure you're aware, but I would never use calculation done on the client side on the server side of thing--it's too easy for that data to be manipulated. I also add this disclaimer. You should only be using the calc() plug-in to provide the user with live feedback and shouldn't trust the values as being valid.
  • Is there a way to evaluate the result of:

    $("input[type=text]").sum("keyup", "#total");

    I need to throw an alert if the value of the sum exceeds 100.

    Thanks,

    Kevin
  • @Kevin:

    If you pass in a option object, you can use the "oncalc" callback to configure something to run after the calculation takes place. For example:

    $("input[type=text]").sum({
         bind: "keyup"
        , selector: "#total"
        , oncalc: function (value, settings){
            // use this callback for validation
        }
    });

    So, you can do your validation in the oncalc callback.
  • I'm working on a project to convert metric units. Everything works fine in all browsers except Internet Explorer. In IE, it seems like the 2nd bind event never gets called so #kg-cm never calculates. Is there something I am doing wrong with the calc() method?

    I have a few text fields:

    <table width="100%" border="0" cellspacing="0" cellpadding="0">
    <thead>
      <tr>
        <th>Bar</th>
        <th>KG/CM</th>
        <th>PSI</th>
      </tr>
    </thead>
     <tr>
      <td><input id="bar" type="text" name="ztest1" /></td>
      <td><input id="kg-cm" type="text" name="ztest2" /></td>
      <td><input id="psi" type="text" name="ztest3" /></td>
     </tr>
    </table>

    $(document).ready(function() {
    //pressure fields

        $('#bar').bind('keyup', function(event){

        $('#psi').calc(

                'bar * numberA',

                {
                    bar: $('#bar'),
                    numberA: ('14.503861')
                },

                function (a){

                    return a.toFixed(2);
                },

                function ($this){

                    var sum = $this.sum();

                    $('#psi').text(sum.toFixed(2));
                }
            );

        });


        $('#bar').bind('keyup', function(event){


         $('#kg-cm').calc(

                'bar * numberB',

                {
                    bar: $('#bar'),
                    numberB: ('1.02')
                },

                function (a){

                    return a.toFixed(2);
                },

                function ($this){

                    var sum = $this.sum();

                    $('#kg-cm').text(sum.toFixed(2));
                }
            );

        });

    }
    );
  • @deleteYourslf:

    It might be because your defining the numberA and numberB variables as strings instead of floats. It shouldn't affect things, but it might be causing issues.
  • how do i use this javascript to calculate multiple input?

    here is my html form
    <form name="form1" id="form1" method="post" action="...">
    water<input type="text" name="water"> power<input type="text" name="power">
    </form>
    and loop form to 47
    ...
    <form name="form47" id="form47" method="post" action="...">
    water<input type="text" name="water"> power<input type="text" name="power">
    </form>

    i want each form calculation water+power not calculate all from.
    thanks for help.
  • Hi Dan

    Thank you for the plugin. I was trying to use the calculator plugin for data grid that is loaded from a database. How do i support this plugin for the same ?

    Thanks
  • hey great plugin,

    i try to use the european number format (german).. but same problem than phillip..

    http://webasic.de/calculation/

    it doesn work with ","
  • @Jeff:

    It works fine with Euro strings--the problem you're having is do to the whitespace in the tag. I'm surprised this issue hasn't come up for me before, but I suspect it's because I don't leave beginning/trailing whitespace to my value.

    I've just pushed up v0.4.07, which trims the value before sending it to the regex and your code works fine now.

    http://www.pengoworks.com/workshop/jquery/calculat...
  • thx for updating,

    now it works in euro format.. i'm add replace(/\./,',') + " EUR" to the recalc function..

    like this: return s.toFixed(2).replace(/\./,',') + " EUR";

    i know, its not the best way
  • Hi Dan,

    Love the Plugin. If I have the following in a span...

    Stock No 12-1000 $150.00

    I use .calc but it picks up the 12 instead of the $150.00 when the user selects a quantity from a select list? Is there a regular expression or something I can use to parse out values with a dollar sign?

    Thanks,

    Rob
  • Hello,

    First of all I want to say this is a great plugin. But I have a problem with the formatting, I would like to have the possibility to use comma's and points for the decimals, so that 99,99 is correct and 99.99 is correct.
    Does someone have a solution for this problem?

    Regards,
    Kl4ver
  • @Kl4ver:

    See the comments above for configuring the plug-in to use European formatting. You could re-work the RegEx and cleanseNumber handler to operate on either, but my recommendation would be to explicitly set the defaults based on the expected page results (i.e. either US or Euro formatting.) Intermingling the formats on a page may prove problematic.
  • Hi Dan,
    Thanks for bringing this great script in the jQuery community! I began using the script yesterdag. The last couple of project I needed something like this and now I found it, really nice.
    But i'm running into a little issue. In your examples you use $ signs in the span's that you are calculating. I think the script remove them and use only the numbers for calculating. I'm set the script to European defaults and use € signs in my span. In that case the script won't work. I get a NaN in the return.

    This is the HTML:

              <span class="textSum">1,99</span>
              <span class="textSum">€49,99</span>
              <span id="totalTextSum">????</span>
              <input type="button" value="Calc" id="idTotalTextSum" />

    This is the script:
      var sum = $(".textSum").sum();
      $("#totalTextSum").text(sum);

    Please help me out.
    Regards, Micha
  • @Micha:

    What exactly is happening? Is it working if you leave the € sign out?

    Are you using this code to set up the euro-style formatting?

    $.Calculation.setDefaults({
        // a regular expression for detecting European-style formatted numbers
        reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
        // define a procedure to convert the string number into an actual usable number
        , cleanseNumber: function (v){
            // cleanse the number one more time to remove extra data (like commas and dollar signs)
            // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
            return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
        }
    })

    Also, try putting an alert(v) or console.log(v) in the cleanseNumber() function to see what the value looks like.
  • Hi Dan,
    it is indeed working correcty without the € sign (the value of the second span 49,99), but it won't work with the euro sign. I do use the exact code you're suggesting in the defaults section.

    I put in a alert, right before the "return v.replace.....". The first time it says "1,99" as excepected for the first span, the second time it's empty.

    Thanks for your quick reply.

    Regards
    Micha
  • Dan,
    i setup a litte demonstration, see:
    http://test.berkman.nu/calculation.htm

    grtz
    Micha
  • @Micha:

    I wasn't paying enough attention to the $ being in the regex, use this instead:

    /(-|-\$|€)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
  • Excellent! It works fine!
    Thanks for your help.
    Regards
    Micha
  • Hello everyone,

    Awesome plugin. I got one question tho. Is it possible to add a '.' when the value gets bigger than 999,00. I would like 1000,00 to look like this:
    1.000,00

    Thank you in advance.
  • @Lasse:

    You can do that by supplying the formatting callback to the calc() method. You just write a function to perform whatever formatting you want to the output.
  • Hello Dan,

    Thank you for your response.

    That is good news. :)

    Could you point me in the right direction, how to build a function performing the right output.

    Thank you in advance.
  • @Lasse:

    See this blog entry for using the formatting callback:

    http://blog.pengoworks.com/index.cfm/2008/1/23/jQu...

    Specifically, this is the formatting callback code:

        function (s){
          // return the number as a dollar amount
          return "$" + s.toFixed(2);
        },

    This code doesn't do the formatting you want, but this shows where you can add your logic.

    I don't have any tested code for user-friendly euro number formatting, but this link has several solutions:

    http://bytes.com/topic/javascript/answers/145113-f...

    I'm sure there are better solutions that you can come across w/a little time spent searching Google. :)
  • Hello Dan,

    Thank you for your response.

    I will give this a try. :)

    Thank you. :)
  • Hello,

    Here is my solution:

    function (s, swap){


    var ts=".", ds=","; // thousands and decimal separators
    if (swap) { ts="."; ts=","; } // swap if requested

    var ns = s.toFixed(0),ps=ns,ss=""; // numString, prefixString, suffixString
    var i = ns.indexOf(".");
    if (i!=-1) { // if ".", then split:
    ps = ns.substring(0,i);
    ss = ds+ns.substring(i+1);
    }
                    // return the number as a dollar amount
                    return ps.replace(/(\d)(?=(\d{3})+([.]|$))/g,"$1"+ts)+ss + "kr";
                },
  • Hi Dan,

    I also got the problem with the European formating. The calculation works fine, but I don't know where to put the following script:

    $.Calculation.setDefaults({
        // a regular expression for detecting European-style formatted numbers
        reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
        // define a procedure to convert the string number into an actual usable number
        , cleanseNumber: function (v){
            // cleanse the number one more time to remove extra data (like commas and dollar signs)
            // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
            return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
        }
    })

    I've put this on serveral places but i can't make it work. Can you make an example how to built op the script for the European formating?

    I hope you can help me.
  • @VDEKKERNL:

    If the calculation is working correctly, you have it in the right place. That code only handles translating European-style numbers into numeric values that JS can deal with.

    You can see this comment on what's need to change the formatting of the calculated number to match the type of output you want:

    http://blog.pengoworks.com/index.cfm/2008/2/20/Wat...
  • @dan

    Thanx for your reply. I think I dind't explain it the right way. Sorry about that.

    The calculation works fine, but I get 10.00 for a anwser. And it must be 10,00.
    I've tried to put the European formatring script on differnent places in the script, but can't seem to work. I keep getting errors.

    Where does the European formatting script need to be placed? And how can overrule the default formatting.
    I've also tried changing the plugin script. But I get the same errors.

    Can you make a video how to make this work. To help us European guys/girls :-)

    p.s. Sorry about the dubbel post. I lost this post :S
  • @vdekkernl:

    As my comment pointed out, the settings you're using only tell the calc plug-in how to interpret "10,00" into a numeric value that JavaScript can understand. If you want to change the output of the calculation, then you must use the callback function to style the number the way you want it displayed.

    This is something you'll have to do manually anytime you want to output a calculated value.

    This comment should put you down the right path:
    http://blog.pengoworks.com/index.cfm/2008/2/20/Wat...
  • @dan


    Thanks agian for your comment. I've set up a test page. I took your example page and stript the text. So only the calculation functions are visable.

    http://www.vdekker.nl/test/js-cal.html

    I've placed the following code:
    $.Calculation.setDefaults({
      // a regular expression for detecting European-style formatted numbers
      reNumbers: /(-|-\$)?(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})?/g
      // define a procedure to convert the string number into an actual usable number
      , cleanseNumber: function (v){
        // cleanse the number one more time to remove extra data (like commas and dollar signs)
        // use this for European numbers: v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".")
        return v.replace(/[^0-9,\-]/g, "").replace(/,/g, ".");
      }
    })

    In the js of the page. Now you can see that it gives an error. Can you please check my code and tell me where in the code I have to place the european formatting code? I've tried everything. Or maby i'm doing something else wrong?

    I hope you can help me.
  • @vdekkernl:

    As I've previously stated, the setDefaults code you're putting in there tells the Calc plug-in how to parse to find numbers. So, the reason it's not working in your example page is because you've told the Calc plug-in to expect numbers to be in the format: 1.000,00--which they are not. That's why everything is coming up as NaN.

    If you change the numbers on the page to match European formatting, it should start working.

    Here's a working example:
    http://jsfiddle.net/dswitzer/drv7v/1/
  • @Dan

    The example you put on jsfiddle is almost perfect. The , and the . are placed in the right position for European style.
    Now I tried to change the dollarsign for the eurosign, but that doens't work.
    Could you please fix that in the example too?

    Thank you in advance.
  • Sorry, the example it's not working in Firefox 7 any more...
  • Something in FF7's regex engine changed and it no longer liked the regex used for finding the European formatted numbers.

    Try using this for the regex instead:
    (-?\$?)(\d+(\.\d{3})*(,\d{1,})?|,\d{1,})

    I've updated the example to show the working RegEx:
    http://jsfiddle.net/dswitzer/drv7v/1/

    I also updated the docs to reflect the better working regex.

Comments for this entry have been disabled.