Javascript function question.

Discussion in 'Web Design and Development' started by zlinuk, Feb 21, 2010.

  1. zlinuk macrumors member

    Joined:
    Jul 8, 2008
    Location:
    UK
    #1
    Can a function make a call to itself? ie in theory would something like this work.

    Code:
    function checkForNull ()
               
              var i=document.getElementById("someElement").value;
    
             if (i=='null')
             {
             checkForNull ();
             }
             else
             {
             callDifferentFunction ();
            }
    
    
    The idea is that onLoad the if statement will loop until the data (from an XML file) get loaded into "someElement".

    Thanks in advance.
     
  2. Cerebrus' Maw macrumors 6502

    Joined:
    Mar 9, 2008
    Location:
    Brisbane, Australia
    #2
    Yes, this method of programming is known as recursion, where you call a method within that method itself.

    .You can use the setTimeout function to put the program to sleep for a few seconds, rather then constantly calling the method, which may cause the page to slow down.
     
  3. zlinuk thread starter macrumors member

    Joined:
    Jul 8, 2008
    Location:
    UK
    #3
    Thanks very much CM, oddly enough my original solution was this
    Code:
    function timing()
    {
    var t=setTimeout("callDifferentFunction()",500);
    }
    
    which worked ok when run locally but needs to be pushed out to something around 3 seconds when accessing over WAN.

    To me it didn't seem a very elegant solution.

    Would you recommend this as the better option. (you may notice that the code was shamelessly stolen from the W3Schools example)
     
  4. Cerebrus' Maw macrumors 6502

    Joined:
    Mar 9, 2008
    Location:
    Brisbane, Australia
    #4
    I would say that this

    Code:
    function timing()
    {
    var t=setTimeout("callDifferentFunction()",500);
    }
    
    is a far more elegant solution! :)

    It is easier to read, and one of the most important rules of programming is not to redesign the wheel. You may as well use built in API methods such as setTimeout rather then spending time writing your own code for functionality that already exists.

    If you need to push it out to three second, simply put 3000 as the second argument in the setTimeout function
    Code:
    {
    var t=setTimeout("callDifferentFunction()",3000);
    }
    
    -Maw
     
  5. angelwatt Moderator emeritus

    angelwatt

    Joined:
    Aug 16, 2005
    Location:
    USA
    #5
    If you explain more about what you're doing we can probably provide a better solution than to guessing how long it will take for something to load. You can make use of the onload event for other objects than just the document, and if you're loading XML you may be able to make use of some AJAX stuff.
     
  6. zlinuk thread starter macrumors member

    Joined:
    Jul 8, 2008
    Location:
    UK
    #6
    Thanks for your input gents.

    I am building a company intranet, the intention is that we can have quick and efficient access to both the technical and pricing information from a single source (this info is currently held on 2 seperate systems), there are approximately 600 products each of which will have a number of configurable options.

    The backend is an access database (which in turn calls data from our accounting software, where the product pricing information is held).

    I am using Dreamweaver as my editor of choice and I utilise Adobe's Spry Framework for menu's, animation, data handling, etc. All product information comes into the page as a Spry XML Dataset.

    In this particular instance I am only working on a test page so that a principle can be established, this is what I am trying to achieve;

    Product_A is made up of 2 seperate components;

    Component_1 has 5 options (call this ds1)
    Component_2 has 5 options (call this ds2)

    So Selling Price of Product_A = selection from ds1 + selection from ds2

    The two datasets are presented in seperate tables, each with selectable rows and a seperate detail region that contains the price for the selected component. The price detail region updates when a different component is selected in the table.

    The task here was to simply add together the 2 prices and have the total presented as a "Total Price"

    So this is what was needed.

    When page initially loads carry out the calculation based on the default selection in the two tables.

    When a different selection is made in either of the tables (and the price in the detail region changes) carry out the calculation again.

    This solution works:

    MyScripts.js

    Code:
    function DelayedStartCalc(){
    	var t1=setTimeout("StartCalc()",3000);
      	var t2=setTimeout("StopCalc()",3500);
    }
    
    function DelayedStopCalc(){
      	var t2=setTimeout("StopCalc()",300);
    }
    
    function StartCalc(){
      interval = setInterval("Calc()",1);
    }
    
    function StopCalc(){
      clearInterval(interval);
      alert ("Stopped"); //This is here for testing purposes only
    }
    
    function Calc(){
      one = document.autoSumForm.firstBox.value;
      two = document.autoSumForm.secondBox.value; 
      three = (one * 1) + (two * 1);
      document.autoSumForm.thirdBox.value = three.toFixed(2);
    }
    
    On the <body>

    Code:
         <body onload="DelayedStartCalc()">
    
    On the <tbody> of both tables

    Code:
          <tbody spry:repeat="ds1" spry:choose="choose" onmousedown="StartCalc()" onmouseup="DelayedStopCalc()">
    
    The detail region

    Code:
    <form  name="autoSumForm">
    <div spry:detailregion="ds1"><input  class="alignright" readonly="readonly"  type=text name="firstBox" value="{Price}.00"></div>
    <div spry:detailregion="ds2"><input class="alignright" readonly="readonly" type=text name="secondBox" value="{Price}.00" /></div>  
    <input class="alignright" readonly="readonly" type=text name="thirdBox" />
    </form>
    
    I would appreciate it if any of you .js guru's can suggest any improvement.
     
  7. angelwatt Moderator emeritus

    angelwatt

    Joined:
    Aug 16, 2005
    Location:
    USA
    #7
    At the start of the thread you mentioned waiting for some XML data to be finished loading, but I don't see anything here about that. How is that XML being loaded in?

    Here's some improvement on your Calc function though that can handle errors more gracefully.
    PHP:
    function Calc(){
      try {
        var 
    one parseFloat(document.autoSumForm.firstBox.value);
        var 
    two parseFloat(document.autoSumForm.secondBox.value);
        var 
    three one two;
        
    document.autoSumForm.thirdBox.value three.toFixed(2);
      }
      catch (
    e) {
        
    // Likely one of the values is not a number
      
    }
    }
     
  8. zlinuk thread starter macrumors member

    Joined:
    Jul 8, 2008
    Location:
    UK
    #8
    Thanks for that angelwatt,

    re the XML, in the head of the document

    Code:
    <script type="text/javascript">
    var ds1 = new Spry.Data.XMLDataSet("/Asp/SinglePinBracket.asp", "export/row");
    ds1.setColumnType("Price", "number");
    var ds2 = new Spry.Data.XMLDataSet("/Asp/2PinBracket.asp", "export/row");
    ds2.setColumnType("Price", "number");
    var ds3 = new Spry.Data.XMLDataSet("/Asp/DummyPins.asp", "export/row");
    ds3.setColumnType("Price", "number");
    </script>
    
    which is then used as described above.

    A couple of questions re your code:

    what does the 10 represent at the end of the var declaration?
    and
    is catch (e) the same as catch (err)

    Thanks
     
  9. angelwatt Moderator emeritus

    angelwatt

    Joined:
    Aug 16, 2005
    Location:
    USA
    #9
    I'll have to look into those Spry functions. I don't use DreamWeaver.

    The 10 represents the base of the number being parsed. This makes sure it's base 10 and not base 16, 8, or binary. For instance, if it tried to parse 08 you would get 0 as the result and not 8 because base 8 numbers start with a 0 often. Though, I forgot the second argument is only used with parseInt and not parseFloat so you can remove that from the code I provided.

    You can use "e" or "err" or any variable name really for the catch. It just holds the error message from the try block when it fails. You can do whatever you want with the error message including nothing.
     
  10. angelwatt Moderator emeritus

    angelwatt

    Joined:
    Aug 16, 2005
    Location:
    USA
    #10
    Alright, I found a decent page on Spry from Adobe. There is a onDataChanged event you can use to call another function, which is what you want. Here's example code they offer. The linked page is long so search for "onDataChanged" to find it more easily.

    PHP:
    var dsPhotos = new Spry.Data.XMLDataSet("/photos.php?galleryid=2000""/gallery/photos/photo");
    ...
    var 
    myObserver = new Object;
    myObserver.onDataChanged = function(dataSetdata)
    {
        
    alert("onDataChanged called!");
    };
    dsPhotos.addObserver(myObserver);
    So, if I understand it, you can then change your code to something like,
    PHP:
    function Calc() {
      try {
        var 
    one parseFloat(document.autoSumForm.firstBox.value);
        var 
    two parseFloat(document.autoSumForm.secondBox.value);
        var 
    three one two;
        
    document.autoSumForm.thirdBox.value three.toFixed(2);
      }
      catch (
    e) {
        
    // Likely one of the values is not a number
      
    }
    }
    var 
    theObserver = new Object;
    theObserver.onDataChanged = function (dataSetdata) { Calc(); };

    var 
    ds1 = new Spry.Data.XMLDataSet("/Asp/SinglePinBracket.asp""export/row");
    ds1.setColumnType("Price""number");
    ds1.addObserver(theObserver);

    var 
    ds2 = new Spry.Data.XMLDataSet("/Asp/2PinBracket.asp""export/row");
    ds2.setColumnType("Price""number");
    ds2.addObserver(theObserver);

    var 
    ds3 = new Spry.Data.XMLDataSet("/Asp/DummyPins.asp""export/row");
    ds3.setColumnType("Price""number");
    ds3.addObserver(theObserver);
    Then you shouldn't need to worry about using the onload event on the body tag. I can't test this code since I don't have DW, so it may not work as is, but should put you in the right direction.
     
  11. zlinuk thread starter macrumors member

    Joined:
    Jul 8, 2008
    Location:
    UK
    #11
    angelwatt, thanks again for your efforts, I will have a read up on observers and implement you modifications when I get into the office in the morning.

    The test page is evolving nicely, i've now dropped the use of <form> and <input> in favour of a simple <table> and the use of .innerHTML to read/write to the target <td>
     

Share This Page