[SalesForce] Unable to display custom object list attribute returned from client side controller

I am hung up on the hands-on challenge for the Lightning Component Basics > Input Data Using Forms section on Trailhead. I have a form with input controls for name, quantity, price, and isPacked checkbox for a camping item. I have a client side controller and helper that should add the inputed item to a list of items at the bottom of the page when the users clicks the "Add to List" button on the form (code for those below).

Here is the error I am getting on the button click:

This page has an error. You might just need to refresh it.
Action failed: aura$iteration$controller$itemsChange [Cannot read property 'apply' of undefined]
Failing descriptor: {aura$iteration$controller$itemsChange}

I found a post from someone having a similar problem on the Salesforce developer forum, but no solution was posted. I am able to get the Expenses example that is provided working locally, so I'm pretty confident my issue is with my particular code rather than anything with my environment and configuration. What am I missing here?

Component code (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}"/>

<!-- NEW ITEM INPUT FORM -->
<form class="slds-form--stacked">

  <div class="slds-form-element slds-is-required">
      <div class="slds-form-element__control">
          <ui:inputText aura:id="itemname" label="Item 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"
              placeholder="0"/>

      </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}"
              placeholder="0"/>
      </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="Add to Camping List"
          class="slds-button slds-button--brand"
          press="{!c.addToCampingList}"/>
  </div>
</form>

<aura:iteration items="{!v.items}" var="item">
    <span>
        <c:campingListItem item="{!item}"/>
    </span>

</aura:iteration>

Controller code (campingListController.js):

({

addToCampingList : function(component, event, helper) {
    // Simplistic error checking
    var validItem = true;

    // Name, Quantity, and Price must not be blank
    if ($A.util.isEmpty(component.find("itemname").get("v.value"))||
        $A.util.isEmpty(component.find("quantity").get("v.value"))||
        $A.util.isEmpty(component.find("price").get("v.value"))){
        validItem = false;
        component.set("v.errors", [{message:"Name, quantity, and price can't be blank."}]);
    }
    else {
        component.set("v.errors", null);
    }

    // If we pass error checking, do some real work
    if(validItem){
        // Create the new expense
        var newItem = component.get("v.newItem");
        console.log("Create expense: " + JSON.stringify(newItem));
        helper.addToList(component, newItem);
    }


    var newItem = component.get("v.newItem");

    //check for nulls

    helper.addToList(component, newItem);
}})

Helper code (campingListHelper.js):

({
addToList : function(component, newItem) {
    var campingList = component.get("v.items");

    // Copy the expense to a new object
    // THIS IS A DISGUSTING, TEMPORARY HACK
    var item = JSON.parse(JSON.stringify(newItem));

    campingList.push(item);

    component.set("v.items", campingList);
}})

UPDATE:
After more debugging it appears to me that the items list is getting successfully updated by the controller and the issue is with the <aura:iteration> element on the campingList component (which makes sense given that the iteration is mentioned in the error message). If I take out the reference to the campingListItem from the and put the item rendering directly in the campingList component, I am able to successfully update the list.

Here is my campingListItem component:

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

Do I have something wrong with how this component is hooked up?

Best Answer

aura$iteration$controller$itemsChange [Cannot read property 'apply' of undefined

This is usually a is parsing error in controller or helper method.

Track missing commas or parenthesis :)