Adding a variable to itself in a loop to produce a total

voltmer1's Avatar

voltmer1

21 Jun, 2016 02:19 PM

How would I create a variable that would be the total of another variable plus it'self for ever iteration of my foreach loop?

Here is my Velocity format:


#macro( courseSequence $yr $trm )
    <table class="courseSequence">
        <tr>
            <th>Course</th><th>Credit</th>
        </tr>

    #foreach( $num in [1..5] )
        #set( $courseName = $trm.getChild( "course-${num}" ).value )
        #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
        #set( $creditTotal = $courseCredit += $courseCredit )
        <tr>
            <td>$courseName</td><td>$courseCredit</td>
        </tr>
    #end
    <tr>
    <td>&nbsp;</td><td>Total Credits: $creditTotal</td>
    </tr>
    </table>
  1. 1 Posted by Wing Ming Chan on 21 Jun, 2016 02:40 PM

    Wing Ming Chan's Avatar

    Hi,

    First thing first. When you use the #set directive, you are dealing with a global variable. So the variable can be accessed anywhere in you program after the directive is executed.

    Second, since all variables created by #set are global, you need to reinitialize them in #foreach loops, unless you want to keep the old value of a global variable.

    Third, you can keep adding values to $creditTotal like this:

    #set( $creditTotal = $creditTotal + $courseCredit )
    
    Here I assume that you will update $courseCredit in every loop.

    Wing

  2. 2 Posted by voltmer1 on 21 Jun, 2016 03:01 PM

    voltmer1's Avatar

    Thanks Wing. It looks like its treating the "value" of $courseCredit as a string, as my $creditTotal = "45123." What is the method to convert them to type "int?"

  3. 3 Posted by Wing Ming Chan on 21 Jun, 2016 03:05 PM

    Wing Ming Chan's Avatar

    Try $_MathTool.toNumber. Of course you can also use Integer.parseInt.

    Wing

  4. 4 Posted by voltmer1 on 21 Jun, 2016 03:13 PM

    voltmer1's Avatar

    #set( $creditTotal = Integer.parseInt($creditTotal + $courseCredit ) ) and
    #set( $creditTotal = $_MathTool.toNumber($creditTotal + $courseCredit ) ) and
    #set( $creditTotal =$_NumberTool.toNumber($creditTotal + $courseCredit ) )

    all return:
    Velocity content invalid: Lexical error, Encountered: "+" (43), after : "" at unset[line 33, column 63]

  5. 5 Posted by Wing Ming Chan on 21 Jun, 2016 03:17 PM

    Wing Ming Chan's Avatar

    Before I continue, if you don't mind, are you a programmer? I need to know how to communicate with you.

    Wing

  6. 6 Posted by voltmer1 on 21 Jun, 2016 03:21 PM

    voltmer1's Avatar

    Yes, web developer, but only for 3 years.

  7. 7 Posted by Wing Ming Chan on 21 Jun, 2016 03:26 PM

    Wing Ming Chan's Avatar

    OK. Integer.parseInt is a static method, But you still need to call it through an Integer object, unless you are ready to deal with reflection. As you pointed out, $courseCredit is a string. So by $creditTotal + $courseCredit, you are adding a string to a number. Same for the second line. Try something like:

    #set( $courseCredit = $_MathTool.toNumber( $courseCredit ) )
    #set( $creditTotal = $creditTotal + $courseCredit )
    
    Wing
  8. 8 Posted by voltmer1 on 21 Jun, 2016 03:44 PM

    voltmer1's Avatar

    Well, that makes sense, but it's not outputting any result now.

    #macro( courseSequence $yr $trm )
        <table class="courseSequence">
            <tr>
                <th>Course</th><th>Credit</th>
            </tr>
    
        #foreach( $num in [1..5] )
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
        <tr>
        <td> </td><td>Total Credits: $creditTotal</td>
        </tr>
        </table>
    
    #end
    
    ~~~
    
  9. 9 Posted by Wing Ming Chan on 21 Jun, 2016 03:53 PM

    Wing Ming Chan's Avatar

    Add a line #set( $creditTotal = 0 ) right before the start tag of table. Also try to figure out why it does not work without this line (it is related to NULL).

    Wing

  10. 10 Posted by voltmer1 on 21 Jun, 2016 04:01 PM

    voltmer1's Avatar

    I cannot believe I MISSED that variable initialization!
    It's working fine now Wing. Thanks again!

  11. 11 Posted by voltmer1 on 21 Jun, 2016 08:37 PM

    voltmer1's Avatar

    Wing, Sorry to bother you again, but it only does the $creditTotal the first term of the first year correctly.

    
    #set ( $page = $_XPathTool.selectSingleNode( $contentRoot, "calling-page/system-page" ) ) 
    #set ( $data = $page.getChild( "system-data-structure" ) )
    #set( $progName = $data.getChild( "program-name" ).value )
    <p class="program">Course Sequence</p>
    
    #set( $sequence = $data.getChild( "course-sequence" ) )
    #set( $studentYears = $sequence.getChildren( "student-year" ) )
    
    #if( $studentYears.size() > 0 )
        #foreach( $studentYear in $studentYears )
            #set( $year = $_XPathTool.selectSingleNode( $studentYear, "year/value" ).value )
            #set( $studTerms = $studentYear.getChildren( "student-term" ) )
                <p class="studentYear">$year</p>
        #foreach( $studTerm in $studTerms)
          #set( $term = $_XPathTool.selectSingleNode( $studTerm, "term/value" ).value )
            <p class="studentTerm">$term</p>
                #courseSequence( $year $studTerm )
            #end
        #end
    #end
    
    #macro( courseSequence $yr $trm )
    #set( $creditTotal = 0 )
        <table class="courseSequence">
            <tr>
                <th>Course</th><th>Credit</th>
            </tr>
        #foreach( $num in [1..5] )
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
        <tr>
        <td> </td><td>Total Credits: $creditTotal</td>
       
        </tr>
        </table>
    #end
    
  12. 12 Posted by Wing Ming Chan on 22 Jun, 2016 11:55 AM

    Wing Ming Chan's Avatar

    This is what I have with my test data. Everything seems to be correct.

        <h2>My Program Course Sequence</h2> Year: Sophomore<br/>Term: Winter<br/>
        <div>
            <table
                class="courseSequence"><tr><th>Course</th><th>Credit</th></tr><tr><td>Course
                        1</td><td>3</td></tr><tr><td>Course 2</td><td>3</td></tr><tr><td>Course
                        3</td><td>4</td></tr><tr><td>Course 4</td><td>4</td></tr><tr><td>Course
                        5</td><td>5</td></tr><tr><td> </td><td>Total Credits: 19</td></tr>
            </table>
        </div>
        Term: Winter<br/>
        <div>
            <table class="courseSequence"
                        ><tr><th>Course</th><th>Credit</th></tr><tr><td>Course
                        6</td><td>1</td></tr><tr><td>Course 7</td><td>2</td></tr><tr><td>Course
                        8</td><td>3</td></tr><tr><td>Course 9</td><td>4</td></tr><tr><td>Course
                        10</td><td>5</td></tr><tr><td> </td><td>Total Credits: 15</td></tr>
            </table>
        </div>Year: Freshman<br/>Term: Spring<br/>
        <div>
            <table
                class="courseSequence"><tr><th>Course</th><th>Credit</th></tr><tr><td>Course
                        1a</td><td>3</td></tr><tr><td>Course 2a</td><td>3</td></tr><tr><td>Course
                        3a</td><td>3</td></tr><tr><td>Course 4a</td><td>3</td></tr><tr><td>Course
                        5a</td><td>3</td></tr><tr><td> </td><td>Total Credits: 15</td></tr>
            </table>
        </div> Term: Fall<br/>
        <div>
            <table class="courseSequence"
                        ><tr><th>Course</th><th>Credit</th></tr><tr><td>Course
                        A</td><td>1</td></tr><tr><td>Course B</td><td>1</td></tr><tr><td>Course
                        C</td><td>1</td></tr><tr><td>Course D</td><td>1</td></tr><tr><td>Course
                        E</td><td>1</td></tr><tr><td> </td><td>Total Credits: 5</td></tr>
            </table>
        </div>
        Term: Spring<br/>
        <div>
            <table class="courseSequence"
                        ><tr><th>Course</th><th>Credit</th></tr><tr><td>Course
                        G</td><td>3</td></tr><tr><td>Course H</td><td>3</td></tr><tr><td>Course
                        J</td><td>3</td></tr><tr><td>Course K</td><td>3</td></tr><tr><td>Course
                        L</td><td>4</td></tr><tr><td> </td><td>Total Credits: 16</td></tr>
            </table>
        </div>
    

    Wing

  13. 13 Posted by voltmer1 on 22 Jun, 2016 12:23 PM

    voltmer1's Avatar

    Well, mine only does the first term correctly, then every following term never goes below a total of 20.

  14. 14 Posted by voltmer1 on 22 Jun, 2016 12:47 PM

    voltmer1's Avatar

    Okay, I found what it is doing. Some terms don't have 5 courses, so it's taking the total value of the last creditTotal and adding it to whatever the last courses credit was for the missing field. Not quite sure how to loop through the courses without the fixed index array.

    
    #foreach( $num in [1..5] )
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
    
  15. 15 Posted by Wing Ming Chan on 22 Jun, 2016 12:59 PM

    Wing Ming Chan's Avatar

    You need to test if $trm.getChild( "course-${num}" ) is null. If it is, then use a #break to get out of the loop. You may want to take a look at my tutorial, at least the first few lessons, to make sense of what I have just suggested.

    Wing

  16. 16 Posted by voltmer1 on 22 Jun, 2016 01:38 PM

    voltmer1's Avatar

    Thanks Wing. I was trying a different approach by trying to use:

    $data.getChildren( "student-term" ).size() / 2 ) to get the number of courses and use that variable instead of the specified array in #foreach( $num in [1..5] )

    but was having issues, so I'll give your suggestion a try.

  17. 17 Posted by voltmer1 on 22 Jun, 2016 02:08 PM

    voltmer1's Avatar

    I've tried all the ways to test for null and empty and it still won't break out of the loop.

    
    #macro( courseSequence $yr $trm )
    #set( $creditTotal = 0 )
    
        <table class="courseSequence">
            <tr>
                <th>Course</th><th>Credit</th>
            </tr>
        #foreach( $num in [1..5] )
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
            #if( $trm.getChild( "course-${num}" ) == "" )
            #break
            #end
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
        <tr>
        <td> </td><td>Total Credits: $creditTotal</td>
       
        </tr>
        </table>
    #end
    
  18. 18 Posted by Wing Ming Chan on 22 Jun, 2016 02:18 PM

    Wing Ming Chan's Avatar

    To test for null, you need to use $_PropertyTool.isNull( $obj ). See lesson 7. You also want to test before you set the variables.

    Wing

  19. 19 Posted by voltmer1 on 22 Jun, 2016 02:21 PM

    voltmer1's Avatar
  20. 20 Posted by Wing Ming Chan on 22 Jun, 2016 02:25 PM

    Wing Ming Chan's Avatar

    In the Velocity context inside Cascade CMS, neither NULL nor null are defined. The empty string is just the empty string and is different than null. You can assign the empty string to a variable, but you can never assign null to a variable.

  21. 21 Posted by voltmer1 on 22 Jun, 2016 02:34 PM

    voltmer1's Avatar

    Still nothing.

     #foreach( $num in [1..5] )
         #if( $_PropertyTool.isNull($trm.getChild( "course-${num}" ) ) )
            #break
            #end
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
           
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
    
  22. 22 Posted by voltmer1 on 22 Jun, 2016 03:00 PM

    voltmer1's Avatar

    Also tried this:

      #foreach( $num in [1..5] )
        #set( $isCourse = $_XPathTool.selectSingleNode( $trm, "course-${num}" ) )
         #if( $_PropertyTool.isNull( $isCourse ) )
            #break
            #end
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
           
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
        <tr>
        <td> </td><td>Total Credits: $creditTotal</td>
       
        </tr>
        </table>
    #end
    
  23. 23 Posted by Wing Ming Chan on 22 Jun, 2016 03:06 PM

    Wing Ming Chan's Avatar

    This second piece won't work. You need to understand one important thing about Velocity: $_XPathTool.selectSingleNode can return null, and when the null is assigned to a variable, as I said before, Velocity will refuse to do that, and the variable keeps its old value. So once a variable is assigned a good value, you can NEVER reassign a null value to it. That is to say, once $isCourse is assigned a good value, it can never be nullified again, and $_PropertyTool.isNull( $isCourse ) will never be true.

    Wing

  24. 24 Posted by voltmer1 on 22 Jun, 2016 03:29 PM

    voltmer1's Avatar

    Then why doesn't this work?

    #foreach( $num in [1..5] )
        #set( $isCourse = $trm.getChild( "course-${num}" ) )
         #if( $_PropertyTool.isNull( $isCourse ) )
            #break
            #end
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
    
  25. 25 Posted by Wing Ming Chan on 22 Jun, 2016 03:35 PM

    Wing Ming Chan's Avatar

    Let's say, when $num is 3, $isCourse is assigned a good value, and $trm.getChild( "course-${num}" ) returns null when $num is 4. When #set( $isCourse = $trm.getChild( "course-4" ) ) is executed, getChild returns null, and $isCourse keeps its old value from $trm.getChild( "course-3" ) and is not null. So the test fails.

  26. 26 Posted by voltmer1 on 22 Jun, 2016 03:43 PM

    voltmer1's Avatar

    I don't see why $isCourse would keep it's value from the last iteration. It would be reassigned when the foreach changed the value of $num before the test. What am I missing?

  27. 27 Posted by Wing Ming Chan on 22 Jun, 2016 03:47 PM

    Wing Ming Chan's Avatar

    That's precisely the point. Velocity refuses to assign null to a variable. That's the built-in behavior. That's why the variable keeps its old value, because the assignment statement is ignored when a null is involved. All variables created by #set are global and can remember the old values, right?

  28. 28 Posted by voltmer1 on 22 Jun, 2016 04:20 PM

    voltmer1's Avatar

    I am at a complete loss and have to move on now. The last thing that I thought trying was from your tutorial and another post you made, but it still doesn't work.

     #foreach( $num in [1..5] )
        #set( $sd = $currentPage.getStructuredData() )
         #if( $_PropertyTool.isNull( $sd.getChild( "course-${num}" ) ) )
            #break
            #end
            #set( $courseName = $trm.getChild( "course-${num}" ).value )
            #set( $courseCredit = $trm.getChild( "course-${num}-credit" ).value )
            #set( $courseCreditInt = $_MathTool.toNumber($courseCredit) )
            #set( $creditTotal = $creditTotal + $courseCreditInt)
            <tr>
                <td>$courseName</td><td>$courseCredit</td>
            </tr>
        #end
    
  29. 29 Posted by Wing Ming Chan on 22 Jun, 2016 04:29 PM

    Wing Ming Chan's Avatar

    Hey,

    You are switching from processing page XML (with the calling-page index block) to using the Cascade API (with getStructuredData). The code will be totally different now. Why the switch?

    Wing

  30. 30 Posted by voltmer1 on 22 Jun, 2016 04:31 PM

    voltmer1's Avatar

    Because I couldn't get it to work with page XML (calling-page index block). Well, neither works.

Discussions are closed to public comments.
If you need help with Cascade CMS please start a new discussion.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac

 

26 Aug, 2016 01:19 PM
25 Aug, 2016 03:02 PM
25 Aug, 2016 12:50 PM
24 Aug, 2016 08:43 PM
24 Aug, 2016 07:20 PM
21 Aug, 2016 01:20 PM