[SalesForce] Stuck on Trailhead ‘Connect Components with Events’ Challenge

I'm facing an issue with this Trailhead module – I'm getting the following error message & I really can't see why:

Challenge Not yet complete… here's what's wrong:
The campingListFormHelper isn't resetting the 'newItem' value provider with a Camping_Item__c sObject.

Functionality, my app works exactly as specified – I think there must be some nuisance in whatever way Trailhead checks the functionality that I'm not aware of.

Here's my app:

<aura:application extends="force:slds">
    <c:campingHeader />
    <c:campingList />
</aura:application>

and my event:

<aura:event type="COMPONENT" description="Event used when an Item is added.">
    <aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>

my header component:

<aura:component >
    <div class="slds-page-header" role="banner">
        <div class="slds-grid">
            <div class="slds-col">
                <p class="slds-text-heading--label">Camping Items</p>
                <h1 class="slds-text-heading--medium">Camping List</h1>
            </div>
        </div>
    </div>
</aura:component>

campingList component:

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId" controller="CampingListController" access="global">
    <aura:attribute name="items" type="Camping_Item__c[]"/>
    <aura:handler name="addItem" event="c:addItemEvent" action="{!c.handleAddItem}"/>
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>

    <div class="slds-col slds-col--padded slds-p-top--large">
        <c:campingListForm />
        <div class="slds-card slds-p-top--medium">
            <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>
    </div>
</aura:component>

controller (no helper code for this component):

({
    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());
            } else {
                console.log('Failed with state: ' + state);
            }
        });

        $A.enqueueAction(action);
    },
    handleAddItem: function(component, event, helper) {
        var item = event.getParam("item");

        var action = component.get("c.saveItem");
        //json stringify is not needed I think.       
        action.setParams({
                    "item": item
                });

        action.setCallback(this, function(response){
            var state = response.getState();
            if (component.isValid() && state === "SUCCESS") {        
                var items = component.get("v.items");
                items.push(item);
                component.set("v.items",items);
            }
        });
        $A.enqueueAction(action);
    }
})

campingListForm component:

<aura:component >
    <aura:attribute name="newItem" type="Camping_Item__c" 
                    default="{'sobjectType':'Camping_Item__c',
                                'Name':'',
                                'Quantity__c':0,
                                'Price__c':0,
                                'Packed__c':false}" />
    <aura:registerEvent name="addItem" type="c:addItemEvent"/>

    <div aria-labelledby="itementryform">
            <fieldset class="slds-box slds-theme--default slds-container--small">
                <legend id="itementryform" class="slds-text-heading--small slds-p-vertical-medium">
                    Add Item
                </legend>

                <form class="slds-form--stacked">
                    <div class="slds-form-element slds-is-required">
                        <div class="slds-form-element__control">
                            <ui:inputText aura:id="itmname" label="Item Name" class="slds-input" labelClass="slds-form-element__label"
                                          value="{!v.newItem.Name}" required="true" />
                        </div>
                        <div class="slds-form-element__control">
                            <ui:inputNumber aura:id="itmquantity" label="Quantity" class="slds-input" labelClass="slds-form-element__label"
                                          value="{!v.newItem.Quantity__c}" required="true" />
                        </div>
                        <div class="slds-form-element__control">
                            <ui:inputNumber aura:id="itmprice" label="Price" class="slds-input" labelClass="slds-form-element__label"
                                          value="{!v.newItem.Price__c}" required="true" />
                        </div>
                        <div class="slds-form-element__control">
                            <ui:inputCheckbox aura:id="itmpacked" label="Packed" class="slds-input" labelClass="slds-form-element__label"
                                          value="{!v.newItem.Packed__c}" required="true" />
                        </div>
                        <div class="slds-form-element">
                            <ui:button label="Create Item" class="slds-button slds-button--brand" press="{!c.submitForm}"/>
                        </div>
                    </div>
                </form>

            </fieldset>
        </div>
</aura:component>

controller:

({
    submitForm : function(component, event, helper) {
        var newItem = component.get("v.newItem");

        var nameField = component.find("itmname");
        var quantityField = component.find("itmquantity");
        var priceField = component.find("itmprice");

        if ($A.util.isEmpty(nameField.get("v.value"))) {
            nameField.set("v.errors", [{message:"Item name can't be blank."}]);   
        } else if ($A.util.isEmpty(quantityField.get("v.value"))) {
            quantityField.set("v.errors", [{message:"Item quantity can't be blank."}]);    
        } else if ($A.util.isEmpty(priceField.get("v.value"))) {
            priceField.set("v.errors", [{message:"Item price can't be blank."}]);    
        } else {


            helper.createItem(component, newItem);

            nameField.set("v.errors", null);
            quantityField.set("v.errors", null);
            priceField.set("v.errors", null);
        }
    }   
})

helper:

({
    createItem : function(component, newItem) {
        // fire event
        var addItem = component.getEvent("addItem");
        addItem.setParams({"item":newItem});
        addItem.fire();
        var newItemStr = "{\"sobjectType\":\"Camping_Item__c\",\"Name\":\"\",\"Price__c\":0,\"Quantity__c\":0,\"Packed__c\":false}";
        component.set("v.newItem", JSON.parse(newItemStr));
    }
})

As I said, the application works perfectly and I can't see any reason why it would be failing but it is. I've checked the other answers for similar problems to no avail.

Edit:

I have seen this question, but do not believe my own to be a duplicate despite the similar error message. The solution in the linked question did not work.

That solution is to move the code from campingListHelper to campingListController. If you read my code snippets above you will see I have already done this.

Best Answer

At the time I did it, I used this line of code and it worked. That's true it's not clear in the Trailhead module how to do it.

component.set("v.newItem", "{'sobjectType':'Camping_Item__c','Name':'',Quantity__c': 0,'Price__c': 0}");
Related Topic