You need to sign in to do that
Don't have an account?
Lightning Components Basics: Handle Actions with Controllers
<!--campingListItem.cmp--> <aura:component > <aura:attribute name="item" type="Camping_Item__c" required="true"/> <ui:outputText value="{!v.item.Name}" /> <ui:outputCheckbox value="{!v.item.Packed__c}" /> <ui:outputCurrency value="{!v.item.Price__c}" /> <ui:outputNumber value="{!v.item.Quantity__c}" /> <ui:button label="Packed!" press="{!c.packItem}"/> </aura:component>
<!--campingListController.js--> ({ packItem : function(component, event, helper) { var button = event.getSource().get("v.disabled"); component.set("v.item.Packed__c", "true"); component.set(button, "true"); } })What am I doing wrong?
packItem: function(component, event, helper) {
var a = component.get("v.item",true);
a.Packed__c = true;
component.set("v.item",a);
var btnClicked = event.getSource();
btnClicked.set("v.disabled",true);
}
})
All Answers
I think that the controller should be a bit different, like this.
I tested this code and it works, checks the Packed and get the button disabled, but the challenge gives me the error:
Challenge Not yet complete... here's what's wrong:
The campingListItem JavaScript controller isn't setting the 'Packed' value correctly.
packItem: function(component, event, helper) {
var a = component.get("v.item",true);
a.Packed__c = true;
component.set("v.item",a);
var btnClicked = event.getSource();
btnClicked.set("v.disabled",true);
}
})
This is complete code to pass the challenge:
Component:
<aura:component implements="force:appHostable">
<aura:attribute name="item" type="Camping_Item__c"/>
<p><ui:outputText value="{!v.item}"/></p>
<div>
<ui:button label="Packed!" press="{!c.packItem}"/>
</div>
</aura:component>
Controller:
({
packItem : function(component, event, helper) {
var itm = component.get("v.item",true);
itm.Packed__c = true;
component.set("v.item",itm);
var btnClicked = event.getSource();
btnClicked.set("v.disabled",true);
}
})
Thanks,
Ghulam
({
packItem : function(component, event, helper) {
event.getSource().set("v.disabled",true); // set the button to disabled
component.set("v.item.Packed__c", true); // set the item's packed field to true
}
})
I tried to use the both ways, and they are work absolutely. Of cause they are right codes, but if you want to pass the challenge, you must use get-set to do that.
So then Ian`s answer is best in this challenge.
<aura:component >
<aura:attribute name="item" type="Camping_Item__c" required="TRUE" default="{ 'sobjectType': 'Camping_Item__c',
'Packed__c': false, 'Name' : 'xyz', 'Quantity__c' : 100, 'Price__c' : 0}"/>
Component :-
<p>Name : <ui:outputText value="{!v.item.Name}" /></p>
<p>Price : <ui:outputCurrency value="{!v.item.Price__c}" /></p>
<p>Quantity : <ui:outputNumber value="{!v.item.Quantity__c}" /></p>
<p>Packed : <ui:outputCheckbox value="{!v.item.Packed__c}" /></p>
<p><ui:button label="Packed!" press="{!c.packItem}" /></p>
</aura:component>
---------------------------------------------------------------------------------------------------------------------------
Controller :-
({
packItem : function(component, event, helper) {
var a = component.get("v.item","True");
a.Name = "Item 1" ;
a.Packed__c = true ;
a.Quantity__c = 1000;
a.Price__c = 2222;
component.set("v.item",a);
var btnClicked = event.getSource();
btnClicked.set("v.disabled",true);
}
})
Please like If you find this as a solution to your query.
Ian made me pass this challenge finally... oef!!. But K Shiv Kumar 6 actually made it work in Salesforce. So it seems that you have to add the fields in your attributes default parameter, in order to be able to give it a value after getting the attribute in your controller. Perhaps there is another way which is coming up in the next paragraphs.
By the way I didn't find anything neither on the second parameter in the component.get("v.item", true) statement. Left it out and got the same result.
For anybody else who ends up stumbling across this thread while working on this Trailhead...the code above will help you pass but you might get the "property 'Packed__c' null" error if you look at it in a browser. I found the following helpful...
Then set the value and push it back to the view...You'll want to make sure your <aura:attribute name="item"....> either does not have "required" set to true (as some code samples above), or if it is, make sure you're providing a default. (as K Shiv Kumar 6 does)
Secondly, in the JS controller, you'll want to check first that the view (v) actually has a value for item before you try setting any of its fields. If you didn't use required/default on the attribute, then in your controller you'll need to first check if it exists, and if it doesn't, create a new sobject and then start operating on that. (providing a default skips this check since, well, you're providing a default object that will exist no matter what)
ex.
Lastly, I'll also add my comment to the others that I don't understand where the second param is coming from in the component.get('v.item') calls in the code samples above. I can't find any documentation to indicate what component.get('v.item',true); could mean...
As per my knowledge, the reason of error is that we are not setting any CampingItem value/record initially ,so when we are trying to update that we are getting error. In order to overcome that we will have to set the default value for that attribute which we will be updating.
Challenge Not yet complete... here's what's wrong:
The campingListItem JavaScript controller doesn't have a 'packItem' handler function.
Solution:
I was creating a .js file via Console > New > Static Resource > text/javascript
That's incorrect
Go to campingListItem.cmp > In Right bar, click CONTROLLER
That's it
I palyed around the code a bit only to find what is the significance of second argument in [var a = component.get("v.item","True");].
I dont think its mandate, this [ var a = component.get("v.item"); ] works just fine.
If anyone kneo the answe why we use a second boolean argument while calling the component, please let know.
campingListItem.cmp:
campingListItemController.js :
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)
This code worked for me
In the component section, change this line
<p><ui:button label="Packed!" press="{!c.packItem}" /></p>
to
<p><lightning:button label="Packed!" press="{!c.packItem}" /></p>
The controller is fine.
In the component section, change this line
<p><ui:button label="Packed!" press="{!c.packItem}" /></p>
to
<p><lightning:button label="Packed!" onclick="{!c.packItem}" /></p>
not
<p><lightning:button label="Packed!" press="{!c.packItem}" /></p>
The controller is fine.
Thanks everyone!
The Component (partly built from an example in a prior section):
And here is the mysterious controller code:
It seems that you have to get the component (or subcomponent) you want to change (with component.get() or event.getSource()), change it in the javacript code and then write the change back using component.set(). Why you can't grab the component with a get() and then chain a call to it's set() method is beyond me. But at least for the challenge that didn't seem to work. Would any Lightning Component gurus in the real world care to comment. Does the challenge require reflect what you have to do in the real world?
Had to wrote the following to complete the challenge
Is there any reason as of why the challenge was failing?
Doesn't this code does the same thing in the end?
over
I guess that's just typo and since that javascript is a loosely typed language, the ",true" is not even used but the code works anyway? Or is there any reason to but the ",true" part on the get funciton?
component.set("v.item.Packed__c",true);
event.getSource().set("v.disabled",true);
}