Can't figure out how to get through the "Connect Components with Events" challenge! - Answers - Salesforce Trailblazer Community
Trailblazer Community
Ask Search:
Liubomyr MalanchakLiubomyr Malanchak 

Can't figure out how to get through the "Connect Components with Events" challenge!

Hi there, 
I just finished the last unit in the Aura basics module but for some reason, I'm not able to pass the challenge... I think I met all the conditions, and the camping items are saved correctly, but I'm getting this error every time I check the challenge. Can someone please point me at what am I doing 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."
Here's the code.
Unit: Connect Components with Events
campingList.cmp
<aura:component controller="CampingListController">
    <aura:attribute name="items" type="Camping_Item__c[]"/>
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
    <aura:handler name="addItem" event="c:addItemEvent"
                  action="{!c.handleAddItem}"/>
    
    <lightning:layout >
        <lightning:layoutItem padding="around-small" size="6">
            <c:campingListForm/>
        </lightning:layoutItem>
    </lightning:layout>
    <lightning:card title="Items">
        <p class="slds-p-horizontal--small">
            <aura:iteration items="{!v.items}" var="item">
                <c:campingListItem item="{!item}"/>
            </aura:iteration>
        </p>
    </lightning:card>
</aura:component>
campingListController.js
({
    handleAddItem: function(component, event, helper) {
        var newItem = event.getParam("item");
        helper.saveItem(component, newItem);
    },
        // Load Items 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 (state === "SUCCESS") {
                component.set("v.items", response.getReturnValue());
            }
            else {
                console.log("Failed with state: " + state);
            }
        });
        // Send action off to be executed
        $A.enqueueAction(action);
    },
})
campingListHelper.js
({
    saveItem: 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());
                    component.set("v.items", items);
                }
            });
        $A.enqueueAction(action);
    }
})
campingListForm.cmp
<aura:component >
    <aura:attribute name="newItem" type="Camping_Item__c"
                    default="{ 'sobjectType': 'Camping_Item__c',
                             'Name': '',
                             'Price__c': 0,
                             'Quantity__c': 0,
                             'Packed__c': false }"/>
    <aura:registerEvent name="addItem" type="c:addItemEvent"/>
    <!-- NEW ITEM FORM -->
    <lightning:layout>
        <lightning:layoutItem padding="around-small" size="6">
            <!-- CREATE NEW ITEM -->
            <div aria-labelledby="newitemform">
                <!-- BOXED AREA -->
                <fieldset class="slds-box slds-theme--default slds-container--small">
                    <legend id="newitemform" class="slds-text-heading--small 
                                                    slds-p-vertical--medium">
                        Add Camping Item
                    </legend>
                    
                    <!-- CREATE NEW CAMPING ITEM FORM -->
                    <form class="slds-form--stacked">          
                        <lightning:input aura:id="itemform" label="Item Name"
                                         name="itemname"
                                         value="{!v.newItem.Name}"
                                         required="true"/> 
                        <lightning:input type="number" aura:id="itemform" label="Price"
                                         name="itemprice"
                                         formatter="currency"
                                         value="{!v.newItem.Price__c}"/>
                        <lightning:input type="number"
                                         aura:id="itemform"
                                         label="Quantity"
                                         name="itemquantity"
                                         min="1"
                                         value="{!v.newItem.Quantity__c}"
                                         messageWhenRangeUnderflow="Enter a quantity that's at least 1."/>
                        <lightning:input type="checkbox" aura:id="itemform" 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 CAMPING ITEM FORM -->
                    
                </fieldset>
                <!-- / BOXED AREA -->
            </div>
            <!-- / CREATE NEW ITEM -->
        </lightning:layoutItem>
    </lightning:layout>
    <!-- / NEW ITEM FORM -->
</aura:component>
campingListFormController.js
({
	clickCreateItem: function(component, event, helper) {
        var validItem = component.find('itemform').reduce(function (validSoFar, inputCmp) 
                                                                {
            // Displays error messages for invalid fields
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);
        // If we pass error checking, do some real work
        if(validItem){
            // Create the new Item reference
            var newItem = component.get("v.newItem");
            helper.createItem(component, newItem);
            component.set("v.newItem", 
                          {'sobjectType' : 'Camping_Item__c',
                           'Name' : '',
                           'Quantity__c' : 0,
                           'Price__c' : 0,
                           'Packed__c' : false});
        }
    },
})
campingListFormHelper.js
({
    createItem: function(component, newItem) {
        var addItem = component.getEvent("addItem");
        addItem.setParams({ "item": newItem });
        addItem.fire();
    },
})

addItemEvent.evt
<aura:event type="COMPONENT">
    <aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>
CampingListController apex class:
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', 'CreatedDate'
        };
        
        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();
            }
        }
        
        // OK, they're cool, let 'em through
        return [SELECT Id, Name, Price__c, Quantity__c, Packed__c, CreatedDate 
                FROM Camping_Item__c];
    }
    
    @AuraEnabled
    public static Camping_Item__c saveItem(Camping_Item__c item) {
        // Perform isUpdateable() checking first, then
        upsert item;
        return item;
    }
}
Help!
 
Liubomyr MalanchakLiubomyr Malanchak
Forgot to list the conditions!
Here they are:
  1. Replace the HTML form in the campingList component with a new campingListForm component that calls the clickCreateItem JavaScript controller action when clicked.
  2. The campingList component listens for a c:addItemEvent event and executes the action handleAddItem in the JavaScript controller. The handleAdditem method saves the record to the database and adds the record to the items value provider.
  3. The addItemEvent event is of type component and has a Camping_Item__c type attribute named item.
  4. The campingListForm registers an addItem event of type c:addItemEvent.
  5. The campingListFormController JavaScript controller calls the helper's createItem method if the form is valid.
  6. The campingListFormHelper JavaScript helper creates an addItem event with the item to be added and then fires the event. It then resets the newItem value provider with a blank sObjectType of type Camping_Item__c.
Marlène DuvalMarlène Duval
Challenge verification expects the "saveItem" function to be called int the Controller (in campingListController.js) instead of from the Helper.
Then another issue is thrown for the same kind of reason if you add the Reset of the form in the Controller -> challenge expects the code to be in the Helper (campingListFormHelper)