Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Looping through 2D array shopping cart 1

Status
Not open for further replies.

JanetB

Programmer
Oct 10, 2002
9
0
0
US
I am new to this and am in need of assistance. I need to loop through the shopping cart to look for duplicate stocknumbers. Desired result will be that the item quantity will be increased if stocknumber already exists in the shopping cart. Code to follow:

<cfloop collection=&quot;#FORM#&quot; ITEM=&quot;VarName&quot;>
<cfif VarName NEQ &quot;AddToCart&quot;><!--- nothing for submit form field --->
<cfset stocknum = #VarName#>
<cfset quantity = #FORM[VarName]#>

<CFIF quantity NEQ &quot;&quot;><!--- if there is a quantity --->
<cfquery name=&quot;qryGetItem&quot; datasource=&quot;landscape&quot; dbtype=&quot;ODBC&quot;><!--- get item info --->
SELECT StockNum, Price, Detail, Note, ShipCode
FROM Item
WHERE StockNum = '#stocknum#'
</cfquery>
<!--- get the length of the array and add one to it --->

<!--- then edit the current quantity which is session.cart[position][2]--->

<!--- else (stocknum is different) --->
<cfif #qryGetItem.RecordCount# GT 0> <!--- if we got a record we'll add next --->
<cfset position = ArrayLen(session.cart) + 1>

<cfloop condition=&quot;#stocknum# EQ #session.cart[position][1]#&quot;>
<cfset session.cart[position][2] = #FORM[VarName]# + #quantity#>

<cfset session.cart[position][1] = &quot;#stocknum#&quot;><!--- stock number --->
<cfset session.cart[position][2] = &quot;#quantity#&quot;><!--- quantity --->
<cfset session.cart[position][3] = &quot;#qryGetItem.price#&quot;> <!--- price --->
<cfset session.cart[position][4] = &quot;#qryGetItem.detail#&quot;><!--- description --->
<cfset session.cart[position][5] = &quot;#qryGetItem.shipcode#&quot;><!--- shipcode --->
<cfif IsDefined(&quot;qryGetItem.note&quot;)>
<cfset session.cart[position][6] = &quot;#qryGetItem.note#&quot;><!--- note --->
<cfelse>
<cfset session.cart[position][6] = &quot; &quot;><!--- no note, make blank --->
</cfif>
<!--- set the total cost of all items --->
<cfset current_cost = #qryGetItem.price# * #quantity#>
<cfset session.RunningTotal = session.RunningTotal + current_cost>
</CFLOOP><!--- end of conditional loop --->
</cfif><!--- end recordcount --->
<!--- end of is stocknum is same --->


</cfif><!--- end of if quantity --->

</CFIF><!--- end if not submit --->
</cfloop> <!--- end of the loop of items to add --->
<!--- send the user to the view page --->
<cflocation url=&quot; addtoken=&quot;YES&quot;>
 
Hi csteinhilber,
The part that is currently not working is as follows:

<cfset session.cart[position][2] = #FORM[VarName]# + #quantity#>


I am having difficulty getting the quantity to increase if a stock # is put in the cart that already exists in the cart. I have only been doing this for three months now and feel very lost here. Hope you may be able to assist. Thanks in advance.
 
Near as I can tell, without being able to actually troubleshoot on your system, there are a couple of things that seem incorrect that could be causing your problem.

First, at the beginning of the code you posted (line 4), you set Variables.quantity to the value of the form field... but then on line 21 (the line you posted in your follow-up), you set the value in the cart array to Variables.quantity plus the value of the form field. In essence, you're setting the quantity to 2 x the value of the form field. When I think what you want to do is take the value already in the array and add the value of the form field to it.
So it would be something more like:
Code:
<cfset session.cart[position][2] = session.cart[position][2] + quantity>

Second, if I take your code at face value,
Code:
<cfset position = ArrayLen(session.cart) + 1>
won't do what you seem to think it will do. You can't increase the size/length of the array by simply specifying a higher value for position. You'll need to use ArrayResize, or, probably more appropriate, ArrayAppend.

Third, even though you're setting the value of
Code:
session.cart[position][2]
to your increased quantity (with the corrected code above) on line 21, you then set it back to the original quantity on line 24.

Forth, you're not using the conditional loop correctly, I don't believe. You're saying &quot;while the Variables.stocknum is equal to the value in the array element, do this...&quot;, but if Variables.stocknum isn't equal to the value in the array element from the get go, the loop will never process.
You would have to loop through each element in the array and check it against Variables.stocknum, update the quantity if it's equal, leave it alone if it's not, and then if after you've looped through the entire array you haven't updated anything then add a new element to the array.

Something like (this is untested code, but it should be close):
Code:
<cfset foundMatch = &quot;false&quot;>
<cfloop index=&quot;whichElement&quot; from=&quot;1&quot; to=&quot;#ArrayLen(session.cart)#&quot;>
	<cfif session.cart[whichElement][1] = stocknum>
		<cfset session.cart[position][2] = session.cart[position][2] + quantity>
		<cfset foundMatch = &quot;true&quot;>
		<!--- you could use a CFBREAK here... 
		      but true coders will tell you not to --->
	</cfif>
</cfloop>
<cfif foundMatch EQ &quot;false&quot;>
	<!--- we didn't find a match above, so we need to add a
	      new element to the cart array --->
	
	<!--- first we load up a temporary array with the
	      values, since you're using a multi-dimensional array --->
	<CFIF NOT IsDefined(&quot;temparray&quot;) OR NOT IsArray(temparray)>
		<!--- since you're looping through multiple stocknums, it's
		      not necessary to keep creating the temparray, just create
			  it the first time --->
		<CFSET tempArray = ArrayNew(1)>
		<CFSET setSuccessful = ArraySet(tempArray, 1, 6, &quot; &quot;)>
	</CFIF>
	<cfset tempArray[1] = &quot;#stocknum#&quot;><!--- stock number  --->
	<cfset tempArray[2] = &quot;#quantity#&quot;><!--- quantity --->
    <cfset tempArray[3] = &quot;#qryGetItem.price#&quot;>   <!--- price --->
	<cfset tempArray[4] = &quot;#qryGetItem.detail#&quot;><!--- description --->
	<cfset tempArray[5] = &quot;#qryGetItem.shipcode#&quot;><!--- shipcode --->
	<cfif IsDefined(&quot;qryGetItem.note&quot;)>
		<cfset tempArray[6] = &quot;#qryGetItem.note#&quot;><!--- note --->
	</cfif>
	
	<!--- once everything is in the temporary array, append it to
	      your cart as a new element --->
	<cfset appendSuccessful = ArrayAppend(session.cart,temparray)>
</cfif>

Fifth, you're checking whether you're reading the FORM value for your submit button (&quot;AddToCart&quot;)... but not whether you're checking the value for &quot;FIELDNAMES&quot;, which always contains a value (ie - it would pass the CFIF quantity NEQ &quot;&quot; test, but would probably break the rest of your code).

Lastly, even if quantity contains something, you don't necessarily know that it's a numeric value. If someone entered &quot;G&quot; in the form field it would, again, pass the CFIF quantity NEQ &quot;&quot; test, but Cold Fusion would complain when you tried to add it to the existing value for the item quantity.


One thing that would probably make your life easier is using a hashed or indexed array - what CF calls a &quot;structure&quot; - rather than the freeform multidimensional array you're using. This way, you can easily relate the data in the array to the item it pertains to. You can do it by checking subelement 1 of each element in your cart, as above, or you can let Cold Fusion do the dirty work for you with it's built in structure functions.

In addition, I would suggest using a list instead of a second dimension of an array. In ColdFusion, you can get at items in a list just as easily as an array element, with a bit less house-cleaning. If your notes or details db columns might contain commas (ie - if they're body text), you might use a different list delimiter, like a pipe &quot;|&quot;.

With a structure as the main basis, and a list as the second dimension, you can turn the above mess into something that might be a lot easier to maintain, like:

Code:
<cfloop collection=&quot;#FORM#&quot; ITEM=&quot;VarName&quot;>    
    <cfif VarName NEQ &quot;AddToCart&quot; AND VarName NEQ &quot;FIELDNAMES&quot;>
        <cfset stocknum = #VarName#>
        <cfset quantity = #FORM[VarName]#>

		<cfif quantity NEQ &quot;&quot; AND IsNumeric(quantity)>
			<CFIF not isdefined(&quot;session.cartstructure&quot;)>
				<CFSET session.cartstructure = structnew()>
			</CFIF>			
	
			<cfif StructKeyExists(session.cartstructure,stocknum)>
				<!--- the stock number is already in the structure,
				      we just need to update the quantity --->
					  
				<!--- get the current list of information --->
				<CFSET itemInfo = StructFind(session.cartstructure,stocknum)>
				<!--- get the current value for the items quantity --->
				<CFSET itemQuantity = ListGetAt(&quot;#theItemInfo#&quot;,1,&quot;|&quot;)>
				<!--- add the value for the quantity submitted --->
				<CFSET itemQuantity = itemQuantity + quantity>
				<!--- insert it into the list of informaion --->
				<CFSET theItemInfo = ListSetAt(&quot;#theItemInfo#&quot;,1,itemQuantity,&quot;|&quot;)>
				<!--- and update the structure --->
				<CFSET updateSuccessful = StructUpdate(session.cartstructure,stocknum,theItemInfo)>
				
				<!--- the above could all be concatenated, of course, into less lines, if you like --->			
			<cfelse>
				<!--- the stock number isn't in the structure,
				      so build the list of information... --->
				<CFSET theItemInfo = &quot;#quantity#|#qryGetItem.price#|#qryGetItem.detail#|#qryGetItem.shipcode#|#qryGetItem.note#&quot;>
				<!--- and insert it into the structure --->
				<CFSET StructInsert(session.cartstructure,stocknum,theItemInfo)>
			</cfif>
		</cfif>
	</cfif>
</cfloop>
Hope it helps,
-Carl
 
Almost forgot...

if you're storing your cart in a session variable (as it certainly appears you are), you're probably going to want to utilize
Code:
<CFLOCK scope=&quot;SESSION&quot; type=&quot;EXCLUSIVE&quot;>
.

And rather than lock the session scope for your entire loop of form elements, you'll probably want to duplicate the structure/array and then unlock the scope while you're processing your loop.

Something like:
Code:
<CFLOCK scope=&quot;SESSION&quot; type=&quot;READONLY&quot;>
   <CFSET workingStruct = Duplicate(session.cartstructure)>
</CFLOCK>

<!--- process loop to update values in &quot;workingStruct&quot;

           :
           :
--->

<CFIF changesWereMade ...>
   <CFLOCK scope=&quot;SESSION&quot; type=&quot;EXCLUSIVE&quot;>
       <CFSET clearSuccessful = StructClear(session.cartstructure)>
       <CFSET session.cartstructure = Duplicate(workingStruct)>
   </CFLOCK>
</CFIF>
<CFSET clearSuccessful = StructClear(workingStruct)>

Hope it helps,
-Carl
 
Carl, I really appreciate your help. Work has moved me to form validation for our credit card customers right now but, I expect I'll be back to this in a few days. I'll try your sugestions then. Again, thank you.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top