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
Stalin CampusStalin Campus 

Trailhead Challenge: Refactor Components and Communicate with Events

I am getting error while saving the CampingList component :
Failed to save campingList.cmp: Invalid definition for null:CampingListController: null: Source

Here is my code .
Camping List.cmp
<aura:component controller="CampingListController">
    <aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
    
    <aura:handler name="addItem" event="c:addItemEvent" action="{!c.handleAddItem }"/>
    
    <aura:attribute name="items" type="Camping_Item__c[]"/>
    
       <!-- NEW EXPENSE FORM -->
    <div class="slds-col slds-col--padded slds-p-top--large">
        <c:campingListForm/>
    </div>
    <!-- / NEW EXPENSE FORM -->    

    <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>
</aura:component>



CampingListController

({
    // 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 (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);
    },
    handleAddItem : function (component,event,helper){
    var action = component.get("c.saveItem");
        var Item = event.getParam("item");
        var lstItems = component.get("v.items");

        lstItems.push(Item);
        component.set("v.items",lstItems);
        console.log("After:"+lstItems);
        action.setParams({"CampingItem":Item});
        action.setCallback(this,function(response){
            var state = response.getState();
                
            if (component.isValid() && state === "SUCCESS") {
                //let the magic happen
            }
         });
        $A.enqueueAction(action);   
     }
})


CampingListHelper
({
    createCamping: function(component, item) {
        var theitems = component.get("v.items");
 
        var newitem = JSON.parse(JSON.stringify(item));
 
        theitems.push(newitem);
        component.set("v.items", theitems);
        
        component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c','Name': '','Quantity__c': 0,
                    'Price__c': 0,'Packed__c': false });
    },
    validateCampingItem: function(component) {
        // Simplistic error checking
        var validCamping = true;

        // Name must not be blank
        var nameField = component.find("campname");
        
        if ($A.util.isEmpty(nameField.get("v.value"))){
            validCamping = false;
            nameField.set("v.errors", [{message:"Camping name can't be blank."}]);
        } else {
            nameField.set("v.errors", null);
        }
        
        if ($A.util.isEmpty(component.find("campQty").get("v.value"))){
            validCamping = false;
            component.find("campQty").set("v.errors", [{message:"Camping Quantity can't be blank."}]);
        } else {
            component.find("campQty").set("v.errors", null);
        }
        
        if ($A.util.isEmpty(component.find("campPrice").get("v.value"))){
            validCamping = false;
            component.find("campPrice").set("v.errors", [{message:"Camping Price can't be blank."}]);
        } else {
            component.find("campPrice").set("v.errors", null);
        }
        
        return(validCamping);
    },
    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 items = component.get("v.items");
                items.push(response.getReturnValue());
                component.set("v.items", items);
            }
        });
            
        $A.enqueueAction(action);
    }
})


Can anyone help me on this  ?

NagendraNagendra (Salesforce Developers) 
Hi Stalin,

May I suggest you please check with below links from the community forums which might help you further with the above issue. Hope this will help you pass the challenge.

Kindly mark this as solved if it's resolved.

Thanks,
Nagendra
Stalin CampusStalin Campus
Hi Nagendra ,
I tried it but no Luck.
Still same error .
User-added image
 
Nirvik MitterNirvik Mitter

This is solved; See my (Nirvik Mitter) answer here: https://developer.salesforce.com/forums/?id=906F0000000kDPpIAM

 

I cleared the Trailhead Challenge - Lightning Components Basics - All of them; This piece above (Connect Components with Events > Refactor Components and Communicate with Events) was the last difficult hurdle.

Nirvik MitterNirvik Mitter

Hi Stalin,

Hope this solves your query. Have a look: https://developer.salesforce.com/forums/?id=906F0000000kDPpIAM

Kindly mark this as solved if it's resolved at your end too.

Mohammed Hasan 11Mohammed Hasan 11
Hi,

Hope this solves your query. Have a look at : https://github.com/anilvanjre/Connect-Components-with-Events
Just copy paste this code and check the challenge.
Surya Pratap Singh 13Surya Pratap Singh 13
This worked for me.Try it once and Mart it CORRECT

campingList.cmp:
<aura:component controller="CampingListController">
<aura:handler name="init" action="{!c.doInit}" value="{!this}" />

    <aura:handler name="addItem" event="c:addItemEvent" action="{!c.handleAddItem}" />
<aura:attribute name="items" type="Camping_Item__c[]"/>
    <c:campingHeader/>
    
     <!-- NEW EXPENSE FORM -->
    <lightning:layout >
        <lightning:layoutItem padding="around-small" size="6">
            <c:campingListForm />
        </lightning:layoutItem>
    </lightning:layout>


<div class="slds-card slds-p-top--medium">
    <header class="slds-card__header">
        <c:campingHeader/>
    </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 :
({
    doInit : function(component, event, helper){
        var getCampingItemListingAction = component.get('c.getItems');
        getCampingItemListingAction.setCallback(this, function(response){
            var respState = response.getState();
            if(respState == 'SUCCESS'){
                var vItems = component.get('v.items');
                vItems = response.getReturnValue();
                component.set('v.items', vItems);
            }
        });
        $A.enqueueAction(getCampingItemListingAction);
    },
    handleAddItem : function(component, event, helper){
        var newCampingItem = event.getParam('item');

        //var theItems = component.get("v.items");
        //theItems.push(newCampingItem);
        //component.set("v.items", theItems);

        //helper.createItem(component, newCampingItem);
        var saveItemAction = component.get('c.saveItem');
        saveItemAction.setParams({ 'campingItem' :  newCampingItem });

        saveItemAction.setCallback(this, function(response){
            var respState = response.getState();
            console.log(respState);
            if( respState == 'SUCCESS'){
                var theItems = component.get("v.items");
                theItems.push(response.getReturnValue());
                component.set("v.items", theItems);
            }
        });
        
        $A.enqueueAction(saveItemAction);
    }
})
addItemEvent.evt :
 
<aura:event type="COMPONENT">
    <aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>


campingListItem.cmp:
<aura:component >
    <aura:attribute name="item" type="Camping_Item__c"/>
    <lightning:card >
        <p class="slds-p-horizontal_small">
            Name:  {!v.item.Name}
        </p>
        
        <p class="slds-p-horizontal_small">
            Price: <lightning:formattedNumber value="{!v.item.Price__c}" style="currency"/>
        </p>
        <p class="slds-p-horizontal_small">
            Quantity: {!v.item.Quantity__c}
        </p>
        
        <p class="slds-p-horizontal_small">
            Packed:
            <ui:outputCheckbox value="{!v.item.Packed__c}"/>
        </p>
        
    </lightning:card>
</aura:component>


campingListItem.css:
.THIS.slds-card.slds-theme_success {
    background-color: rgb(75, 202, 129);
}
campingListForm.cmp:
<aura:component controller="CampingListController">
    <aura:registerEvent name="addItem" type="c:addItemEvent" />
    
    <aura:attribute name="newItem" type="Camping_Item__c"
                    default="{ 'sobjectType': 'Camping_Item__c',
                             'Name': '',
                             'Quantity__c': 0,
                             'Price__c': 0,
                             'Packed__c': false }" required="true"/>
    <!-- CREATE NEW EXPENSE -->
    <div aria-labelledby="newexpenseform">
        <!-- BOXED AREA -->
        <fieldset class="slds-box slds-theme_default slds-container_small">
            <legend id="newexpenseform" class="slds-text-heading_small
                                               slds-p-vertical_medium">
                Add Camp
            </legend>
            
            <!-- CREATE NEW ITEM FORM -->
            <form class="slds-form--stacked">
                
                <div class="slds-form-element slds-is-required">
                    <div class="slds-form-element__control">
                        <lightning:input aura:id="campingItem" type="text" name="name" label="Name" value="{!v.newItem.Name}" required="true" />
                    </div>
                </div>
                
                <div class="slds-form-element slds-is-required">
                    <div class="slds-form-element__control">
                        <lightning:input aura:id="campingItem" type="number" label="Quantity" name="quantity" value="{!v.newItem.Quantity__c}" step="1" min="1" required="true" />
                    </div>
                </div>
                
                <div class="slds-form-element">
                    <div class="slds-form-element__control">
                        <lightning:input aura:id="campingItem" type="number" formatter="currency" name="price" label="Price" value="{!v.newItem.Price__c}"  />
                    </div>
                </div>
                
                <div class="slds-form-element">
                    <lightning:input aura:id="campingItem" type="checkbox" label="Packed?" name="packed" checked="{!v.newItem.Packed__c}" />
                </div>
                
                <div class="slds-form-element">
                    <lightning:button label="Create Camping Item" variant="brand" onclick="{!c.clickCreateItem}" />
                </div>
                
            </form>
            <!-- / CREATE NEW ITEM FORM -->
        </fieldset>
        <!-- / BOXED AREA -->
    </div>
    <!-- / CREATE NEW Camping -->
</aura:component>
campingListFormContoller.js :
({
    
    clickCreateItem: function(component, event, helper) {

        // Simplistic error checking
        var validItem = true;
        validItem = component.find('campingItem').reduce(function(validSoFar, inputCmp){
            inputCmp.showHelpMessageIfInvalid();
            return validSoFar && inputCmp.get('v.validity').valid;
        }, true);

        if(validItem){
            helper.createItem(component);
        }
    }
})

campingListFormHelper.js::
({
   
    createItem : function(component){

        var campingItem = component.get("v.newItem");
        console.log(campingItem);

        var adItemEvent = component.getEvent('addItem');
        adItemEvent.setParams({'item': campingItem});
        adItemEvent.fire();
        console.log('Event fired');
        component.set("v.newItem",{'sobjectType': 'Camping_Item__c',
                             'Name': '',
                             'Quantity__c': 0,
                             'Price__c': 0,
                             'Packed__c': false });
    }
})

campingHeader.cmp:
<aura:component >
    <lightning:layout class="slds-page-header slds-page-header--object-home">
    <lightning:layoutItem >
    <lightning:icon iconName="action:goal" alternativeText="My Camping"/>
</lightning:layoutItem>
    <lightning:layoutItem padding="horizontal-small">
<div class="page-section page-header">
<h1 class="slds-text-heading--label">Camping</h1>
<h2 class="slds-text-heading--medium">My Camping</h2>
</div>
</lightning:layoutItem>
</lightning:layout>
</aura:component>

campingApp.app:
<aura:application extends="force:slds" >
<c:campingList />
</aura:application>


 
kumar d 51kumar d 51
Hi,
Surya Pratap Singh 13
Your answer is working

Thanks