+ Start a Discussion
Tyler HarrisTyler Harris 

Increment a count else add item to list Apex

Hi All,

I'm trying to increment a counter if a user tries to add the same merchandise item to the shopcart. If its a new merchandise item, add the item with it's correct total.
 
public class StoreFront2 {


    public String message { get; set; }
 	DisplayMerchandise[] products;
    DisplayMerchandise[] cart;

	
                           
    public PageReference shop(){
        
        for(DisplayMerchandise c :products){
            if(c.id == cart.merchandise.id){
                cart.count++;
            }
            else{
                cart.add(c);
            }
            
        }
        message = 'You bought: ';
        for (DisplayMerchandise p:products){
            if(p.count > 0){
               message += p.merchandise.name + ' (' + p.count + ') ' ;
                
                
               }
 
            
            }
        
    
      
        return null;
    }


    
 public DisplayMerchandise[] getCart() {
    if(cart == null){
        cart = new DisplayMerchandise[]{};
    }
    
    return cart;
}
    
        public class DisplayMerchandise {
        public Merchandise__c merchandise{get; set;}
        public Decimal count{get; set;}
        public DisplayMerchandise(Merchandise__c item){
            this.merchandise = item;
        }
       }
    
    public DisplayMerchandise[] getProducts() {
        
        if (products == null){
            products = new DisplayMerchandise[]{};
            for (Merchandise__c item : 
            [SELECT id, name, description__c, price__c
            FROM Merchandise__c
            WHERE Total_Inventory__c > 0]) {
            
            products.add(new DisplayMerchandise(item));
         	
            }
    
    }
        
    return products;
    }

}

 
Best Answer chosen by Tyler Harris
JayantJayant

You are using {!carti[carti].count} instead of {!cart[carti].count}. Correct it and it should be fixed.

It should be -  { ! c a r t [ c a r t i ] . c o u n t } without the spaces.

You may also copy the mark-up I had pasted earlier.

All Answers

Mohit Bansal6Mohit Bansal6
Hi Tyler

At line 13, it should be: 

13            if(c.merchandise.id == cart.merchandise.id){

Please try and let me know, if you are still facing issue.
 
Tyler HarrisTyler Harris
It's showing a "Initial term of field expression must be a concrete SObject: List<StoreFront2.DisplayMerchandise>
JayantJayant
Seems like DisplayMerchandise and Cart are instances of some class, can you please paste those classes (or at least the attributes) ?
Tyler HarrisTyler Harris
They are instances of the DisplayMerchandise inner class. They are working on the Merchandise__c custom object I've created.
Mohit Bansal6Mohit Bansal6
Tyler,

At line 13 below code should be working fine, i think the error is due to some other line of code. Can you just add this line and share screenshot of error?

13            if(c.merchandise.id == cart.merchandise.id){
 
Tyler HarrisTyler Harris
User-added image
Looks like your advice clear the initial error, but now it's throwing it for an inner variable.
Mohit Bansal6Mohit Bansal6
Tyler,

there is no need to create new variable.

Replace "increse" with "cart"
JayantJayant
The variable 'increase' that you are using is not declared.
While line #14 suggests it should be a local variable of Id type, line # 15 suggests its a instance of DisplayMerchandise.

Make it - 

DisplayMerchandise increase = c;

at line #14.

Ideally you should declare 'increase' based on the scope you want to live it for.
Tyler HarrisTyler Harris
Thank you! How can I increment the count value in the cart?

for(DisplayMerchandise c :products){
            if(c.merchandise.id == cart.merchandise.id){
                DisplayMerchandise increase = c;
                cart.count += increase.count;
            }

 
JayantJayant
If I am not wrong 'cart' is a list ?

You should have a nested for loop to compare an instance of DisplayMerchandise with an element in the list - cart.

Or to improve performance have Maps instead to retrieve required instances based on Id.
Tyler HarrisTyler Harris
Yes. Like this?

    for(DisplayMerchandise c :products){
            if(c.merchandise.id == cart.merchandise.id){
                for(DisplayMerchandise increase:c){
                cart.count += increase.count;
                }
Mohit Bansal6Mohit Bansal6
Tyler,

for(DisplayMerchandise c :products){
            if(c.merchandise.id == cart.merchandise.id){
                cart.count += cart.count;
            }

This should work for you.
Tyler HarrisTyler Harris
Hi Mohit,

It's still throwing a Field expression must be a concrete SObject:List <StoreFront.DisplayMerchandise> on line 14
 
public class StoreFront2 {


    public String message { get; set; }
 	DisplayMerchandise[] products;
    DisplayMerchandise[] cart;

	
                           
    public PageReference shop(){
        
        for(DisplayMerchandise c :products){
            if(c.merchandise.id == cart.merchandise.id){
                cart.count += cart.count;
              
            }
            else{
                cart.add(c);
            }
            
        }
        message = 'You bought: ';
        for (DisplayMerchandise p:products){
            if(p.count > 0){
               message += p.merchandise.name + ' (' + p.count + ') ' ;
                
                
               }
 
            
            }
        
    
      
        return null;
    }


    
 public DisplayMerchandise[] getCart() {
    if(cart == null){
        cart = new DisplayMerchandise[]{};
    }
    
    return cart;
}
    
        public class DisplayMerchandise {
        public Merchandise__c merchandise{get; set;}
        public Decimal count{get; set;}
        public DisplayMerchandise(Merchandise__c item){
            this.merchandise = item;
        }
       }
    
    public DisplayMerchandise[] getProducts() {
        
        if (products == null){
            products = new DisplayMerchandise[]{};
            for (Merchandise__c item : 
            [SELECT id, name, description__c, price__c
            FROM Merchandise__c
            WHERE Total_Inventory__c > 0]) {
            
            products.add(new DisplayMerchandise(item));
         	
            }
    
    }
        
    return products;
    }

}

 
JayantJayant
Tweaked your code a bit, see if you can use this or this works for you ?
Primarily modified 'cart' to a map instead of a list. Its copied from Notepad++, regret any inconvenience in reading.
---------------------------------

public class StoreFront2 {
    public String message { get; set; }
    List<DisplayMerchandise> products;
    Map<Id, DisplayMerchandise> cart;

    public PageReference shop(){
        for(DisplayMerchandise c : products){
            if(cart.containsKey(c.merchandise.Id)){
                cart.get(c.Id).count = count++;
            }
            else{
                cart.put(c.merchandise.Id, c);
            }            
        }
        
        message = 'You bought: ';
        for (DisplayMerchandise p:products){
            if(p.count > 0){
               message += p.merchandise.name + ' (' + p.count + ') ' ;
               }
            }
        return null;
    }

    public Map<Id, DisplayMerchandise> getCart() {
        if(cart == null){
            cart = new Map<Id, DisplayMerchandise>{};
        }
        return cart;
    }

    public class DisplayMerchandise {
        public Merchandise__c merchandise{get; set;}
        public Decimal count{get; set;}
        
        public DisplayMerchandise(Merchandise__c item){
            this.merchandise = item;
        }
    }

    public List<DisplayMerchandise> getProducts() {
        if (products == null){
            products = new List<DisplayMerchandise>{};
            for (Merchandise__c item :
            [SELECT id, name, description__c, price__c
            FROM Merchandise__c
            WHERE Total_Inventory__c > 0]) {
            products.add(new DisplayMerchandise(item));
            }
        }
        return products;
    }
}
Tyler HarrisTyler Harris
It's now saying on Line: 9 Variable does not exist:count
JayantJayant
Sorry, this should be - 

cart.get(c.Id).count = cart.get(c.Id).count + c.count;

instead of

cart.get(c.Id).count = count++;
 
JayantJayant
Did that work ?
If it does, please do select the best answer (the one you think helped you the most) and mark the question as resolved.
Tyler HarrisTyler Harris
Hi Jayant,

It's now showing a "Variable does not exist:Id" Error on line 9.
JayantJayant
Sorry, blunder from my end :)

cart.get(c.Id).count should be cart.get(c.merchandise.Id).count.
Tyler HarrisTyler Harris
No worries Jayant! I'm very greatful and this is helping me learn immesely! Now I'm getting an error on my visualforce page saying Unknown Property 'String.Merchandise'

 
<apex:page standardStylesheets="false" showHeader="false" sidebar="false" controller="StoreFront2">
  <apex:stylesheet value="{!URLFOR($Resource.styles)}"/>
  <h1>Store Front</h1>
  
  <apex:form >
      <apex:dataTable value="{!products}" var="pitem" rowClasses="odd,even">
          
          <apex:column headerValue="Product">
              <apex:outputText value="{!pitem.merchandise.name}" />
          </apex:column>
          <apex:column headervalue="Price">
              <apex:outputText value="{!pitem.merchandise.Price__c}" />
          </apex:column>
          <apex:column headerValue="#Items">
              <apex:inputText value="{!pitem.count}"/>
          </apex:column>
   
      </apex:dataTable>
      
      <br/>
      <apex:commandButton action="{!shop}" value="Add to Cart" reRender="msg,cart" />
  </apex:form>
  
    <apex:outputPanel id="msg">{!message}</apex:outputPanel><br/>    
    <h1>Your Basket</h1>
<form>    
     <apex:dataTable id="cart" value="{!cart}" var="carti" rowClasses="odd,even">
          
          <apex:column headerValue="Product">
              <apex:outputText value="{!carti.merchandise.name}" />
          </apex:column>
          <apex:column headervalue="Price">
              <apex:outputText value="{!carti.merchandise.Price__c}" />
          </apex:column>
          <apex:column headerValue="#Items">
              <apex:outputText value="{!carti.count}"/>
          </apex:column>
   
      </apex:dataTable>
    </form>
    
  
</apex:page>

 
JayantJayant
Now Cart is a Map instead of a List, so we must first obtain the value (of DisplayMerchandise type) from the Key-Value pair in Map. Id is treated as a String at most places, so the error says String instead of Id (type of key in our map).

If I have not already forgotten dealing with Maps on VF, probably following snippet should work - 

<apex:dataTable id="cart" value="{!cart}" var="carti" rowClasses="odd,even">
    <apex:column headerValue="Product">
        <apex:outputText value="{!cart[carti].merchandise.name}" />
    </apex:column>
    <apex:column headervalue="Price">
        <apex:outputText value="{!cart[carti].merchandise.Price__c}" />
    </apex:column>
    <apex:column headerValue="#Items">
        <apex:outputText value="{!cart[carti].count}"/>
    </apex:column>
</apex:dataTable>

Let me know if it doesn't and I have a work-around (but that requires tweaking the controller as well a bit).

 
Tyler HarrisTyler Harris
Hi Jayant,

It's now throwing a "Expression of type Text cannot be subscripted"
Tyler HarrisTyler Harris
Sorry, I found the issue and fixed it, but now I'm getting a syntax error Extra "/>
Tyler HarrisTyler Harris
Apologies, thought I fixed it, but it's still showing "Expression of type Text cannot be subscripted"
JayantJayant
Can you please paste your latest VF Mark-Up here ?
Tyler HarrisTyler Harris
<apex:page standardStylesheets="false" showHeader="false" sidebar="false" controller="StoreFront2">
  <apex:stylesheet value="{!URLFOR($Resource.styles)}"/>
  <h1>Store Front</h1>
  
  <apex:form >
      <apex:dataTable value="{!products}" var="pitem" rowClasses="odd,even">
          
          <apex:column headerValue="Product">
              <apex:outputText value="{!pitem.merchandise.name}" />
          </apex:column>
          <apex:column headervalue="Price">
              <apex:outputText value="{!pitem.merchandise.Price__c}" />
          </apex:column>
          <apex:column headerValue="#Items">
              <apex:inputText value="{!pitem.count}"/>
          </apex:column>
   
      </apex:dataTable>
      
      <br/>
      <apex:commandButton action="{!shop}" value="Add to Cart" reRender="msg,cart" />
  </apex:form>
  
    <apex:outputPanel id="msg">{!message}</apex:outputPanel><br/>    
    <h1>Your Basket</h1>
<form>    
     <apex:dataTable id="cart" value="{!cart}" var="carti" rowClasses="odd,even">
          
          <apex:column headerValue='Product'>
              <apex:outputText value="{!carti[carti].merchandise.name}" />
          </apex:column>
          <apex:column headervalue='Price'>
              <apex:outputText value="{!carti[carti].merchandise.price__c}" />
          </apex:column>
          <apex:column headerValue='#Items'>
              <apex:outputText value="{!carti[carti].count}"/>
          </apex:column>
   
      </apex:dataTable>
    </form>
    
  
</apex:page>
JayantJayant

You are using {!carti[carti].count} instead of {!cart[carti].count}. Correct it and it should be fixed.

It should be -  { ! c a r t [ c a r t i ] . c o u n t } without the spaces.

You may also copy the mark-up I had pasted earlier.
This was selected as the best answer
Tyler HarrisTyler Harris
Thank you! An error on my part. It's working very well now. However, when I click "Add to cart" on my visualforce page and try to add additional values it's not totally correctly. It will add "1" correctly to the basket, but when I type in 2 for example it will total to 4? Do you what in my code maybe causing this?
Tyler HarrisTyler Harris
Thank you Jayant. I appreciate all your help. I've learned a lot from your assitance. I'll try to solve the rest on my own.
JayantJayant
Cool. Good Luck & Happy Programming !!!