You need to sign in to do that
Don't have an account?
Manuel Casas
Lightning Components Basics - Connect to Salesforce with Server-Side Controllers
Hi everyone!
I have a problem with the challenge, my App work fine but I don´t pass the challenge. This is my code:
campingList.cmp:
campingListController.js:
Challenge Not yet complete... here's what's wrong:
The campingList JavaScript helper isn't saving the new record to the database or adding it to the 'items' value provider.
My App save the new record into the database and add it to the "items" list.
Thanks for your answers!
I have a problem with the challenge, my App work fine but I don´t pass the challenge. This is my code:
campingList.cmp:
<aura:component controller="CampingListController"> <ltng:require styles="/resource/SLDS105/assets/styles/salesforce-lightning-design-system-ltng.css"/> <aura:handler name="init" action="{!c.doInit}" value="{!this}"/> <aura:attribute name="newItem" type="Camping_Item__c" default="{ 'sobjectType': 'Camping_Item__c', 'Price__c': 0, 'Quantity__c': 0}"/> <div class="slds-card slds-p-top--medium"> <ui:inputText aura:id="campname" label="Camping Name" value="{!v.newItem.Name}" required="true"/> <ui:inputCheckbox aura:id="packed" label="Packed?" value="{!v.newItem.Packed__c}"/> <ui:inputCurrency aura:id="price" label="Price" value="{!v.newItem.Price__c}" required="true"/> <ui:inputNumber aura:id="quantity" label="Quantity" value="{!v.newItem.Quantity__c}" required="true"/> <ui:button label="Create Camping" press="{!c.clickCreateCamping}"/> </div> <aura:attribute name="items" type="Camping_Item__c[]"/> <div class="slds-card slds-p-top--medium"> <header class="slds-card__header"> <h3 class="slds-text-heading--small">Campings</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> </aura:component>
campingListController.js:
({ // Load expenses from Salesforce doInit: function(component, event, helper) { // Create the action var action = component.get("c.getItems"); // Add callback behavior for when response is received action.setCallback(this, function(response) { var state = response.getState(); if (component.isValid() && state === "SUCCESS") { component.set("v.items", response.getReturnValue()); } else { console.log("Failed with state: " + state); } }); // Send action off to be executed $A.enqueueAction(action); }, clickCreateCamping: function(component, event, helper) { if(helper.validateCampingForm(component)){ // Create the new expense var newCamping = component.get("v.newItem"); helper.createItem(component, newCamping); } } })campingListHelper.js
({ createItem: function(component, camping) { var action = component.get("c.saveItem"); action.setParams({ "item": camping }); 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); }, validateCampingForm: function(component) { var validQuantity = true; var validPrice = true; var nameField = component.find("campname"); var campname = nameField.get("v.value"); var quantityField = component.find("quantity"); var quantity = quantityField.get("v.value"); var priceField = component.find("price"); var price = priceField.get("v.value"); if ($A.util.isEmpty(campname) || $A.util.isEmpty(quantity) || $A.util.isEmpty(price)){ validQuantity = false; validPrice = false; nameField.set("v.errors", [{message:"Camping name, quantity or price can't be blank."}]); } else { nameField.set("v.errors", null); } return(validQuantity && validPrice); } })CampingListController.apxc:
public with sharing class CampingListController { @AuraEnabled public static List<Camping_Item__c> getItems() { // Check to make sure all fields are accessible to this user String[] fieldsToCheck = new String[] { 'Id', 'Name', 'Packed__c', 'Price__c', 'Quantity__c' }; Map<String,Schema.SObjectField> fieldDescribeTokens = Schema.SObjectType.Camping_Item__c.fields.getMap(); for(String field : fieldsToCheck) { if( ! fieldDescribeTokens.get(field).getDescribe().isAccessible()) { throw new System.NoAccessException(); return null; } } // Perform isAccessible() checking first, then return [SELECT Id, Name, Packed__c, Price__c, Quantity__c FROM Camping_Item__c]; } @AuraEnabled public static Camping_Item__c saveItem(Camping_Item__c item) { // Perform isUpdatable() checking first, then upsert item; return item; } }I am still getting this error:
Challenge Not yet complete... here's what's wrong:
The campingList JavaScript helper isn't saving the new record to the database or adding it to the 'items' value provider.
My App save the new record into the database and add it to the "items" list.
Thanks for your answers!
Jeff Douglas
Trailhead Developer Advocate
All Answers
Jeff Douglas
Trailhead Developer Advocate
Jeff Douglas
Trailhead Developer Advocate
thank you for code but it is not saving records through web form while i try to save them.
I also ran into this problem and read what challenge asks us to do line by line.
Trailhead challenge do not ask us to call HELPER method from campingListController.js. It just tells us to perform save action in campingListcontroller.js method instead. This is not very intuitive as trailhead module performs saving operation in HELPER method.
Just copy and past the code from campingListHelper.js to campingListController.js to pass the challenge. This is weird but this is how it is.
I hope this would help others.
Thanks,
Akshay
In case anyone wonders, using a namespaced dev org (which entails having to add the namespace plus two underscores to every custom field name in the Camping_Item__c object in the code), does not seem to be a problem. I implemented the code for the challenge with some apprehension since I expected the namespace to break it, but it didn't.
This is the proper validateCampingForm, you are setting the "errors" on the nameField not the respective fields that are errored and having two booleans to track valid in your function is redundant
Hi Everyone,
Codes below works perfecly fine.
campingListController.js
campingList.cmp
campingListHelper.js
CampingListController.apxc
campingListController.js
CampingListController.apxc
CampingListHelper.js
Can you guys help me out!!! please@!!
Why is there no official place showing the solution.
I did the challenge following the structure in the module and it worked but failed the challenge.
I moved stuff around and it failedto work but passed the challenge.
I decided to retry and now it doesn't work and all the threads are unsatisfactory.
This is dis-heartening.
I hear so many good things about trailhead but my experience is not a happy one.
...back to the drawing board.
See https://developer.salesforce.com/forums/?id=9060G000000XeVtQAK
This page has an error. You might just need to refresh it. Component class instance initialization error [Cannot read property 'apply' of undefined] Failing descriptor: {markup://c:camping}
Any ideas.
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':false}"/>
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<!-- NEW Campaing FORM -->
<div class="slds-col slds-col--padded slds-p-top--large">
<!-- [[ Campaing form goes here ]] -->
<div aria-labelledby="newCampaingForm">
<!-- BOXED AREA -->
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newCampaingForm" class="slds-text-heading--small
slds-p-vertical--medium">
Add Expense
</legend>
<!-- CREATE NEW Campaing FORM -->
<form class="slds-form--stacked">
<div class="slds-form-element slds-is-required">
<div class="slds-form-element__control">
<ui:inputText aura:id="campingName" label="Camping 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 Expense"
class="slds-button slds-button--brand"
press="{!c.createCampingList}"/>
</div>
</form>
<!-- / CREATE NEW EXPENSE FORM -->
</fieldset>
<!-- / BOXED AREA -->
</div>
<!-- / CREATE NEW EXPENSE -->
</div>
<!-- ITERATIING ITEM LISTS -->
<div class="slds-card slds-p-top--medium">
<!-- PAGE HEADER -->
<div class="slds-page-header" role="banner">
<div class="slds-grid">
<div class="slds-col">
<h1 class="slds-text-heading--medium">Camping List</h1>
</div>
</div>
</div>
<!-- / PAGE 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>
<!-- / ITERATIING ITEM LISTS -->
</aura:component>
campingListController.js
({
// Load expenses from Salesforce
doInit: function(component, event, helper) {
// Create the action
var action = component.get("c.getItems");
// Add callback behavior for when response is received
action.setCallback(this, function(response) {
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
component.set("v.items", response.getReturnValue());
}
else {
console.log("Failed with state: " + state);
}
});
// Send action off to be executed
$A.enqueueAction(action);
},
createCampingList : function(component, event, helper) {
if(helper.validateCampingForm(component)){
// Create the new expense
var newCampingItem = component.get("v.newItem");
helper.createItem(component,newCampingItem);
}
/*
if(isCampingValid){
var newCampingItem = component.get("v.newItem");
//helper.createCamping(component,newCampingItem);
var campings = component.get("v.items");
var item = JSON.parse(JSON.stringify(newCampingItem));
campings.push(item);
component.set("v.items",campings);
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false });
}
*/
}
})
campingListHelper
({
createItem : function(component, camping) {
var action = component.get("c.saveItem");
action.setParams({
"item": camping
});
action.setCallback(this, function(response){
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
console.log('State== Success');
var campings = component.get("v.items");
campings.push(response.getReturnValue());
component.set("v.items", campings);
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false });
}
});
$A.enqueueAction(action);
},
validateCampingForm: function(component) {
//Error Checking
var isCampingValid = true;
var nameField = component.find("campingName");
var quantityField = component.find("quantity");
var priceField = component.find("price");
//Name should not be blank
if(nameField.get("v.value") == '' ){
nameField.set("v.errors",[{message:"Name can't be blank"}]);
isCampingValid = false;
}
else{
nameField.set("v.errors",null);
}
//Quantity should not be blank
if( quantityField.get("v.value") == '' ){
quantityField.set("v.errors",[{message:"Quantity can't be blank"}]);
isCampingValid = false;
}
else{
quantityField.set("v.errors",null);
}
//Price Shoud not be blank
if(priceField.get("v.value") == ''){
priceField.set("v.errors",[{message:"Price can't be blank"}]);
isCampingValid = false;
}
else{
priceField.set("v.errors",null);
}
return(isCampingValid);
},
})
CampingListController.apxc
public with sharing class CampingListController {
@AuraEnabled
public static List<Camping_Item__c> getItems() {
// Check to make sure all fields are accessible to this user
String[] fieldsToCheck = new String[] {
'Id', 'Name', 'Price__c', 'Quantity__c', 'Packed__c'
};
Map<String,Schema.SObjectField> fieldDescribeTokens =
Schema.SObjectType.Camping_Item__c.fields.getMap();
for(String field : fieldsToCheck) {
if( ! fieldDescribeTokens.get(field).getDescribe().isAccessible()) {
throw new System.NoAccessException();
return null;
}
}
// OK, they're cool, let 'em through
return [SELECT Id, Name, Price__c, Quantity__c, Packed__c FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem (Camping_Item__c item) {
upsert item;
return item;
}
}
campingListItem.cmp
<aura:component implements="force:appHostable">
<aura:attribute name="item" type="Camping_Item__c" />
<p>Name :
<ui:outputText value="{!v.item.Name}"/>
</p>
<p>Quantity :
<ui:outputNumber value="{!v.item.Quantity__c}" />
</p>
<p>Price :
<ui:outputCurrency value="{!v.item.Price__c}"/>
</p>
<p>Packed? :
<ui:outputCheckbox value="{!v.item.Packed__c}"/>
</p>
</aura:component>
Challenge Not yet complete... here's what's wrong:
The Apex controller CampingListController doesn't have a 'getItems()' or 'saveItem(Camping_Item__c item)' method.
http://faizanaz90.blogspot.com/2017/11/lightning-components-basics-connect-to.html
CampingListForm
<aura:component >
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<aura:attribute name="newItem" type="Camping_Item__c"
default="{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 1,
'Price__c': 0,
'Packed__c': false }"/>
<!-- CREATE NEW ITEM FORM -->
<form class="slsd-form--stacked">
<lightning:input aura:id="campingform" label="Camping Name"
name="campingname"
value="{!v.newItem.Name}"
required="true"/>
<lightning:input type="number" aura:id="campingform" label="Quantity"
name="campingQuantity"
min="1"
step="1"
value="{!v.newItem.Quantity__c}"
messageWhenRangeUnderflow="Enter an Quantity that's at least 1."/>
<lightning:input type="number" aura:id="campingform" label="Price"
name="campingPrice"
min="0.1"
formatter="currency"
step="0.1"
value="{!v.newItem.Price__c}"
messageWhenRangeUnderflow="Enter an Price that's at least 0.1."/>
<lightning:input type="checkbox" aura:id="campingform" label="Packed ?"
name="campingPacked"
checked="{!v.newItem.Packed__c}"/>
<lightning:button label="Create Camping"
class="slds-m-top--medium"
variant="brand"
onclick="{!c.clickCreateItem}"/>
</form>
<!-- / CREATE NEW ITEM FORM -->
</aura:component>
https://developer.salesforce.com/forums/?id=906F0000000kEd9IAE
Connect to Salesforce with Server-Side Controllers
Step 1:- campingList.cmp
Step 2:- campingListController.js Step 3:-Apex class
Step 4:--CampingListHelper
Step 5:-Add event name as :- addItemEvent.evt
Step 6:- Add Helpper for CampingListFormHelper.js
Step 7:- Add new component name as:- campingListItem.cmp Step 8: Add controller campingListController.js Add new Component CampingListForm.cmp
Add ListFormController.js
Enjoy and finish if you have any question please let me know..
Don't forgot to like.....
Error message as below:-
Challenge Not yet complete... here's what's wrong:
The campingList JavaScript controller isn't calling 'saveItem' in the Apex class to save the record or setting the 'item' as a parameter for the 'saveItem' action.
<aura:component controller="CampingListController" implements="force:appHostable,flexipage:availableForAllPageTypes" access="global" >
<aura:attribute name="items" type="Camping_Item__c[]" />
<aura:attribute name="newItem" type="Camping_Item__c" default="{'Price__c': 0, 'Packed__c': false, 'Quantity__c': 0, 'Name':'Test', 'sobjectType': 'Camping_Item__c'}" />
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<lightning:layout>
<lightning:layoutItem padding="around-small" size="4">
<!-- CREATE NEW EXPENSE -->
<div aria-labelledby="newCampingItem">
<!-- BOXED AREA -->
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newCampingItem" class="slds-text-heading--small
slds-p-vertical--medium">
Add Camping Item
</legend>
<!-- CREATE NEW EXPENSE FORM -->
<form class="slds-form--stacked">
<lightning:input aura:id="campingItemForm" label="Name"
name="itemName"
value="{!v.newItem.Name}"
required="true"/>
<lightning:input type="number" aura:id="campingItemForm" label="Quantity"
name="itemQuantity"
min="1"
step="1"
value="{!v.newItem.Quantity__c}"
messageWhenRangeUnderflow="Enter the quantity atleast 1"/>
<lightning:input type="number" aura:id="campingItemForm" label="Price"
name="itemPrice"
min="0.1"
formatter="currency"
step="0.01"
value="{!v.newItem.Price__c}" />
<lightning:input type="checkbox" aura:id="campingItemForm" label="Packed ?"
name="itemPacked"
checked="{!v.newItem.Packed__c}"/>
<lightning:button label="Create Item"
class="slds-m-top--medium"
variant="brand"
onclick="{!c.clickCreateItem }"/>
</form>
<!-- / CREATE NEW EXPENSE FORM -->
</fieldset>
<!-- / BOXED AREA -->
</div>
<!-- / CREATE NEW EXPENSE -->
</lightning:layoutItem>
<lightning:layoutItem padding="around-small" size="3">
<aura:Iteration items="{!v.items}" var="item">
<c:campingListItem item="{!item}" />
</aura:Iteration>
</lightning:layoutItem>
</lightning:layout>
<!--
<ol>
<li>Bug Spray</li>
<li>Bear Repellant</li>
<li>Goat Food</li>
</ol>
-->
</aura:component>
CampingListcontroller.js: (Controller)
({
clickCreateItem : function(component, event, helper) {
var isFormValid = component.find("campingItemForm").reduce(function(isValid, inputCmp){
inputCmp.showHelpMessageIfInvalid();
return isValid && inputCmp.get("v.validity").valid;
});
if (isFormValid) {
var newCampingItem = component.get("v.newItem");
helper.createItem(component,newCampingItem);
}
},
doInit : function (component, event, helper) {
var action = component.get("c.getItems");
action.setCallback(this,function (response) {
var campingItems = response.getReturnValue();
component.set("v.items",campingItems);
});
$A.enqueueAction(action);
}
})
CampingListHelper.js (Helper):
({
createItem : function(component,newCampingItem) {
var action = component.get("c.saveItem");
action.setParams({
"campingItem" : newCampingItem
});
action.setCallback(this,function(response){
var state = response.getState();
if (state === "SUCCESS") {
var parsedCampingItem = JSON.parse(JSON.stringify(newCampingItem));
console.log(JSON.parse(JSON.stringify(parsedCampingItem)), JSON.stringify(parsedCampingItem));
var campingItems = JSON.parse(JSON.stringify(component.get("v.items")));
campingItems.push(parsedCampingItem);
component.set("v.items",campingItems);
component.set("v.newItem", {'Price__c': 0, 'Packed__c': false, 'Quantity__c': 0, 'Name':'', 'sobjectType': 'Camping_Item__c'})
}
});
$A.enqueueAction(action);
}
})
APEX CLASS:
CampingListController.apxc
public with sharing class CampingListController {
/**
* This method will insert the camping item record
*
*/
@AuraEnabled
public static void saveItem (Camping_Item__c campingItem) {
//insert the campingItem record
insert campingItem;
}
/**
* This method fetches the Camping_Item__c records and return as list
*/
@AuraEnabled
public static List<Camping_Item__c> getItems() {
//fetch the active records using soql query
List<Camping_Item__c> campingItems = [SELECT Id,Name,Price__c,Packed__c,Quantity__c FROM Camping_Item__c];
//return the list of camping items
return campingItems;
}
}