0

I ran into this error when trying to Preview my Application from the Developer Console. When I click the "CreateExpense" button after entering in data into the fields (I might have spelled Expenses wrong)

All of this code references the Trail head Module: "Connecting Components With Events" from 'Lightning Components Basics' There is a lot of code and I am not experienced enough to know where the error is happening in the code and since I can't debug, line by line, this error is hard to find.

Any help is appreciated!!!

This is the error message:

Action failed: c:exspenses$controller$clickCreateExpense [action.setCallBack is not a function]
Failing descriptor: {c:exspenses$controller$clickCreateExpense}

exspensesApp.app

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

exspenses.cmp

<aura:component controller="ExpensesController">
<!-- CUSTOM ATTRIBUTE DEFINITION -->
<aura:attribute name="expenses" type="Expense__c[]" /> // local array of Objects to hold all expenses created.
<aura:attribute name="newExpense" type="Expense__c"
                default="{'sObject': 'Expense__c', 
                                'Name': '',
                                'Amount__c': 0,
                                'Client__c': '',
                                'Date__c': '',
                                'Reimbursed__c': false}"/>
<!-- init handler -->
<aura:handler name="init" action="{!c.doInit}" value="{!this}" />

<!-- PAGE HEADER -->
<div class="slds-page-header" role="banner">
  <div class="slds-grid">
    <div class="slds-col">
      <p class="slds-text-heading--label">Expenses</p>
      <h1 class="slds-text-heading--medium">My Expenses</h1>
    </div>
  </div>
</div>
<!-- /PAGE HEADER -->

<!-- NEW EXPENSE FORM -->
<div class="slds-col slds-col--padded slds-p-top--large">

  <div aira-labelledby="newexpenseform">

    <!-- BOXED AREA -->
    <fieldset class="slds-box slds-theme--default slds-container--small">
      <legend id="newexpenseform" class="slds-text-heading--small slds-p-vertial--medium">
      Add Expense
      </legend>

      <!-- CREATE NEW EXPENSE FORM -->
      <form class="slds-form--stacked">

        <div class="slds-form-element slds-is-required">
            <div class="slds-form-element__control">
                <ui:inputText aura:id="expname" label="Expense Name" 
                            class="slds-input"
                            labelClass="slds-form-element__label"
                            value="{!v.newExpense.Name}"
                            required="true" />
            </div>
        </div>

  <div class="slds-form-element slds-is-required">
      <div class="slds-form-element__control">
          <ui:inputNumber aura:id="amount" label="Amount"
              class="slds-input"
              labelClass="slds-form-element__label"
              value="{!v.newExpense.Amount__c}"
              required="true"/>

      </div>
  </div>

  <div class="slds-form-element">
      <div class="slds-form-element__control">
          <ui:inputText aura:id="client" label="Client"
              class="slds-input"
              labelClass="slds-form-element__label"
              value="{!v.newExpense.Client__c}"
              placeholder="ABC Co."/>
      </div>
  </div>

  <div class="slds-form-element">
      <div class="slds-form-element__control">
          <ui:inputDate aura:id="expdate" label="Expense Date"
              class="slds-input"
              labelClass="slds-form-element__label"
              value="{!v.newExpense.Date__c}"
              displayDatePicker="true"/>
      </div>
  </div>

  <div class="slds-form-element">
      <ui:inputCheckbox aura:id="reimbursed" label="Reimbursed?"
          class="slds-checkbox"
          labelClass="slds-form-element__label"
          value="{!v.newExpense.Reimbursed__c}"/>
  </div>

  <div class="slds-form-element">
      <ui:button label="Create Expense"
          class="slds-button slds-button--brand"
          press="{!c.clickCreateExpense}"/>
  </div>

      </form>
      <!-- Create new expense form -->
    </fieldset>
    <!-- Boxed Area -->
  </div>    
</div>

<!-- NEW EXPENSE FORM -->
<c:expensesList expenses="{!v.expenses}" />
</aura:component>

exspensesController.js

({  
clickCreateExpense : function(component, event, helper) {

    if(helper.validateExpenseForm(component)) {
        // Create a new Expense, if it is valid
        var newExpense = component.get("v.newExpense");
        console.log(newExpense);
        helper.createExpense(component, newExpense);
    }
},

// Load expenses from Salesforce
doInit: function(component, event, helper) {

// Create the action (remote method call)
var action = component.get("c.getExpenses");

// 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.expenses", response.getReturnValue());
    }
    else {
        console.log("Failed with state: " + state);
        console.log(response + " ");
    }
});

    // Send action off to be executed (server request)
    $A.enqueueAction(action);
},

})

exspensesHelper.js

({
createExpense : function(component, expenseToAdd) {
    var action = component.get("c.saveExpense"); // call to Apex Controller method
    action.setParams({
        "expense": expenseToAdd
    });
    action.setCallBack(this, function(response) {
        var state = response.getState();
        if(component.isValid() && state === "SUCCESS") {
            var expenses = component.get("v.expenses"); // get the Local Array [] of Expense__c Objects.
            expenses.push(response.getReturnValue()); // pusing the response from the Server into our Local Array
            component.set("v.expenses", expenses);
        }
    });
    $A.enqueAction(action);
},

validateExpenseForm : function(component) {
//----------------------------------------------------------------------------------    
// simplistic error checking
var validExpense = true;

// Name must not be blank.
var nameField = component.find("expname");
var expname = nameField.get("v.value");
    if($A.util.isEmpty(expname)) {
        validExpense = false;
        nameField.set("v.errors", [{message: "Expense name can't be blank..."}]);
    }
    else {
        nameField.set("v.errors", null);
    }
//-------------------------------------------------------------------------------        
// Amount must be set, must be a positive number.
var amtField = component.find("amount");
var amt = amtField.get("v.value");
    if($A.util.isEmpty(amt) || isNaN(amt) || (amt <= 0.0)) {
        validExpense = false;
        amtField.set("v.errors", [{message: "Enter a different expense amount..."}]);
    }
    else {
        // if the amount is valid, uset any errors set before.
        amtField.set("v.errors", null);
    }

return(validExpense);
}
})

this is the component that displays the list, once the expense is created. I am sure this piece of code works.

expensesList.cmp

<aura:component >

<aura:attribute name="expenses" type="Expense__c[]" />

<div class="slds-card slds-p-top--medium">
    <header class="slds-card__header">
        <h3 class="slds-text-heading--small">Expenses</h3>
    </header>

    <section class="slds-card__body">
        <div id="list" class="row">
            <aura:iteration items="{!v.expenses}" var="expense">
                <c:expenseItem expense="{!expense}" />
            </aura:iteration>
        </div>
    </section>
</div>

</aura:component>

ExpensesController.apxc

public with sharing class ExpensesController {

// LECTURE ABOUT WHAT IS MISSING HERE COMING SOON

@AuraEnabled
public static Expense__c saveExpense(Expense__c expense) {
    // Perform isUpdatable() check first, then
    upsert expense;// upsert slaps a new ID onto this record passed in
    return expense;
}

@AuraEnabled
public static Expense__c getExpenses() {
    // Check to make sure all fields are accessible to this user.
    String[] fieldsToCheck = new String[] {
        'Id', 'Name', 'Amount__c', 'Client__c', 'Date__c',
        'Reimbursed__c', 'CreatedDate'
    };
    // Map Object    
    Map<String, Schema.SObjectField> fieldDescribeTokens = 
        Schema.SObjectType.Expense__c.fields.getMap();

    for(String field : fieldsToCheck) {
        if( ! fieldDescribeTokens.get(field).getDescribe().isAccessible()) {
            throw new System.NoAccessException();
            return null;
        }
    }

    // OK, they're cool, let 'em through
    return [SELECT Id, Name, Amount__c, Client__c, Date__c,
                    Reimbursed__c, CreatedDate
           FROM Expense__c];
}
}

expensesItemUpdate.evt

Custom Event type I made for this project.

<aura:event type="COMPONENT" >
    <!-- there are 2 types of Events: APPLICATION and COMPONENT Events -->
    <aura:attribute name="expense" type="Expense__c" />
</aura:event>

expenseItem.cmp

this is the most recently edited code, it is what uses the Event I made

<aura:component >
<aura:attribute name="expense" type="Expense__c"/>

<!-- This component FIRES/SENDS an EVENT named "updateExpense" -->
<aura:registerEvent name="updateExpense" type="c:expensesItemUpdate" />
<div class="slds-card">

    <!-- Color the item GREEN if the expense is Reimbursed -->
    <div class="{!v.expense.Reimbursed__c == true ? 
                'slds-theme--success' : 'slds-theme--warning'}">

        <header class="slds-card__header slds-grid grid--flex-spread">
            <a aura:id="expense" href="{!'/' + v.expense.Id}">
                <h3>{!v.expense.Name}</h3>
            </a>
        </header>

        <section class="slds-card__body">
            <div class="slds-title slds-hint-parent">
                <p class="slds-title__title slds-truncate">Amount:
                    <ui:outputCurrency value="{!v.expense.Amount__c}"/>
                </p>
                <p class="slds-truncate">Client:
                    <ui:outputText value="{!v.expense.Client__c}"/>
                </p>
                <p class="slds-truncate">Date:
                    <ui:outputDate value="{!v.expense.Date__c}"/>
                </p>
                <p class="slds-truncate">Reimbursed?:
                    <ui:inputCheckbox value="{!v.expense.Reimbursed__c}" 
                                      click="{!c.clickReimbursed}"/>
                </p>
            </div>
        </section>
    </div>
</div>
</aura:component>

expensesController.js

This is the JavaScript that fires the Event

({
clickReimbursed : function(component, event, helper) {
    var expense = component.get("v.expense");
    var updateEvent = component.getEvent("updateExpense");
    udateEvent.setParams({ "expense": expense});
    updateEvent.fire();
}
})

1 Answer 1

6

Javascript is case-sensitive.

action.setCallBack is not a function because setCallBack should be:

setCallback

If you read the documentation from the Lightning developer guide, this is specified:

Expression Functions Reference

The expression language contains math, string, array, comparison, boolean, and conditional functions. All functions are case-sensitive.

2
  • Thank You, I fixed that error but now I am just getting "Failed with state: ERROR" in the JavaScript console window and no other modal window error like I was before. so half the problem is fixed, I just need help with where it broke, because I am the sole developer working on this. Thanks again!!!
    – Kangarooah
    Aug 4, 2017 at 19:40
  • feel free to create a new post specifying the details. Thanks
    – glls
    Aug 4, 2017 at 19:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .