The Trailhead challenge check is telling me the following:
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.
The app is really not working as expected, but I can not guess why is that.
Here is my code.
campingApp.app
:
<aura:application extends="force:slds">
<c:camping />
</aura:application>
camping.cmp
:
<aura:component controller="CampingListController">
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<aura:attribute name="items" type="Camping_Item__c[]" default="[]"/>
<aura:attribute name="item" type="Camping_Item__c" default="{
'sobjectType': 'Camping_Item__c',
'campingItemName': 'campingItemNameDefault',
'Price__c': 0,
'Quantity__c': '0',
'Packed__c': false }"/>
<c:campingHeader />
<!-- <c:campingItemForm item="{!v.item}" items="{!v.items}" /> -->
<c:campingList items="{!v.items}"/>
</aura:component>
CampingListController.apxc
:
public class CampingListController {
@AuraEnabled
public static List<Camping_Item__c> getItems() {
return [SELECT Id, Name, Quantity__c, Price__c, Packed__c FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem(Camping_Item__c item) {
upsert item;
return item;
}
}
campingController.js
:
({
logArray : function(component, event, helper) {
var items = component.get("v.items");
console.log(JSON.stringify(items));
},
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);
}
})
campingHeader.cmp
:
<aura:component >
<lightning:layout class="slds-page-header slds-page-header--object-home">
<lightning:layoutItem >
<lightning:icon iconName="action:goal"/>
</lightning:layoutItem>
<lightning:layoutItem padding="horizontal-small">
<div class="page-section page-header">
<h1 class="slds-text-heading--label">Camping list</h1>
</div>
</lightning:layoutItem>
</lightning:layout>
</aura:component>
campingList.cmp
:
<aura:component controller="CampingListController">
<aura:attribute name="items" type="Camping_Item__c[]" />
<aura:handler name="addItemEvent" event="c:addItemEvent"
action="{!c.handleAddItem}"/>
<c:campingListForm/>
<aura:iteration items="{!v.items}" var="item">
<c:campingListItem item="{!item}" />
</aura:iteration>
</aura:component>
campingListController.js
:
({
clickCreateItem : function(component, event, helper) {
var isValidItem = component.find('campingItemForm').reduce(function(total,currentValue, index,arr)
{
currentValue.showHelpMessageIfInvalid();
return total && currentValue.get('v.validity').valid;
}, true);
if(isValidItem) {
helper.createItem(component);
}
},
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);
},
handleAddItem: function(component, event, helper) {
var item = event.getParam("item");
helper.updateExpense(component, item);
}
})
campingListHelper.js
:
({
createItem : function(component, item) {
var action = component.get("c.saveItem");
//var newItem = component.get("v.newItem");
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());
item = {sobjectType: "Camping_Item__c"};;
component.set("v.newItem", item);
component.set("v.items", items);
}
});
$A.enqueueAction(action);
}
})
campingListForm.cmp
:
<aura:component controller="CampingListController">
<aura:attribute name="newItem" type="Camping_Item__c" default="{
'sobjectType': 'Camping_Item__c',
'campingItemName': 'SSSSSSSSSSSSSSSSS',
'Price__c': 0,
'Quantity__c': '0',
'Packed__c': false }"/>
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<form class="slds-form--stacked">
<lightning:input aura:id="campingItemForm" label="Name"
name="Name"
value="{!v.newItem.Name}"/>
<lightning:input type="number" aura:id="campingItemForm" label="Quantity"
name="Quantity"
min="1"
step="1"
value="{!v.newItem.Quantity__c}"
placeholder="0"/>
<lightning:input type="number" aura:id="campingItemForm" label="Price"
name="Price"
formatter="currency"
value="{!v.newItem.Price__c}"/>
<lightning:input aura:id="campingItemForm" type="checkbox" label="Packed"
name="campingItemIsPacked"
checked="{!v.newItem.Packed__c}"/>
<lightning:button label="Create Camping Item"
class="slds-m-top--medium"
variant="brand"
onclick="{!c.clickCreateItem}"/>
</form>
</aura:component>
campingListFormController.js
:
({
clickCreateItem : function(component, event, helper) {
var isValidItem = component.find('campingItemForm').reduce(function(total,currentValue, index,arr)
{
currentValue.showHelpMessageIfInvalid();
return total && currentValue.get('v.validity').valid;
}, true);
if(isValidItem) {
helper.createItem(component);
}
}
})
campingListHelper.js
:
({
createItem : function(component) {
var action = component.get("c.saveItem");
var newItem = component.get("v.newItem");
action.setParams({
"item": newItem
});
action.setCallback(this, function(response){
var state = response.getState();
if (state === "SUCCESS") {
/* var items = component.get("v.items");
items.push(response.getReturnValue());
newItem = {sobjectType: "Camping_Item__c"};
component.set("v.newItem", newItem);
component.set("v.items", items); */
var addItemEvent = component.getEvent("addItem");
addItemEvent.setParams({"item": response.getReturnValue()});
addItemEvent.fire();
newItem = {sobjectType: "Camping_Item__c"};
component.set("v.newItem", newItem);
}
});
$A.enqueueAction(action);
}
})
addItemEvent.evt
:
<aura:event type="COMPONENT">
<aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>
As you can tell from the line :
<aura:component controller="CampingListController">
in the campingList.cmp
the .apxc
controller is attached to the campingList.cmp
.
Next, as you can tell from the line :
helper.updateExpense(component, item);
in the campingListController.js
and then from the line :
var action = component.get("c.saveItem");
in the campingListHelper.js
the .apxc
function saveItem
is called.
So, what is still needs to be checked is that the event arrives to the handler in campingList.cmp
.
Here is the event which will be thrown from the campingListForm.cmp
:
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
and in the campingListFormHelper.js
it is actually thrown :
addItemEvent.fire();
Hence I am expecting the even to get caught in the campingList.cmp
over here:
<aura:handler name="addItemEvent" event="c:addItemEvent"
action="{!c.handleAddItem}"/>
and as a result call the saveItem
function.
But the Trailhead continues to tell me that that call does not happen. And after debugging I see that it really does not. What am I doing wrong here?
String[]
will trip it up if it's expecting aList<String>
- another example I had recentlySystem.Queueable
vsQueueable
caused me not to get the challenge on first try. I think the trailhead team needs some more creativity + people better at regex expressions.