function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Ryan Adams 173Ryan Adams 173 

Save and Load Records with a Server-Side Controller continued difficulty

Sir,

I am experiencing great difficulty with the following Trailhead module:

Lightning Components Basics, Connect to Salesforce with Server-Side Controllers

located at:  https://trailhead.salesforce.com/modules/lex_dev_lc_basics/units/lex_dev_lc_basics_server

*****************************************************************************************************************************

Here is my code:

(campingList.cmp)

<aura:component >
   
 <aura:attribute name="items" type="Camping_Item__c[]"/>
    <aura:attribute name="newItem" type="Camping_Item__c"
                    default="{'sobjectType' : 'Camping_Item__c',
                               'Quantity__c' : 0,
                               'Price__c' : 0}"/>
  <!-- BOXED AREA -->
  <fieldset class="slds-box slds-theme--default slds-container--small">
    <legend id="newCampItemForm" class="slds-text-heading--small
      slds-p-vertical--medium">
      Add Camping Item
    </legend>
    <!-- CREATE NEW CAMPING ITEM FORM -->
    <form class="slds-form--stacked">
      <div class="slds-form-element slds-is-required">
          <div class="slds-form-element__control">
              <ui:inputText aura:id="campItemName" label="Camping Item Name"
                  class="slds-input"
                  labelClass="slds-form-element__label"
                  value="{!v.newItem.Name}"
                  required="true"/>
          </div>
     </div>
     <div class="slds-form-element slds-is-required">
          <div class="slds-form-element__control">
              <ui:inputNumber aura:id="quantity" label="Quantity"
                  class="slds-input"
                  labelClass="slds-form-element__label"
                  value="{!v.newItem.Quantity__c}"
                  required="true"/>
          </div>
      </div>
      <div class="slds-form-element">
          <div class="slds-form-element__control">
              <ui:inputCurrency aura:id="price" label="Price"
                  class="slds-input"
                  labelClass="slds-form-element__label"
                  value="{!v.newItem.Price__c}"/>
          </div>
      </div>
      <div class="slds-form-element">
          <ui:inputCheckbox aura:id="packed" label="Packed?"
              class="slds-checkbox"
              labelClass="slds-form-element__label"
              value="{!v.newItem.Packed__c}"/>
      </div>
      <div class="slds-form-element">
          <ui:button label="Create Camping Item"
              class="slds-button slds-button--brand"
              press="{!c.clickCreateItem}"/>
      </div>
    </form>
    <!-- / CREATE NEW CAMPING ITEM FORM -->
  </fieldset>
        <div class ="slds-card slds-p-top--meduim">
        <header class ="slds-card__header">
            <h3 class = "slds-text-heading--small">Items</h3>
        </header>
        <section class ="slds-card__body">
         <div id="list" class = "row">
             <aura:iteration items="{!v.items}" var="item">
                    <c:campingListItem item="{!item}"/>
                </aura:iteration>
            </div>
        </section>
    </div>
    <!-- i do not think this html is needed any longer
 <ol> 
        <li>Bug Spray</li>
        <li>Bear Repellant</li>
        <li>Goat Food</li>
    </ol>-->
</aura:component>


(campingListController.js)

({
 
    doInit  : function(component, event, helper) {
  var action = component.get("c.getItems");
        action.setCallback(this, function(response){
            var state = response.getState();
          
            if (component.isValid() && state === "SUCCESS") {
          
              
                component.set("v.items", response.getReturnValue());
                
            }
        });
       
        $A.enqueueAction(action);
 },
   
    CreateCamping : function(component, event, helper){
       
        helper.validateFields (component,component.find("name"));
        helper.validateFields (component,component.find("Price"));
        helper.validateFields (component,component.find("Quantity"));
        if(component.get("v.er") === false)
        {    
&nbsp;           //Here I removed the lines and shifted the code to the helperJs      
            console.log('Before:'+Items);           
            helper.CreateCampaign(component,Item);            
             console.log('After:'+Items);                   
        }
 }   
})


(campingListHelper.js)

({
 
    validateFields : function (component,field) {
       
        var nameField = field;
        console.log('yes:'+nameField);
        var expname = nameField.get("v.value");
        if ($A.util.isEmpty(expname)){
           component.set("v.er",true);
           nameField.set("v.errors", [{message:"this field can't be blank."}]);
        }
        else {
            nameField.set("v.errors", null);
        }
    },
   
    CreateCampaign : function (component,Item){
     
        var action = component.get("c.saveItem");
        action.setParams({"CampingItem":Item});
        action.setCallback(this,function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                console.log('save');
            }
        });
        $A.enqueueAction(action); 
//Below lines are shifted from controller Js to helperJs
        var Items = component.get("v.items");
&nbsp;       var Item = component.get("v.newItem");
&nbsp;       Items.push(Item);   
        component.set("v.items",Items);
        component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
                'Name': '',
                'Quantity__c': 0,
                'Price__c': 0,
                'Packed__c': false });
    }
})

*****************************************************************************************************************************

When I do the Check Challenge, I receive the following error:

Challenge Not yet complete... here's what's wrong:
The Apex controller 'CampingListController' does not exist.

The only thing that I can find in the Forum help documentation is that my code has a campingListController.js and a campingListHelper.js, others have a .js file named camperList.js

Please advise.

Ryan
 
Best Answer chosen by Ryan Adams 173
LBKLBK
This is the code that worked for me.

APEX Controller
public class CampingListController {
    @auraenabled
    public static List<Camping_Item__c> getItems (){
        List<Camping_Item__c> CI = [select id, name,price__c,Quantity__c,Packed__c from Camping_Item__c ];
        return CI;
    }
    @auraenabled
    public static Camping_Item__c saveItem (Camping_Item__c item){
        insert item;
        return item;
    }
}
campingList.cmp
<aura:component controller="CampingListController">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
	<aura:attribute name="items" type="Camping_Item__c[]"/>
    <aura:attribute name="er" type="boolean" default="false"/>
    <aura:attribute name="newItem" type="Camping_Item__c"    default="{ 'sobjectType': 'Camping_Item__c',
                         'Name': '',
                         'Price__c': 0,
                         'Quantity__c': 0,                         
                         'Packed__c': false
                       }"/>
    <ui:inputText value="{!v.newItem.Name}" aura:id="name" label="name"/>
    <ui:inputCheckbox value="{!v.newItem.Packed__c}" aura:id="Packed" label="Packed"/>
    <ui:inputCurrency value="{!v.newItem.Price__c}"  aura:id="Price" label="Price"/>
    <ui:inputNumber value="{!v.newItem.Quantity__c}" aura:id="Quantity" label="Quantity"/>
    <ui:button label="Create Camping" press="{!c.createItem}" aura:id="button"/>
    <br/>
	<aura:iteration items="{!v.items}" var="PerItem">
        
        <c:campingListItem item="{!PerItem}" />
    </aura:iteration>
</aura:component>
campingListController.js
({
	
    doInit  : function(component, event, helper) {
		var action = component.get("c.getItems");
        action.setCallback(this, function(response){
            var state = response.getState();
           
            if (component.isValid() && state === "SUCCESS") {
           
               
                component.set("v.items", response.getReturnValue());
                 
            }
        });
        
        $A.enqueueAction(action);
	},
    
    createItem : function(component, event, helper){
        
        helper.validateFields (component,component.find("name"));
        helper.validateFields (component,component.find("Price"));
        helper.validateFields (component,component.find("Quantity"));
        if(component.get("v.er") === false)
        {     
            var Item = component.get("v.newItem");            
            helper.createItem (component,Item);             
                       
        }
	}    
})
campingListHelper.js
({
	
    validateFields : function (component,field) {
        
        var nameField = field;
        console.log('yes:'+nameField);
        var expname = nameField.get("v.value"); 
        if ($A.util.isEmpty(expname)){
           component.set("v.er",true);
           nameField.set("v.errors", [{message:"this field can't be blank."}]);
        }
        else {
            nameField.set("v.errors", null);
        }
    },
    
    createItem : function (component,Item){         
        var action = component.get("c.saveItem");
        action.setParams({"item":Item});
        action.setCallback(this,function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                var campings = component.get("v.items");
                campings.push(response.getReturnValue());
                component.set("v.items", campings);
            }
        });
       $A.enqueueAction(action);        
    }
})



 

All Answers

LBKLBK
I don't see the controller reference in your AURA component.

Isn't the first line supposed to be like..
 
<aura:component controller="CampingListController">
?

Try that. If it doesn't work, I will share the code that worked for me.
 
Ryan Adams 173Ryan Adams 173
Hi, I tried to add the line you suggested into my campingList.cmp and upon attempting to save it I received an error message in the Developer Console titled FIELD_INTEGRITY_EXCEPTION with the following notation: "Failed to save undefined: markup://c:campingList:2,56: Invalid attribute "controller": Source" Did you notice above what I said about the campingList.js code? Thanks, Ryan
Pedro Muller LopesPedro Muller Lopes
Hi, I am also getting an error, but a bit differen...

Challenge Not yet complete... here's what's wrong: 
The campingList JavaScript controller isn't calling the helper's 'createItem' function.


CampingListController.apxc
 
public class CampingListController {
@auraenabled
    public static List<Camping_Item__c> getItems (){
        List<Camping_Item__c> CI = [select id, name,price__c,Quantity__c,Packed__c from Camping_Item__c ];
        return CI;
    }
    @auraenabled
    public static Camping_Item__c saveItem (Camping_Item__c CampingItem){
        insert campingItem;
        return campingItem;
    }
}

CampingList.cmp
 
<aura:component controller="CampingListController">
    <aura:handler name = "init" value="{!this}" action = "{!c.doInit}"/>
	<aura:attribute name="items" type="Camping_Item__c[]"/>
    <aura:attribute name="er" type="boolean" default="false"/>
    <aura:attribute name="newItem" type="Camping_Item__c"    default="{ 'sobjectType': 'Camping_Item__c',
                         'Name': '',
                         'Price__c': 0,
                         'Quantity__c': 0,                         
                         'Packed__c': false
                       }"/>
    <ui:inputText value="{!v.newItem.Name}" aura:id="name" label="name"/>
    <ui:inputCheckbox value="{!v.newItem.Packed__c}" aura:id="Packed" label="Packed"/>
    <ui:inputCurrency value="{!v.newItem.Price__c}"  aura:id="Price" label="Price"/>
    <ui:inputNumber value="{!v.newItem.Quantity__c}" aura:id="Quantity" label="Quantity"/>
    <ui:button label="Create Expense" press="{!c.CreateCamping}" aura:id="button"/>
    <br/>
	<aura:iteration items="{!v.items}" var="PerItem">
        
        <c:campingListItem item="{!PerItem}" />
    </aura:iteration>
</aura:component>

CampingListController.js
 
({
	 doInit  : function(component, event, helper) {
		var action = component.get("c.getItems");
        action.setCallback(this, function(response){
            var state = response.getState();
           
            if (component.isValid() && state === "SUCCESS") {
           
               
                component.set("v.items", response.getReturnValue());
                 
            }
        });
        
        $A.enqueueAction(action);
	},
    
    CreateCamping : function(component, event, helper){
        
        helper.validateFields (component,component.find("name"));
        helper.validateFields (component,component.find("Price"));
        helper.validateFields (component,component.find("Quantity"));
        if(component.get("v.er") === false)
        {     
                 
            console.log('Before:'+Items);            
            helper.CreateCampaign(component,Item);             
             console.log('After:'+Items);                    
        }
	}    
})

CampingListHelper.js
 
({
	validateFields : function (component,field) {
        
        var nameField = field;
        console.log('yes:'+nameField);
        var expname = nameField.get("v.value"); 
        if ($A.util.isEmpty(expname)){
           component.set("v.er",true);
           nameField.set("v.errors", [{message:"this field can't be blank."}]);
        }
        else {
            nameField.set("v.errors", null);
        }
    },
    
    CreateCampaign : function (component,Item){ 
		    
        var action = component.get("c.saveItem");
        action.setParams({"CampingItem":Item});
        action.setCallback(this,function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                console.log('save');
            }
        });
        $A.enqueueAction(action);  
        var Items = component.get("v.items"); 
        var Item = component.get("v.newItem"); 
        Items.push(Item);    
        component.set("v.items",Items); 
        component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
                'Name': '',
                'Quantity__c': 0,
                'Price__c': 0,
                'Packed__c': false });
    }
})

What am I missing?


 
LBKLBK
This is the code that worked for me.

APEX Controller
public class CampingListController {
    @auraenabled
    public static List<Camping_Item__c> getItems (){
        List<Camping_Item__c> CI = [select id, name,price__c,Quantity__c,Packed__c from Camping_Item__c ];
        return CI;
    }
    @auraenabled
    public static Camping_Item__c saveItem (Camping_Item__c item){
        insert item;
        return item;
    }
}
campingList.cmp
<aura:component controller="CampingListController">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
	<aura:attribute name="items" type="Camping_Item__c[]"/>
    <aura:attribute name="er" type="boolean" default="false"/>
    <aura:attribute name="newItem" type="Camping_Item__c"    default="{ 'sobjectType': 'Camping_Item__c',
                         'Name': '',
                         'Price__c': 0,
                         'Quantity__c': 0,                         
                         'Packed__c': false
                       }"/>
    <ui:inputText value="{!v.newItem.Name}" aura:id="name" label="name"/>
    <ui:inputCheckbox value="{!v.newItem.Packed__c}" aura:id="Packed" label="Packed"/>
    <ui:inputCurrency value="{!v.newItem.Price__c}"  aura:id="Price" label="Price"/>
    <ui:inputNumber value="{!v.newItem.Quantity__c}" aura:id="Quantity" label="Quantity"/>
    <ui:button label="Create Camping" press="{!c.createItem}" aura:id="button"/>
    <br/>
	<aura:iteration items="{!v.items}" var="PerItem">
        
        <c:campingListItem item="{!PerItem}" />
    </aura:iteration>
</aura:component>
campingListController.js
({
	
    doInit  : function(component, event, helper) {
		var action = component.get("c.getItems");
        action.setCallback(this, function(response){
            var state = response.getState();
           
            if (component.isValid() && state === "SUCCESS") {
           
               
                component.set("v.items", response.getReturnValue());
                 
            }
        });
        
        $A.enqueueAction(action);
	},
    
    createItem : function(component, event, helper){
        
        helper.validateFields (component,component.find("name"));
        helper.validateFields (component,component.find("Price"));
        helper.validateFields (component,component.find("Quantity"));
        if(component.get("v.er") === false)
        {     
            var Item = component.get("v.newItem");            
            helper.createItem (component,Item);             
                       
        }
	}    
})
campingListHelper.js
({
	
    validateFields : function (component,field) {
        
        var nameField = field;
        console.log('yes:'+nameField);
        var expname = nameField.get("v.value"); 
        if ($A.util.isEmpty(expname)){
           component.set("v.er",true);
           nameField.set("v.errors", [{message:"this field can't be blank."}]);
        }
        else {
            nameField.set("v.errors", null);
        }
    },
    
    createItem : function (component,Item){         
        var action = component.get("c.saveItem");
        action.setParams({"item":Item});
        action.setCallback(this,function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {
                var campings = component.get("v.items");
                campings.push(response.getReturnValue());
                component.set("v.items", campings);
            }
        });
       $A.enqueueAction(action);        
    }
})



 
This was selected as the best answer
Ryan Adams 173Ryan Adams 173
LY Packaging, Thanks for your help. I finally realized after seeing your code that I had not yet created the APEX Controller which you showed as your first item. Thank you also for your patience with me. I have experienced a plethora of coding difficulties, so don't be surprised if you see me with additional questions. I hope you have the time and patience to assist again. Ryan
Amit singh DhakreAmit singh Dhakre
Hi all i am getting below error while completing this challenge.The campingList JavaScript helper doesn't appear to have the correct functionality. Ensure that it is saving the new record to the database and in the callback, pushing the new record to the array of existing items (e.g., v.items) and setting the modified array of items to the 'items' value provider to display the updated list.
Any Help in appriciated.
campingList.cmp

<aura:component controller="CampingListController" >
    <aura:attribute name="items" type="Camping_Item__c[]"/>
	<aura:attribute name="newItem" type="Camping_Item__c" default="{'sobjectType': 'Camping_Item__c','Price__c':0,Quantity__c:0}"/>
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>

    <c:campingHeader />
  <div aria-labelledby="newexpenseform">
   <fieldset class="slds-box slds-theme--default slds-container--small">
    <form  class="slds-form--stacked">
        <lightning:input name="Name" label="Name" value="{!v.newItem.Name}" />
        <lightning:input aura:id="clist" name="Quantity" value="{!v.newItem.Quantity__c}"
                            type="number" min="1" label="Quantity"/>
            <lightning:input aura:id="clist" name="Price" value="{!v.newItem.Price__c}"
                             type="number" formatter="currency" label="Price"/>
            <lightning:input aura:id="clist" name="Packed" value="{!v.newItem.Packed__c}" 
                             type="checkbox" label="Packed"/>
            
        <lightning:button label="create" onclick="{!c.clickCreateItem}" />
    </form>
   </fieldset>
    </div>
    <aura:iteration items="{!v.items}" var="v">
    	<c:campingListItem item="{!v}"/><br/>
 </aura:iteration>
</aura:component>
 
campingListController.js

({
    doInit: function(component, event, helper)
    {
        var action = component.get("c.getItems");
       
        action.setCallback(this,function(response)
                           {
                               var state =response.getState();
                               if(state ==="SUCCESS")
                               {
                                   component.set("v.items",response.getReturnValue());
                               }
                           })
         $A.enqueueAction(action);
        
    },	
    
	clickCreateItem: function(component, event, helper) {
		
        var validForm = component.find("clist").reduce(function(validSoFar, inputCmp){
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;},true);
        
        if(validForm)
        {
           var item = component.get("v.newItem");
            helper.createItem(component,item)
           
	}
}
})
 
campingListHelper.js

({
	createItem: function(component,item) {
		var action= component.get("c.saveItem");
            action.setParams({"item":item});
            
            action.setCallback(this,function(response)
                                             {
                                             var state=response.getState();
                               				if(state==="SUCCESS")
            								{
                                             var items =component.get("v.items");
                                              items.push(response.getReturnValue());
                                                compnent.set("v.items",items);
                                                component.set("v.newItem", 
                                                 {'Price__c': 0, 'Packed__c': false, 
                                                  'Quantity__c': 0, 'Name':'', 
                                                  'sobjectType': 'Camping_Item__c'})
                                            }
                                             });
        
        	$A.enqueueAction(action);
        }
	}
)
 
CampingListController.apxc

public class CampingListController {
@AuraEnabled
    public static list<camping_item__c> getItems()
    {
        return [select name,quantity__c,price__c from camping_item__c];
    }


@AuraEnabled
public static camping_item__c saveItem(Camping_Item__c item)
{
    upsert item;
    return item;
}
}


 
rohit jha 32rohit jha 32
Hi Amit,
Correct the spelling of component in line 15 of campingListHelper. 
I hope this will work for you.

 
Saket Ranjan 3Saket Ranjan 3
Thanks @LBK
iSaasforceiSaasforce
Best Answer
Yogesh MeltyYogesh Melty
CampingList.cmp
<aura:component controller="CampingListController">
    <aura:attribute name="items" type="Camping_Item__c[]"/>
    <aura:attribute name="newItem" type="Camping_Item__c"
         default="{ 'sobjectType': 'Camping_Item__c',
                        'Name': '',
                        'Quantity__c': 0,
                        'Price__c': 0,
                        'Packed__c': ''}"/>
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
    <div aria-labelledby="newcampingform">
        <fieldset class="slds-box slds-theme--default slds-container--small">
  
        <form class="slds-form--stacked">          
            <lightning:input aura:id="campingform" label="Name"
                             name="name"
                             value="{!v.newItem.Name}"
                             required="true"/> 
            <lightning:input type="number" aura:id="campingform" label="Quantity"
                             name="quantity"
                             min="1"
                             formatter="Number"
                             step="1"
                             value="{!v.newItem.Quantity__c}"
                             messageWhenRangeUnderflow="Enter a quantity that's at least 1."/>
            <lightning:input aura:id="campingform" label="Price"
                             name="price"
                             formatter="currency" 
                             value="{!v.newItem.Price__c}"
                             />
            <lightning:input type="checkbox" aura:id="campingform" label="Packed"  
                             name="packed"
                             checked="{!v.newItem.Packed__c}"/>
            <lightning:button label="Create Item" 
                              class="slds-m-top--medium"
                              variant="brand"
                              onclick="{!c.clickCreate}"/>
        </form>
      </fieldset>
    </div>
    <div>
    <aura:iteration items="{!v.items}" var="item">
        <c:campingListItem item="{!item}"/>
    </aura:iteration>
    </div>
</aura:component>


CampingListController.apxc
public class CampingListController 
{
    public static List<Camping_Item__c> getItems()
    {
        return[SELECT Name, Quantity__c, Price__c, Packed__c from Camping_Item__c];
    }
	public static Camping_Item__c saveItem(Camping_Item__c items)
    {
        upsert items;
        return items;
    }
}


CampingListController.js
({
    doInit : function(component, event, helper)
    {
        var action = component.get("c.getItems");
        action.setCallback(this, function(response)
        {
        	var state = response.getState();
        	if(state === "SUCCESS")
        	{
            	component.set("v.items",response.getReturnValue());
        	}
        	else
        	{
            	console.log("Failed with state : " +state);
        	}
        
        });
        $A.enqueueAction(action);
    },
    clickCreate: function(component, event, helper) {
        var validExpense = component.find('campingform').reduce(function (validSoFar, inputCmp) {
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        if(validExpense){
            var newItem = component.get("v.newItem");
            console.log("Create expense: " + JSON.stringify(newExpense));
            helper.createItem(component, newItem);
        }
    }
})


CampingListHelper.js
({
    createItem: function(component, items) {
        var action = component.get("c.saveItem");
        action.setParams({
            "items": items
        });
        action.setCallback(this, function(response){
            var state = response.getState();
            if (state === "SUCCESS") {
                var items = component.get("v.items");
                items.push(response.getReturnValue());
                component.set("v.items", items);
            }
        });
        $A.enqueueAction(action);
    },
})

 
kumari shivanikumari shivani
Getting this error:
The Apex controller CampingListController doesn't have a 'getItems()' or 'saveItem(Camping_Item__c item)' method.