You need to sign in to do that
Don't have an account?
Guiomar Fernández de Bobadilla
Lightning Components Basics - Connect Components with Events Challenge
Hi,
I can't pass the challenge (https://developer.salesforce.com/trailhead/force_com_dev_intermediate/lex_dev_lc_basics/lex_dev_lc_basics_events). This is the error when check challenge:
Challenge Not yet complete... here's what's wrong:
The campingList JavaScript controller isn't adding the new record to the 'items' value provider.
I tryed in the browser add new Camping Items and it's working correctly. The item is added to database and the list is updated.
This is my code:
campingList Component
campingList Controller.js
CampingListController
CampingListForm Component
CampingListForm Controller.js
CampingListForm Helper.js
Could anyone help me?
Thanks,
Regards.
I can't pass the challenge (https://developer.salesforce.com/trailhead/force_com_dev_intermediate/lex_dev_lc_basics/lex_dev_lc_basics_events). This is the error when check challenge:
Challenge Not yet complete... here's what's wrong:
The campingList JavaScript controller isn't adding the new record to the 'items' value provider.
I tryed in the browser add new Camping Items and it's working correctly. The item is added to database and the list is updated.
This is my code:
campingList Component
<aura:component controller="CampingListController"> <aura:handler name="init" action="{!c.doInit}" value="{!this}"/> <aura:handler name="addItem" event="c:addItemEvent" action="{!c.handleAddItem}"/> <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">My Camping Items</h1> </div> </div> </div> <div aria-labelledby="newitemform"> <fieldset class="slds-box slds-theme--default slds-container--small"> <c:campingListForm /> </fieldset> </div> <aura:attribute name="items" type="Camping_Item__c[]"/> <div class="slds-card slds-p-top--medium"> <header class="slds-card__header"> <h3 class="slds-text-heading--small">Camping List Items</h3> </header> <section class="slds-card__body"> <div id="list" class="row"> <aura:iteration items="{!v.items}" var="campItem"> <c:campingListItem item="{!campItem}"/> </aura:iteration> </div> </section> </div> </aura:component>
campingList Controller.js
({ 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"); action.setParams({ "item": item }); action.setCallback(this, function(response){ var state = response.getState(); if (component.isValid() && state === "SUCCESS") { var theItems = component.get("v.items"); theItems.push(item); component.set("v.items",theItems); } }); $A.enqueueAction(action); } })
CampingListController
public with sharing class CampingListController { @AuraEnabled public static List<Camping_Item__c> getItems() { return [SELECT Id, Name, Price__c, Quantity__c, Packed__c FROM Camping_Item__c]; } @AuraEnabled public static Camping_Item__c saveItem(Camping_Item__c item) { upsert item; return item; } }
CampingListForm Component
<aura:component > <aura:attribute name="newItem" type="Camping_Item__c" default="{ 'sobjectType': 'Camping_Item__c', 'Name': '', 'Packed__c': false, 'Price__c': '0', 'Quantity__c': '0' }"/> <aura:registerEvent name="addItem" type="c:addItemEvent"/> <div aria-labelledby="newitemform"> <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> <form class="slds-form--stacked"> <div class="slds-form-element slds-is-required"> <div class="slds-form-element__control"> <ui:inputText aura:id="name" label="Camping Item Name" class="slds-input" labelClass="slds-form-element__label" value="{!v.newItem.Name}" required="true"/> </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"> <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}" /> </div> </div> <div class="slds-form-element"> <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}"/> </div> </div> <div class="slds-form-element"> <ui:button label="Create Camping Item" class="slds-button slds-button--brand" press="{!c.clickCreateCampingItem}"/> </div> </form> </fieldset> </div> </aura:component>
CampingListForm Controller.js
({ clickCreateCampingItem : function(component, event, helper) { var validCamping = true; // Name must not be blank var nameField = component.find("name"); var expname = nameField.get("v.value"); if ($A.util.isEmpty(expname)){ validCamping = false; nameField.set("v.errors", [{message:"Camping Item name can't be blank."}]); } else { nameField.set("v.errors", null); } var priceField = component.find("price"); var price = priceField.get("v.value"); if ($A.util.isEmpty(price) || isNaN(price) || (price <= 0.0)){ validCamping = false; priceField.set("v.errors", [{message:"Camping Item price can't be blank."}]); } else { priceField.set("v.errors", null); } var quantityField = component.find("quantity"); var quantity = quantityField.get("v.value"); if ($A.util.isEmpty(quantity) || isNaN(quantity) || (quantity <= 0)){ validCamping = false; quantityField.set("v.errors", [{message:"Camping Item quantity can't be blank."}]); } else { quantityField.set("v.errors", null); } if(validCamping){ helper.createItem(component); } }, })
CampingListForm Helper.js
({ createItem : function(component) { var newItem = component.get("v.newItem"); var addEvent = component.getEvent("addItem"); addEvent.setParams({"item" : newItem}); addEvent.fire(); component.set("v.newItem", { 'sobjectType': 'Camping_Item__c', 'Name': '', 'Packed__c': false, 'Price__c': 0, 'Quantity__c': 0}); } })
Could anyone help me?
Thanks,
Regards.
In campingList Controller.js in lines #31, #32 and #33 change theItems to items
The action button must be submitForm, that is, in CampingListForm Controller.js line #3 and in CampingListForm Component in line #63 change clickCreateCampingItem to submitForm.
Regards!
All Answers
In campingList Controller.js in lines #31, #32 and #33 change theItems to items
The action button must be submitForm, that is, in CampingListForm Controller.js line #3 and in CampingListForm Component in line #63 change clickCreateCampingItem to submitForm.
Regards!
Still m getting the same issue. can you please provide the solution of this?
Regards!
Parth Joshi
This is my code which I passed the challenge! I hope it helps you.
campingList Component
campingList Controller.js
CampingListController
CampingListForm Component
CampingListForm Controller.js
CampingListForm Helper.js
Regards.
1. campingList Component
<aura:component controller="CampingListController">
<!-- <ol>
<li>Bug Spray</li>
<li>Bear Repellant</li>
<li>Goat Food</li>
</ol> -->
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<aura:handler name="addItem" event="c:addItemEvent" action="{!c.handleAddItem}"/>
<aura:attribute name="newItem" type="Camping_Item__c" required="true" default="{
'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c':0,
'Price__c':0,
'Packed__c':false }"/>
<aura:attribute name="items" type="Camping_Item__c[]"/>
<div class="slds-col slds-col--padded slds-p-top--large">
<c:campingListForm/>
</div>
<div class="slds-grid slds-m-top--large">
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newexpenseform1" class="slds-text-heading--small slds-p-vertical--medium">
Camping List
</legend>
<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>
</fieldset>
</div>
</aura:component>
2. campingList Controller.js
({
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);
}
});
$A.enqueueAction(action);
},
handleAddItem: function(component, event, helper) {
var item = event.getParam("item");
var action = component.get("c.saveItem");
action.setParams({
"campingItem": 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);
},
clickCreateItem : function(component, event, helper) {
var validCamping = true;
// Name must not be blank
var nameField = component.find("name");
var name = nameField.get("v.value");
var quantityField = component.find("quantity");
var quantity = nameField.get("v.value");
var priceField = component.find("price");
var price = nameField.get("v.value");
if ($A.util.isEmpty(name)){
validCamping = false;
nameField.set("v.errors", [{message:"Camping name can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
if ($A.util.isEmpty(quantity)){
validCamping = false;
quantityField.set("v.errors", [{message:"Camping quantity can't be blank."}]);
}
else {
quantityField.set("v.errors", null);
}
if ($A.util.isEmpty(price)){
validCamping = false;
priceField.set("v.errors", [{message:"Camping price can't be blank."}]);
}
else {
priceField.set("v.errors", null);
}
if(validCamping){
var newItem = component.get("v.newItem");
console.log("Create item: " + JSON.stringify(newItem));
// var newItems = component.get("v.items");
//newItems.push(JSON.parse(JSON.stringify(newItem)));
//component.set("v.items", newItems);
helper.createItem(component, newItem);
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c','Name': '','Quantity__c': 0,
'Price__c': 0,'Packed__c': false });
}
}
})
3. CampingListForm Component
<aura:component >
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<div aria-labelledby="newcampingform">
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newexpenseform" class="slds-text-heading--small slds-p-vertical--medium">
Camping
</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="name" label="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"/>
</div>
</div>
<div class="slds-form-element">
<div class="slds-form-element__control">
<ui:inputText aura:id="price" label="Price"
class="slds-input"
labelClass="slds-form-element__label"
value="{!v.newItem.Price__c}"
placeholder="100$."/>
</div>
</div>
<div class="slds-form-element">
<div class="slds-form-element__control">
<ui:inputCheckbox aura:id="reimbursed" label="Packed?"
class="slds-checkbox"
labelClass="slds-form-element__label"
value="{!v.newItem.Packed__c}"/>
</div>
</div>
<div class="slds-form-element">
<ui:button label="Packed!"
class="slds-button slds-button--brand"
press="{!c.submitForm}"/>
</div>
</form>
</fieldset>
</div>
</aura:component>
4. CampingListForm Controller.js
({
submitForm : function(component, event, helper) {
var validCamping = true;
// Name must not be blank
var nameField = component.find("name");
var name = nameField.get("v.value");
var quantityField = component.find("quantity");
var quantity = nameField.get("v.value");
var priceField = component.find("price");
var price = nameField.get("v.value");
if ($A.util.isEmpty(name)){
validCamping = false;
nameField.set("v.errors", [{message:"Camping name can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
if ($A.util.isEmpty(quantity)){
validCamping = false;
quantityField.set("v.errors", [{message:"Camping quantity can't be blank."}]);
}
else {
quantityField.set("v.errors", null);
}
if ($A.util.isEmpty(price)){
validCamping = false;
priceField.set("v.errors", [{message:"Camping price can't be blank."}]);
}
else {
priceField.set("v.errors", null);
}
if(validCamping){
//var newItem = component.get("v.newItem");
//console.log("Create item: " + JSON.stringify(newItem));
// var newItems = component.get("v.items");
//newItems.push(JSON.parse(JSON.stringify(newItem)));
//component.set("v.items", newItems);
helper.createItem(component);
}
}
})
5. CampingListForm Helper.js
({
createItem : function(component) {
var newItem = component.get("v.newItem");
var addEvent = component.getEvent("addItem");
addEvent.setParams({"item" : newItem});
addEvent.fire();
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c','Name': '','Quantity__c': 0,
'Price__c': 0,'Packed__c': false });
}
})
6. Additem Event- Create new Lighting Event
<aura:event type="COMPONENT">
<aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>
7. CampingListController
public with sharing class CampingListController {
@AuraEnabled
public static List<Camping_Item__c> getItems() {
return [SELECT Id, Name, Price__c, Quantity__c, Packed__c FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem(Camping_Item__c item) {
upsert item;
return item;
}
}
Hope it help
Thank you so much for you help. Actually there is one issue in my code so by resolving that passed this challenge.
Failed to save undefined: No EVENT named markup://c:addItemEvent found : [markup://c:CampingListForm]
Thanks
Hope you have not created the event for the component
Create an event ->>>
Let me know if it helped you and if it worked prove it by giving kudos
Thanks
Sangeetha Madrasi
email:sangee.atf@gmail.com
I also ran into this problem and read what challenge asks us to do line by line.
Trailhead challenge do not ask us to call HELPER method from campingListController.js. It just tells us to perform save action in campingListcontroller.js method instead. This is not very intuitive as trailhead module performs saving operation in HELPER method.
Just copy and past the code from campingListHelper.js to campingListController.js to pass the challenge. This is weird but this is how it is.
I hope this would help others.
Thanks,
Akshay
1. CampingListController.js
({
submitForm : function(component, event, helper) {
var validCamping = true;
// Name must not be blank
var nameField = component.find("name");
var name = nameField.get("v.value");
var quantityField = component.find("quantity");
var quantity = nameField.get("v.value");
var priceField = component.find("price");
var price = nameField.get("v.value");
if ($A.util.isEmpty(name)){
validCamping = false;
nameField.set("v.errors", [{message:"Camping name can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
if ($A.util.isEmpty(quantity)){
validCamping = false;
quantityField.set("v.errors", [{message:"Camping quantity can't be blank."}]);
}
else {
quantityField.set("v.errors", null);
}
if ($A.util.isEmpty(price)){
validCamping = false;
priceField.set("v.errors", [{message:"Camping price can't be blank."}]);
}
else {
priceField.set("v.errors", null);
}
if(validCamping){
//var newItem = component.get("v.newItem");
//console.log("Create item: " + JSON.stringify(newItem));
// var newItems = component.get("v.items");
//newItems.push(JSON.parse(JSON.stringify(newItem)));
//component.set("v.items", newItems);
helper.createItem(component);
}
}
})
2. CampingListForm.cmp
<aura:component >
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<div aria-labelledby="newcampingform">
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newexpenseform" class="slds-text-heading--small slds-p-vertical--medium">
Camping
</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="name" label="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"/>
</div>
</div>
<div class="slds-form-element">
<div class="slds-form-element__control">
<ui:inputText aura:id="price" label="Price"
class="slds-input"
labelClass="slds-form-element__label"
value="{!v.newItem.Price__c}"
placeholder="100$."/>
</div>
</div>
<div class="slds-form-element">
<div class="slds-form-element__control">
<ui:inputCheckbox aura:id="reimbursed" label="Packed?"
class="slds-checkbox"
labelClass="slds-form-element__label"
value="{!v.newItem.Packed__c}"/>
</div>
</div>
<div class="slds-form-element">
<ui:button label="Packed!"
class="slds-button slds-button--brand"
press="{!c.submitForm}"/>
</div>
</form>
</fieldset>
</div>
</aura:component>
3.CampingListFormController.js
({
submitForm : function(component, event, helper) {
var validCamping = true;
// Name must not be blank
var nameField = component.find("name");
var name = nameField.get("v.value");
var quantityField = component.find("quantity");
var quantity = nameField.get("v.value");
var priceField = component.find("price");
var price = nameField.get("v.value");
if ($A.util.isEmpty(name)){
validCamping = false;
nameField.set("v.errors", [{message:"Camping name can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
if ($A.util.isEmpty(quantity)){
validCamping = false;
quantityField.set("v.errors", [{message:"Camping quantity can't be blank."}]);
}
else {
quantityField.set("v.errors", null);
}
if ($A.util.isEmpty(price)){
validCamping = false;
priceField.set("v.errors", [{message:"Camping price can't be blank."}]);
}
else {
priceField.set("v.errors", null);
}
if(validCamping){
//var newItem = component.get("v.newItem");
//console.log("Create item: " + JSON.stringify(newItem));
// var newItems = component.get("v.items");
//newItems.push(JSON.parse(JSON.stringify(newItem)));
//component.set("v.items", newItems);
helper.createItem(component);
}
}
})
4. campingListFormHelper.js
({
createItem : function(component) {
var newItem = component.get("v.newItem");
var addEvent = component.getEvent("addItem");
addEvent.setParams({"item" : newItem});
addEvent.fire();
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c','Name': '','Quantity__c': 0,
'Price__c': 0,'Packed__c': false });
}
})
5. CampingListController.apxc
public class CampingListController {
public with sharing class CampingListController {
@AuraEnabled
public static List<Camping_Item__c> getItems() {
return [SELECT Id, Name, Price__c, Quantity__c, Packed__c FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem(Camping_Item__c item) {
upsert item;
return item;
}
}
6. CampingListHelper.js
({
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);
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false });
}
});
$A.enqueueAction(action);
/*var theItems = component.get("v.items");
// Copy the expense to a new object
// THIS IS A DISGUSTING, TEMPORARY HACK
var newItem = JSON.parse(JSON.stringify(item));
theItems.push(newItem);
component.set("v.items", theItems);
console.log('theItems helper==',theItems);*/
},
validateItemForm: function(component) {
// Simplistic error checking
var validExpense = true;
// Name must not be blank
var fld = component.find("ciName");
var fldVal = fld.get("v.value");
if ($A.util.isEmpty(fldVal)){
validExpense = false;
fld.set("v.errors", [{message:"Name can't be blank."}]);
}
else {
fld.set("v.errors", null);
}
// Amount must be set, must be a positive number
var quantFld = component.find("ciQuantity");
var quantFldVal = quantFld.get("v.value");
if ($A.util.isEmpty(quantFldVal) || isNaN(quantFldVal) || (quantFldVal <= 0.0)){
validExpense = false;
quantFld.set("v.errors", [{message:"Enter qunatity."}]);
}
else {
// If the amount looks good, unset any errors...
quantFld.set("v.errors", null);
}
// Amount must be set, must be a positive number
var priceFld = component.find("ciPrice");
var priceFldVal = priceFld.get("v.value");
if ($A.util.isEmpty(priceFldVal) || isNaN(priceFldVal) || (priceFldVal <= 0.0)){
validExpense = false;
priceFld.set("v.errors", [{message:"Enter price."}]);
}
else {
// If the amount looks good, unset any errors...
priceFld.set("v.errors", null);
}
return(validExpense);
}
})
7. Add Event (I named it Component)
<aura:event type="COMPONENT">
<aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>
Any help will be useful.
Challenge Not yet complete... here's what's wrong:
The campingList JavaScript controller isn't calling the helper's 'createItem' function.
({
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());
}
});
$A.enqueueAction(action);
},
CreateCamping : function(component, event, helper){
helper.validateFields (component,component.find("name"));
helper.validateFields (component,component.find("Price"));
helper.validateFields (component,component.find("Quantity"));
if(component.get("v.er") === false)
{
//Here I removed the lines and shifted the code to the helperJs
console.log('Before:'+Items);
helper.CreateCampaign(component,Items);
console.log('After:'+Items);
}
}
})
I'm struggling to pass the challenge. I tried Akshay's suggestion, but I get the error, "The campingList component isn't handing the added item correctly."
Can you share your code so I can compare?
Here's a version with the additional changes that were made to the expenses example in the main article.
Camping
Harness
<aura:application extends="force:slds" implements="force:hasRecordID"><c:camping />
</aura:application>
camping.cmp
<aura:component controller="CampingListController"><!-- https://trailhead.salesforce.com/modules/lex_dev_lc_basics/units/lex_dev_lc_basics_events -->
<!-- the Apex server side controller -->
<aura:attribute name="items" type="Camping_Item__c[]"/>
<c:campingHeader />
<c:campingList items="{!v.items}"/>
</aura:component>
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}"/>
<!-- use same type of event -->
<aura:handler name="updateItem" event="c:addItemEvent"
action="{!c.handleUpdateItem}"/>
<!-- FORM AREA -->
<div aria-labelledby="newitemform">
<fieldset class="slds-box slds-theme--default slds-container--small">
<c:campingListForm />
</fieldset>
</div>
<!-- / FORM AREA -->
<aura:attribute name="items" type="Camping_Item__c[]"/>
<!-- / LIST AREA -->
<div class ="slds-card slds-p-top--medium">
<header class ="slds-card__header">
<h3 class = "slds-text-heading--small">Existing Camping List 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.js
({
// Load camping items from Salesforce
doInit: function(component, event, helper) {
console.log("call c.getItems: ");
// Create the action
var action = component.get("c.getItems");
console.log("back from 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);
}, //doInit
handleAddItem: function(component, event, helper) {
var newItem = event.getParam("item");
helper.addItem(component, newItem);
/*
var action = component.get("c.saveItem");
action.setParams({
"item": newItem
});
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);
*/
},
handleUpdateItem: function(component, event, helper) {
var updatedItem = event.getParam("item");
helper.updateItem(component, updatedItem);
}
})
campingListHelper.js
({
addItem: function(component, campItem) {
/* old version
var action = component.get("c.addItem");
action.setParams({ "campItem": 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);
*/
this.saveItem(component, campItem, function(response){
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
var expenses = component.get("v.items");
expenses.push(response.getReturnValue());
component.set("v.items", items);
}
});
},//addItem
//server side action defined in CampingListController
updateItem: function(component, item) {
this.saveItem(component, item);
},
saveItem: function(component, expense, callback) {
var action = component.get("c.saveItem");
action.setParams({
"item": item
});
if (callback) {
action.setCallback(this, callback);
}
$A.enqueueAction(action);
},//saveItem
validateCampingItem: function(component, item) {
// Simplistic error checking
var validItem = true;
console.log("validate item");
// Name must not be blank
var nameField = component.find("campItemName");
var itemname = nameField.get("v.value");
console.log("itemname="+itemname);
if ($A.util.isEmpty(itemname)){
validItem = false;
nameField.set("v.errors", [{message:"Item name can't be blank."}]);
}
else {
console.log("good name "+itemname);
nameField.set("v.errors", null);
}
// Price must not be blank
var priceField = component.find("price");
var itemprice = priceField.get("v.value");
console.log("itemprice="+itemprice);
if (isNaN(itemprice)){
validItem = false;
priceField.set("v.errors", [{message:"Item price can't be null."}]);
}
else {
priceField.set("v.errors", null);
}
if ($A.util.isEmpty(itemprice)){
validItem = false;
priceField.set("v.errors", [{message:"Item price can't be null."}]);
}
else {
priceField.set("v.errors", null);
}
if (itemprice<0.01){
validItem = false;
priceField.set("v.errors", [{message:"Item price can't be zero."}]);
}
else {
priceField.set("v.errors", null);
}
// Quantity must not be blank
var qtyField = component.find("quantity");
var itemqty = qtyField.get("v.value");
console.log("itemqty ="+itemqty);
console.log("now check empty"+qtyField);
if (isNaN(itemqty)){
console.log("bad qty ="+itemqty);
validItem = false;
qtyField.set("v.errors", [{message:"Item quantity can't be null."}]);
}
else {
console.log("good");
qtyField.set("v.errors", null);
}
if ($A.util.isEmpty(itemqty)){
console.log("bad qty ="+itemqty);
validItem = false;
qtyField.set("v.errors", [{message:"Item quantity can't be null."}]);
}
else {
console.log("good");
qtyField.set("v.errors", null);
}
if (itemqty<1){
console.log("bad qty <1 ="+itemqty);
validItem = false;
qtyField.set("v.errors", [{message:"Enter an Item quantity."}]);
}
else {
console.log("good");
qtyField.set("v.errors", null);
}
return(validItem);
} //validateCampingItem
})
campingHeader.cmp
<aura:component ><!-- PAGE HEADER -->
<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">My Camping Items</h1>
</div>
</div>
</div>
<!-- / PAGE HEADER -->
</aura:component>
campingHeader.css
.THIS {}
p.THIS {
font-size: 18px;
}
campingListItem.cmp
<aura:component >
<aura:attribute name="item" type="Camping_Item__c"/>
<!-- use same event type or package format 'structure' to add or update -->
<aura:registerEvent name="updateItem" type="c:addItemEvent"/>
<!-- this component can send/fire events -->
<!-- campingList receives and handles it -->
<!-- SLDS markup to give style -->
<div class="slds-card">
<!-- Color the item green if the expense is reimbursed -->
<div class="{!v.item.Packed__c == true ?
'slds-theme--success' : 'slds-theme--warning'}">
<header class="slds-card__header slds-grid grid--flex-spread">
<a aura:id="item" href="{!'/' + v.item.Id}">
<h3>{!v.item.Name}</h3>
</a>
</header>
<section class="slds-card__body">
<div class="slds-tile slds-hint-parent">
<!--<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}"/>-->
<ui:inputCheckbox value="{!v.item.Packed__c}"
click="{!c.clickPacked}"/>
</p>
<!-- SLDS markup to give style -->
</div>
</section>
</div>
</div>
</aura:component>
campingListItemController.js
({
dummy: function(component, event, helper) {
},
clickPacked: function(component, event, helper) {
var campingItem = component.get("v.item");
var updateEvent = component.getEvent("updateItem");
updateEvent.setParams({ "item": campingItem });
updateEvent.fire();
}
})
...more to follow
campingListForm.js
<aura:component >
<aura:attribute name="newItem" type="Camping_Item__c"
default="{'sobjectType' : 'Camping_Item__c',
'Name':'',
'Quantity__c' : '',
'Price__c' : ''}"/>
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<!-- CREATE NEW CAMPING ITEM FORM -->
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newitemform" class="slds-text-heading--small
slds-p-vertical--medium">
Add a Camping 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="campItemName" label="Camping 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"/>
</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}"/>
</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="Create Camping Item"
class="slds-button slds-button--brand"
press="{!c.submitForm}"/>
</div>
</form>
</fieldset>
<!-- / CREATE NEW CAMPING ITEM FORM -->
</aura:component>
campingListFormController.js
({
myAction : function(component, event, helper) {
},
handleAddItem: function(component, event, helper) {
var newItem = event.getParam("item");
helper.addItem(component, newItem);
},
submitForm: function(component, event, helper) {
console.log('submit if valid');
var nameField = component.find("campItemName");
console.log('nameField='+nameField+'<<<');
var itemname = nameField.get("v.value");
console.log('itemname='+itemname+'<<<');
console.log('submit if valid...');
if(helper.validateCampingListForm(component)){
console.log('valid so add');
// Add the new item
//var newItem = component.get("v.newItem"); //created in helper
//helper.addItem(component, newItem);
helper.createItem(component);
}
},
})
campingListFormHelper.js
({
helperMethod : function() {
},
validateCampingListForm: function(component) {
var validItem = true;
// Name must not be blank (aura id)
var nameField = component.find("campItemName");
console.log('nameField='+nameField+'<<<');
var itemname = nameField.get("v.value");
console.log('itemname='+itemname+'<<<');
if ($A.util.isEmpty(itemname)){
validItem = false;
nameField.set("v.errors", [{message:"Item name can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
// Quantity must be set, must be a positive number
var amtField = component.find("quantity");
console.log('qtyField='+amtField+'<<<');
var amt = amtField.get("v.value");
console.log('quantity='+amt+'<<<');
if ($A.util.isEmpty(amt) || isNaN(amt) || (amt <= 0.0)){
validItem = false;
amtField.set("v.errors", [{message:"Enter an item quantity."}]);
}
else {
// If the quantity looks good, unset any errors...
amtField.set("v.errors", null);
}
//also do price
//Price must be set, must be a positive number
amtField = component.find("price");
console.log('priceField='+amtField+'<<<');
amt = amtField.get("v.value");
console.log('price='+amt+'<<<');
if ($A.util.isEmpty(amt) || isNaN(amt) || (amt <= 0.0)){
validItem = false;
amtField.set("v.errors", [{message:"Enter an item price."}]);
}
else {
// If the price looks good, unset any errors...
amtField.set("v.errors", null);
}
console.log('validItem='+validItem+'<<<');
return(validItem);
},//validateCampingListForm
createItem: function(component, newItem) {
console.log('in addItem');
var newItem = component.get("v.newItem");
var addEvent = component.getEvent("addItem");
addEvent.setParams({"item" : newItem});
addEvent.fire();
//component.set("v.newItem", default);
component.set("v.newItem",{'sobjectType':'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false});
},//addItem
})
campingListController.apxc
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', 'Quantity__c', 'Price__c', 'Packed__c' };
system.debug('fields: '+fieldsToCheck);
Map<String,Schema.SObjectField> fieldDescribeTokens =
Schema.SObjectType.Camping_Item__c.fields.getMap();
system.debug('map: '+fieldDescribeTokens);
for(String field : fieldsToCheck) {
if( ! fieldDescribeTokens.get(field).getDescribe().isAccessible()) {
throw new System.NoAccessException();
return null;
}
}
/*
//temp for debug
List<Camping_Item__c> checklist = [SELECT Id, Name, Quantity__c, Price__c, Packed__c
FROM Camping_Item__c];
system.debug(checklist);
*/
// OK, they're cool, let 'em through
return [SELECT Id, Name, Quantity__c, Price__c, Packed__c
FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem(Camping_Item__c item) {
system.debug('campitem = '+item);
// Perform isUpdatable() checking first, then
upsert item;
return item;
}
}
addItemEvent.evt
<aura:event type="COMPONENT">
<aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>
@Guiomar Fernández de Bobadilla:
I tried your solution posted on June 17th 2016 and keep getting this error message while trying to save the campingListForm component and
campingList component. Can anybody point me to where/how to create this addItemEvent ??
This is regarding the below lightning trailhead. Have found a solution towards it. Hope it helps upcoming future trailhead learners as well.
CampingList.cmp:
<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}"/>
<!-- Page Header -->
<div class="slds-page-header" role="banner" >
<div class="slds-grid">
<div class="slds-col" >
<h1 class="slds-text-heading--medium">Camping List</h1>
</div>
</div>
</div>
<!--/ Page Header -->
<!-- New Camping Form -->
<c:campingListForm />
<!--/ New Camping Form -->
<!-- Camping List Items -->
<aura:iteration items="{!v.items}" var="itm">
<c:campingListItem item="{!itm}"/><br/>
</aura:iteration>
CampingListController.js:
({
//-- Load Camping list Items.
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());
console.log("doInit: "+response.getReturnValue());
}
});
//-- Send action off to be execute.
$A.enqueueAction(action);
},
//-- Handle Create Expense Actions..
handleAddItem: function(component, event, helper)
{
console.log("\nEntry into CampingListController.js -> handleAddItem()");
var item = event.getParam("item");
console.log("\nCampingListController.js -> handleAddItem() item: "+ JSON.stringify(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");
console.log("Campaigns(items..) before create: "+JSON.stringify(items));
items.push(response.getReturnValue());
console.log("Campaigns(items..) after create: "+JSON.stringify(items));
component.set("v.items",items);
}
});
$A.enqueueAction(action);
}
/*handleAddItem: function(component, event, helper)
{
console.log("\nEntry into CampingListController.js -> handleAddItem()");
var newItem = event.getParam("item");
console.log("\nCampingListController.js -> handleAddItem()\n the Item: "+ JSON.stringify(newItem));
helper.createItem(component, newItem);
}*/
})
CampingListController.apxc (apex):
public with sharing class CampingListController
{
@AuraEnabled
public static List<Camping_Item__c> getItems()
{
String[] fieldsToCheck = new String[]{'Id','Name','Packed__c','Price__c','Quantity__c'};
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();
return null;
}
}
return [SELECT Id,Name,Packed__c,Price__c,Quantity__c FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem(Camping_Item__c item)
{
System.debug('Campaign List Item from Apex: '+item);
upsert item;
System.debug('Campaign List Item from Apex Id: '+item.Id);
return item;
}
}
CampingListForm.cmp:
<aura:component controller="CampingListController" >
<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"/>
<!-- New Camping Form-->
<div class="slds-col slds-col--padded slds-p-top--large" >
<!-- Boxed Area-->
<fieldset class="slds-box slds-theme--default slds-container--small">
<legend id="newexpenseform" class="slds-text-heading--small" >
Add Camping List
</legend>
<!-- Create New Expense Form -->
<form class="slds-form--stacked">
<!-- Name -->
<div class="slds-form-element slds-is-required" >
<div class="slds-form-element__control" >
<lightning:input aura:id="itemform"
label="Name"
name="itemname"
value="{!v.newItem.Name}"
required="true"/>
</div>
</div>
<!-- Quantity -->
<div class="slds-form-element__label" >
<div class="slds-form-element__control" >
<lightning:input type="number"
aura:id="itemform"
label="Quantity"
name="quantity"
value="{!v.newItem.Quantity__c}"
min="1"
required="true"/>
</div>
</div>
<!-- Price -->
<div class="slds-form-element slds-is-required" >
<div class="slds-form-element__control" >
<lightning:input type="number"
aura:id="itemform"
label="Price"
name="price"
value="{!v.newItem.Price__c}"
formatter="currency"
step="0.01"/>
</div>
</div>
<!-- Packed -->
<div class="slds-form-element" >
<lightning:input type="checkbox"
aura:id="itemform"
label="Packed?"
name="packed"
checked="{!v.newItem.Packed__c}"/>
</div>
<!-- Button Create Expense -->
<div class="slds-form-element">
<lightning:button label="Create Camping Item"
variant="brand"
onclick="{!c.clickCreateItem}"/>
</div>
</form>
<!--/ Create New Expense Form -->
</fieldset>
<!--/ Boxed Area-->
</div>
<!--/ New Camping Form-->
</aura:component>
CampingListFormController.js:
({
clickCreateItem : function(component, event, helper)
{
//-- Simplistic error checking.
console.log("\nIn CampingListFormController.js -> submitForm()");
var validCampign = true;
//-- Name must not be blank.
var nameField = component.find("name");
var campaignname = nameField.get("v.value");
if($A.util.isEmpty(campaignname))
{
validCampign = false;
nameField.set("v.errors",[{message: "Camping name can't be blank."}]);
}
else
{
nameField.set("v.errors",null);
}
//-- Quantity must not be blank.
var qtyField = component.find("quantity");
var quantity = qtyField.get("v.value");
if($A.util.isEmpty(quantity))
{
validCampign = false;
qtyField.set("v.errors",[{message: "Quantity can't be blank."}]);
}
else
{
qtyField.set("v.errors",null);
}
//-- Price must not be blank
var priceField = component.find("price");
var price = priceField.get("v.value");
if($A.util.isEmpty(price))
{
validCampign = false;
priceField.set("v.errors",[{message: "Price can't be blank."}]);
}
else
{
priceField.set("v.errors",null);
}
//-- If we pass error checking, do some real work.
if(validCampign)
{
//-- Create the new expense.
var newCampaign = component.get("v.newItem");
console.log("In CampingListFormController.js -> submitForm()\n The Item: " + JSON.stringify(newCampaign));
helper.createItem(component, newCampaign);
}
}
})
CampingListFormHelper.js:
({
createItem : function(component,item)
{
console.log("\nEntry into CampingListFormHelper.js -> createItem()");
console.log("In CampingListFormHelper.js -> createItem() the item is: "+JSON.stringify(item));
var createEvent = component.getEvent("addItem");
createEvent.setParams({ "item": item });
createEvent.fire();
component.set("v.newItem",{'sobjectType':'Camping_Item__c','Name': '','Quantity__c': 0,'Price__c': 0,'Packed__c': false});
}
})
CampingApplication.app:
<aura:application extends="force:slds">
<c:campingHeader />
<c:campingList />
</aura:application>
CampingListHelper.js:
({
createItem : function(component,campaign)
{
console.log("\nEntry into CampingListHelper.js -> createItem()");
console.log("\nCampingListHelper.js -> createItem()\n the Item: "+ JSON.stringify(campaign));
this.saveItem(component, campaign, function(response)
{
var state = response.getState();
if (component.isValid() && state === "SUCCESS")
{
var campaigns = component.get("v.items");
console.log("Campaigns before create: "+JSON.stringify(campaigns));
var retcamp = response.getReturnValue();
campaigns.push(retcamp);
console.log("Campaigns after create: "+JSON.stringify(campaigns));
component.set("v.items",campaigns);
}
});
},
saveItem : function(component,campaign,callback)
{
console.log("\nEntry into CampingListHelper.js -> saveItem()");
console.log("\nCampingListHelper.js -> saveItem() the campaign is: "+ JSON.stringify(campaign));
var action = component.get("c.saveItem");
console.log("Helper->saveItems"+campaign);
action.setParams
({
"campaign": campaign
});
if (callback)
{
action.setCallback(this, callback);
}
$A.enqueueAction(action);
}
})
Reference Links:
1) https://developer.salesforce.com/forums/ForumsMain?id=906F0000000kDmtIAE
2) https://salesforce.stackexchange.com/questions/149023/facing-problem-with-trailhead-lightning-module-challenge-connect-components-wit
3) https://salesforce.stackexchange.com/questions/192815/how-can-i-use-lightninginput-instead-of-uiinputsmthg-for-the-challenge-ente
4) https://salesforce.stackexchange.com/questions/191861/the-campinglist-component-appears-to-be-using-ui-components-instead-of-base-ligh
Hope you find this comment useful and clear this trailhead successfully. All the best.
Regards,
Muthukumaran K
Consultant (Salesforce)
Your code worked, and allowed me to pass the challenge.
Hope this helps.
addItemEvent.evt (Lightning Event)
CampingListController.apxc (Apex Class)
campingListForm.cmp (Lightning Component)
campingListFormController.js (Lightning Component Controller)
campingListFormHelper.js (Lightning Component Helper)
campingList.cmp (Lightning Component)
campingListController.js (Lightning Component Controller)
campingListHelper.js (Lightning Component Helper)
Happy trailblazing.
Regards,
Vineeth Batreddy
the code itself works yet i get an error of :
Challenge Not yet complete... here's what's wrong:
The campingList component doesn't appear to have a Quantity input field in the form using a Lightning Base component.
i guess its a default message for somthing else, any suggestion will be appreciated, i am posting my classes below,
CampingList.cmp
<aura:component controller="CampingListController">
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<aura:handler name="addItem" event="c:addItemEvent" action="{!c.handleAddItem}"/>
<aura:attribute name="items" type="Camping_Item__c[]"/>
<div class="slds-col slds-col--padded slds-p-top--small">
<c:campingListForm />
</div>
<br/>
<section class="slds-card__body">
<div id="list" class="row">
<aura:iteration items="{!v.items}" var="PerItem">
<c:campingListItem item="{!PerItem}"/>
</aura:iteration>
</div>
</section>
</aura:component>
CampingList(Controller).js (helper - is empty)
({
doInit : function(component, event, helper)
{
var action = component.get("c.getItems"); // c of apex controller
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 action = component.get("c.saveItem");
var item = event.getParam("item");
var lstItems = component.get("v.items");
action.setParams({"item":item});
action.setCallback(this,function(response)
{
var state = response.getState();
if (component.isValid() && state === "SUCCESS")
{
lstItems.push(item);
component.set("v.items",lstItems);
console.log("After:"+lstItems);
}
});
$A.enqueueAction(action);
},
})
CampingListForm.cmp
<aura:component >
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<aura:attribute name="er" type="boolean" default="false"/>
<aura:attribute name="newItem" type="Camping_Item__c" default="{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Price__c': 0,
'Quantity__c': 0,
'Packed__c': false}"/>
<form class="slds-form--stacked">
<lightning:input aura:id="Name" label="Camping Name"
name="name"
value="{!v.newItem.Name}"
required="true"/>
<lightning:input type="toggle" aura:id="Packed" label="Packed?"
name="Packed"
checked="{!v.newItem.Packed__c}"/>
<lightning:input type="number" aura:id="Price" label="Price"
name="Price"
min="0.1"
formatter="currency"
step="0.01"
value="{!v.newItem.Price__c}"
messageWhenRangeUnderflow="Enter an amount that's at least $0.10."/>
<lightning:input type="number" aura:id="Quantity" label="Quantity"
name="Quantity"
value="{!v.newItem.Quantity__c}"
placeholder="ABC Co."/>
<lightning:button label="Create Camping"
class="slds-m-top--medium"
variant="brand"
onclick="{!c.clickCreateItem}"/>
</form>
</aura:component>
CampingListForm(Controller).js
({
clickCreateItem: function(component, event, helper) {
var a = component.get("v.newItem");
helper.validateFields (component,component.find("Name"));
helper.validateFields (component,component.find("Price"));
helper.validateFields (component,component.find("Quantity"));
var er = component.get("v.er");
console.log(er);
if(!er)
{
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 });
},
})
CampingListForm(Helper).js
({
CreateItem : function(component, newItem)
{
// creating event setting its parameters and fires it
var createEvent = component.getEvent("addItem");
// cleaning from fields
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false });
createEvent.setParams({ "item": newItem });
createEvent.fire();
},
validateFields : function (component,field) {
var nameField = field;
console.log('yes:'+nameField);
var fieldname = nameField.get("v.value");
if ($A.util.isEmpty(fieldname))
{
console.log('found empty nameField' + fieldname);
component.set("v.er",true);
nameField.set("v.errors", [{message:"this field can't be blank."}]);
}
else
{
console.log('found nameField' + fieldname);
nameField.set("v.errors", null);
}
},
})
CampingListItem.cmp
<aura:component >
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<aura:attribute type="Camping_Item__c" name="item" required="true"/>
Name:
<lightning:formattedText value="{!v.item.Name}" /><br/>
Price:
<lightning:formattedNumber value="{!v.item.Price__c}" style="currency"/><br/>
Quantity:
<lightning:formattedNumber value="{!v.item.Quantity__c}" /><br/>
Packed:
<lightning:input type="toggle"
label="Packed?"
name="Packed"
class="slds-p-around--small"
checked="{!v.item.Packed__c}"
messageToggleActive="Yes"
messageToggleInactive="No"
onchange="{!c.packItem}"/>
</aura:component>
CampingListController.apxc
public with sharing class CampingListController {
@AuraEnabled
public static List<Camping_Item__c> getItems() {
return [SELECT Id, Name, price__c, Quantity__c, Packed__c
FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem(Camping_Item__c item) {
system.debug('^^^the new item '+item);
upsert item;
return item;
}
}
and camping class that includes campingHeader and campingList
and i start it from harness.app
thank you
Naeh Orchay
many thanks :)
Naeh Orchay
campingListController.js
campingListHelper.js
campingListForm.cmp
campingListFormController.js
campingListFormHelper.js
addItemEvent.evt
It will work.
i got this error, please help
"Connect Components with Events"
addItemEvent:
____________________________________________________________________________
<aura:event type="COMPONENT">
<aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>
-----------------------------------------------------------------------------------------------------------------------------------------
campingListForm.cmp:
<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"/>
<form class="slds-form--stacked">
<div class="slds-form-element slds-is-required">
<div class="slds-form-element__control">
<lightning:input aura:id="itemname" label="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">
<lightning:input aura:id="quantity" label="Quantity"
class="slds-input"
labelClass="slds-form-element__label"
value="{!v.newItem.Quantity__c}"
required="true"/>
</div>
</div>
<div class="slds-form-element">
<div class="slds-form-element__control">
<lightning:input aura:id="price" label="Price"
class="slds-input"
labelClass="slds-form-element__label"
value="{!v.newItem.Price__c}"
/>
</div>
</div>
<div class="slds-form-element">
<lightning:input aura:id="packed" label="Packed?"
class="slds-checkbox"
labelClass="slds-form-element__label"
value="{!v.newItem.Packed__c}"/>
</div>
<div class="slds-form-element">
<lightning:input label="Create Camping Item"
class="slds-button slds-button--brand"
press="{!c.submitForm}"/>
</div>
</form>
</aura:component>
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
campingListFormController.js:
({
submitForm: function(component, event, helper) {
if(helper.validateItemForm(component)){
// Create the new item
var newItem = component.get("v.newItem");
helper.createItem(component, newItem);
}
}
})
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
campingListFormHelper.js:
({
addItem: function(component, newItem) {
var addItem = component.getItem("addItem");
addItem.setParams({ "item": item });
addItem.fire();
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false } );
},
validateItemForm: function(component) {
var validItem = true;
var nameField = component.find("itemname");
var itemname = nameField.get("v.value");
if ($A.util.isEmpty(itemname)){
validItem = false;
nameField.set("v.errors", [{message:"Item name can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
var quantityField = component.find("quantity");
var quantity = nameField.get("v.value");
if ($A.util.isEmpty(quantity)){
validItem = false;
quantityField.set("v.errors", [{message:"Quantity can't be blank."}]);
}
else {
quantityField.set("v.errors", null);
}
var priceField = component.find("price");
var price = priceField.get("v.value");
if ($A.util.isEmpty(price)){
validItem = false;
priceField.set("v.errors", [{message:"Price can't be blank."}]);
}
else {
quantityField.set("v.errors", null);
}
return (validItem);
}
})
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
campingListController.apxc:
public with sharing class CampingListController {
@auraenabled
public static List<Camping_Item__c> getItems (){
List<Camping_Item__c> CI = [select id, name,price__c,Quantity__c,Packed__c from Camping_Item__c ];
return CI;
}
@auraenabled
public static Camping_Item__c saveItem (Camping_Item__c item){
insert item;
return item;
}
}
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
campingList.cmp:
<aura:component controller="CampingListController">
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<aura:handler name="addItem"
event="c:addItemEvent"
action="{!c.handleAddItem }"/>
<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'}"/>
<form class="slds-form--stacked">
<lightning:input aura:id= "cmpform" label="Name" name= "itemname" value="{!v.newItem.Name}"/>
<lightning:input aura:id= "cmpform" label="Quantity" name="itemquantity"
value="{!v.newItem.Quantity__c}" type="number" min= "1"/>
<lightning:input aura:id= "cmpform" label="Price" name="itemprice" value="{!v.newItem.Price__c}"
formatter="currency"/>
<lightning:input type="checkbox" aura:id="cmpform" label="Packed?"
checked="{!v.newItem.Packed__c}"/>
<lightning:button label="Submit" onclick="{!c.clickCreateItem}"/>
</form>
<aura:iteration items="{!v.items}" var="itm">
<c:campingListItem item="{!itm}"/><br/>
</aura:iteration>,
</aura:component>
addItemEvent Event
<aura:event type="COMPONENT" description="Event template" >
<aura:attribute name="item" type="Camping_Item__c"/>
</aura:event>
-------------------------------------------------------------------------------------------------------
campingListForm CMP
<aura:component >
<aura:registerEvent name="addItem" type="c:addItemEvent"/>
<!-- 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="itemname" 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 type="number" min="1" aura:id="quantity" label="Quantity"
value="{!v.newItem.Quantity__c}"
required="true"/>
</div>
</div>
<div class="slds-form-element">
<div class="slds-form-element__control">
<lightning:input aura:id="price" label="Price" Formatter="currency"
value="{!v.newItem.Price__c}"
/>
</div>
</div>
<div class="slds-form-element">
<lightning:input aura:id="packed" label="Packed?" type="checkbox"
checked="{!v.newItem.Packed__c}" value="{!v.newItem.Packed__c}"/>
</div>
<div class="slds-form-element">
<lightning:input label="Create Camping Item"
class="slds-button slds-button--brand"
onclick="{!c.clickCreateItem}"/>
</div>
</form>
<!-- / CREATE NEW ITEM FORM -->
</aura:component>
---------------------------------------------------------------------------------------------
campingListForm Controller
({
submitForm : function(component, event, helper) {
var validCamping = true;
// Name must not be blank
var nameField = component.find("name");
var expname = nameField.get("v.value");
if ($A.util.isEmpty(expname)){
validCamping = false;
nameField.set("v.errors", [{message:"Camping Item name can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
var priceField = component.find("price");
var price = priceField.get("v.value");
if ($A.util.isEmpty(price) || isNaN(price) || (price <= 0.0)){
validCamping = false;
priceField.set("v.errors", [{message:"Camping Item price can't be blank."}]);
}
else {
priceField.set("v.errors", null);
}
var quantityField = component.find("quantity");
var quantity = quantityField.get("v.value");
if ($A.util.isEmpty(quantity) || isNaN(quantity) || (quantity <= 0)){
validCamping = false;
quantityField.set("v.errors", [{message:"Camping Item quantity can't be blank."}]);
}
else {
quantityField.set("v.errors", null);
}
if(validCamping){
helper.createItem(component);
}
},
})
--------------------------------------------------------------------------------------------------------------
campingListForm Helper
({
createItem : function(component) {
var newItem = component.get("v.newItem");
var addEvent = component.getEvent("addItem");
addEvent.setParams({"item" : newItem});
addEvent.fire();
component.set("v.newItem",
{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Packed__c': false,
'Price__c': 0,
'Quantity__c': 0});
}
})
-----------------------------------------------------------------------------------------------------------
campingList Component
<aura:component controller="CampingListController">
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<aura:handler name="addItem" event="c:addItemEvent" action="{!c.handleAddItem}"/>
<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">My Camping Items</h1>
</div>
</div>
</div>
<div aria-labelledby="newitemform">
<fieldset class="slds-box slds-theme--default slds-container--small">
<c:campingListForm />
</fieldset>
</div>
<aura:attribute name="items" type="Camping_Item__c[]"/>
<div class="slds-card slds-p-top--medium">
<header class="slds-card__header">
<h3 class="slds-text-heading--small">Camping List Items</h3>
</header>
<section class="slds-card__body">
<div id="list" class="row">
<aura:iteration items="{!v.items}" var="campItem">
<c:campingListItem item="{!campItem}"/>
</aura:iteration>
</div>
</section>
</div>
</aura:component>
---------------------------------------------------------------------------
campingList Controller
({
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");
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);
}
})
----------------------------------------------------------------------------------------------------------
campingList Helper
({
validateFields : function (component,field) {
var nameField = field;
var expname = nameField.get("v.value");
if ($A.util.isEmpty(expname)){
component.set("v.er",true);
nameField.set("v.errors", [{message:"this field can't be blank."}]);
}
else {
nameField.set("v.errors", null);
}
},
createItem : function (component,Item){
var action = component.get("c.saveItem");
action.setParams({"CampingItem":Item});
action.setCallback(this,function(response){
var state = response.getState();
if (component.isValid() && state === "SUCCESS") {
console.log('save');
}
});
$A.enqueueAction(action);
//Below lines are shifted from controller Js to helperJs
var Items = component.get("v.items");
var Item = component.get("v.newItem");
Items.push(Item);
component.set("v.items",Items);
component.set("v.newItem",{ 'sobjectType': 'Camping_Item__c',
'Name': '',
'Quantity__c': 0,
'Price__c': 0,
'Packed__c': false });
}
})
-------------------------------------------------------
CampingListController Class
public with sharing class CampingListController {
@AuraEnabled
public static List<Camping_Item__c> getItems() {
return [SELECT Id, Name, Price__c, Quantity__c, Packed__c FROM Camping_Item__c];
}
@AuraEnabled
public static Camping_Item__c saveItem(Camping_Item__c item) {
upsert item;
return item;
}
}
The campingList component appears to be using UI Components instead of Base Lightning Components in the form. You should be using only Base Lightning Components.
please help me to complete this task
How should i create the CampingListController
i show an error like this: duplicate value found: <unknown> duplicates value on record with id: <unknown>
while create the CampingListController
Hi All, Tried several codes but getting below error -
The campingList component appears to be using UI Components instead of Base Lightning Components in the form. You should be using only Base Lightning Components.
can you please help me.