Adding a variable to itself in a loop to produce a total
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> </td><td>Total Credits: $creditTotal</td>
</tr>
</table>
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
1 Posted by Wing Ming Chan on 21 Jun, 2016 02:40 PM
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
Here I assume that you will update$creditTotal
like this:$courseCredit
in every loop.Wing
2 Posted by voltmer1 on 21 Jun, 2016 03:01 PM
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 Posted by Wing Ming Chan on 21 Jun, 2016 03:05 PM
Try
$_MathTool.toNumber
. Of course you can also useInteger.parseInt
.Wing
4 Posted by voltmer1 on 21 Jun, 2016 03:13 PM
#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 Posted by Wing Ming Chan on 21 Jun, 2016 03:17 PM
Before I continue, if you don't mind, are you a programmer? I need to know how to communicate with you.
Wing
6 Posted by voltmer1 on 21 Jun, 2016 03:21 PM
Yes, web developer, but only for 3 years.
7 Posted by Wing Ming Chan on 21 Jun, 2016 03:26 PM
OK.
WingInteger.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:8 Posted by voltmer1 on 21 Jun, 2016 03:44 PM
Well, that makes sense, but it's not outputting any result now.
9 Posted by Wing Ming Chan on 21 Jun, 2016 03:53 PM
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 Posted by voltmer1 on 21 Jun, 2016 04:01 PM
I cannot believe I MISSED that variable initialization!
It's working fine now Wing. Thanks again!
11 Posted by voltmer1 on 21 Jun, 2016 08:37 PM
Wing, Sorry to bother you again, but it only does the $creditTotal the first term of the first year correctly.
12 Posted by Wing Ming Chan on 22 Jun, 2016 11:55 AM
This is what I have with my test data. Everything seems to be correct.
Wing
13 Posted by voltmer1 on 22 Jun, 2016 12:23 PM
Well, mine only does the first term correctly, then every following term never goes below a total of 20.
14 Posted by voltmer1 on 22 Jun, 2016 12:47 PM
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.
15 Posted by Wing Ming Chan on 22 Jun, 2016 12:59 PM
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 Posted by voltmer1 on 22 Jun, 2016 01:38 PM
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 Posted by voltmer1 on 22 Jun, 2016 02:08 PM
I've tried all the ways to test for null and empty and it still won't break out of the loop.
18 Posted by Wing Ming Chan on 22 Jun, 2016 02:18 PM
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 Posted by voltmer1 on 22 Jun, 2016 02:21 PM
Why won't these work?
http://wiki.apache.org/velocity/CheckingForNull
20 Posted by Wing Ming Chan on 22 Jun, 2016 02:25 PM
In the Velocity context inside Cascade CMS, neither
NULL
nornull
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 Posted by voltmer1 on 22 Jun, 2016 02:34 PM
Still nothing.
22 Posted by voltmer1 on 22 Jun, 2016 03:00 PM
Also tried this:
23 Posted by Wing Ming Chan on 22 Jun, 2016 03:06 PM
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 Posted by voltmer1 on 22 Jun, 2016 03:29 PM
Then why doesn't this work?
25 Posted by Wing Ming Chan on 22 Jun, 2016 03:35 PM
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 Posted by voltmer1 on 22 Jun, 2016 03:43 PM
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 Posted by Wing Ming Chan on 22 Jun, 2016 03:47 PM
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 Posted by voltmer1 on 22 Jun, 2016 04:20 PM
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.
29 Posted by Wing Ming Chan on 22 Jun, 2016 04:29 PM
Hey,
You are switching from processing page XML (with the
calling-page
index block) to using the Cascade API (withgetStructuredData
). The code will be totally different now. Why the switch?Wing
30 Posted by voltmer1 on 22 Jun, 2016 04:31 PM
Because I couldn't get it to work with page XML (calling-page index block). Well, neither works.