function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Brian KesslerBrian Kessler 

Lightning Component Superbadge: What's Wrong with My New Boat Button?

Hi,

I'm currently working on the Lightning Component Framework Specialist Superbadge.

When I click "New", at least as I've interpretted the requirements, the "Friends with Boats" pages is behaving as expected, but Trailhead complains:
Challenge Not yet complete... here's what's wrong: 
The BoatSearchForm component's "New" button should launch the default boat record create page using logic in its controller.

Have I misunderstood a requirement?

Here is my markup:
 
<aura:component controller="BoatSearchFormAuraCtrl" >
	<aura:attribute access="private" name="boatList" type="BoatType__c[]" default="[]" />
	<aura:attribute access="private" name="showNewButton" type="Boolean" default="false" />
	<aura:attribute access="private" name="selectedBoat" type="BoatType__c" />
	
	<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
	
	<h2 class="slds-page-header__title">Find a Boat</h2>
	<form>
		<lightning:layout horizontalAlign="center">
		    <lightning:select name="select" value="{!v.selectedBoat}">
		        <option value="">All Types</option>
		        <aura:iteration items="{!v.boatList}" var="boat">
		            <option value="{!boat.Name}" text="{!boat.Name}"></option>
		        </aura:iteration> 
		    </lightning:select>
		    <lightning:button name="Search" label="Search" variant="brand" />
		    <aura:if isTrue="{!v.showNewButton}">
		    	<lightning:button name="New" label="New" variant="neutral" onclick="{!c.createBoat}"/>
		    </aura:if>
		</lightning:layout>
	</form>	
</aura:component>
And here is my controller:
({
	doInit : function(component, event, helper) {
		component.set('v.showNewButton', $A.get('e.force:createRecord'));
		helper.setBoatTypeList(component);
	},
	
	createBoat : function(component) {
		var createRecordEvent = $A.get('e.force:createRecord');
		createRecordEvent.setParams({
			'entityApiName' : 'BoatType__c',
			'defaultFieldValues': {
				'Name': component.get('v.selectedBoat')
			},
		});
		createRecordEvent.fire();
	}
})





 
Brian KesslerBrian Kessler
Hi @Pat,

Thanks for all the great input.
Great call on the Boat/Boat Type confusion.

Allow me to repay the favour by suggesting the use of JavaScript ES6 maps instead of a second handler:

Here is my present code:

Markup:
<aura:component controller="BoatSearchFormAuraCtrl" >
	<aura:attribute access="private" name="boatTypeList" type="BoatType__c[]" default="[]" />
	<aura:attribute access="private" name="boatTypeIdByNameMap" type="Map" />
	<aura:attribute access="private" name="selectedBoatType" type="BoatType__c" />
	<aura:attribute access="private" name="showNewButton" type="Boolean" default="false" />
	
	<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
	
	<h2 class="slds-page-header__title">Find a Boat</h2>
	<form>
		<lightning:layout horizontalAlign="center" verticalAlign="center">
		    <lightning:select name="select" value="{!v.selectedBoatType}">
		        <option value="">All Types</option>
		        <aura:iteration items="{!v.boatTypeList}" var="boatType">
		            <option value="{!boatType.Name}">{!boatType.Name}</option>
		        </aura:iteration> 
		    </lightning:select>
		    <lightning:button name="Search" label="Search" variant="brand" />
		    <aura:if isTrue="{!v.showNewButton}">
		    	<lightning:button name="New" label="New" variant="neutral" onclick="{!c.createBoat}"/>
		    </aura:if>
		</lightning:layout>
	</form>	
</aura:component>

Controller:
({
	doInit : function(component, event, helper) {
		component.set('v.showNewButton', $A.get('e.force:createRecord'));
		helper.setBoatTypeCollections(component);
	},
	
	createBoat: function (component) {
		var createRecordEvent = $A.get('e.force:createRecord');
		var selectedBoatType = component.get('v.selectedBoatType');
		var selectedBoatTypeId = (selectedBoatType)
			? component.get('v.boatTypeIdByNameMap').get(selectedBoatType)
			: null;
		
		createRecordEvent.setParams({
			'entityApiName' : 'Boat__c',
			'defaultFieldValues': {
				'BoatType__c': selectedBoatTypeId
			},
		});
		createRecordEvent.fire();
	}
})

Helper:
({
    setBoatTypeCollections : function(component) {
        var action = component.get('c.getBoatTypes');
        action.setCallback(this, function(response){
            if (response.getState() === 'SUCCESS') {
                component.set('v.boatTypeList', response.getReturnValue());
                this.setBoatTypeIdByNameMap(component);
            }
        });
        $A.enqueueAction(action);
    },

    setBoatTypeIdByNameMap : function(component) {
        var boatTypeList = component.get('v.boatTypeList');
        var boatTypeIdByNameMap = new Map();
        for (var i = 0; i < boatTypeList.length; i++) {
            var boatType = boatTypeList[i];
            boatTypeIdByNameMap.set(boatType.Name, boatType.Id);
        }
        component.set('v.boatTypeIdByNameMap', boatTypeIdByNameMap);
    }
})



I'm still not passing yet as "Friends with Boats" is apparently both the right and wrong name for this Lightning application.  :-/
... But I'll start a clean, new thread for that....

 
Brian KesslerBrian Kessler
I tried plugging boatType.Id directly into my aura:iteration, but something seemed to be going wrong and my selections never seemed to take.  I thought it was because the var was a Object/Boat__c while the value was an Id/String...   Perhaps I should have used boatType.id instead of boatType.Id (or vice-versa).... It is really frustrating that the API names can be unpredictable.

Maps are really useful for so many things... unfortunately, Lightning support for them is limited.  For example, you can't iterate over them.  :-(
But, yes, you can definitely use maps to reduce your need for SOQL statements.

Whether it conflicts with the instructions, I do wish they'd learn to test for results rather than implementation details.  It pisses me off that they enforce bad practices.
 
@jeronimoburgers ☁@jeronimoburgers ☁
Banging my head over the 2nd step of the supber badge. Functionality-wise the BoatSeachForm.cmp component does exactly what it's supposed to to. Pretty much along the lines of Patt's code. 

Still... "Challenge Not yet complete... here's what's wrong: The BoatSearchForm component's "New" button doesn't launch the new boat page with the correct default field values using logic in its controller."
 
, handleNew : function (component, event, helper) {
		var selectedBoatTypeId = component.get("v.selectedBoatTypeId");
        var createRecordEvent = $A.get("e.force:createRecord");
    	createRecordEvent.setParams({
        	"entityApiName": "Boat__c",
    	});
        
   
        if (!selectedBoatTypeId=="") {
            createRecordEvent.setParams({
            	"defaultFieldValues": {"BoatType__c": selectedBoatTypeId}
    		});
		}
        
    	createRecordEvent.fire();
	}

Thanks by the way for tackling the question arround how to hide the New button based on the context. Learnt something today. Attribute type could be a function reference ;-)
component.set("v.showNewButton", $A.get("e.force:createRecord"));
Anyways - anybody in the clear on this Superbadge... help appreciated!

Jeroen
 
@jeronimoburgers ☁@jeronimoburgers ☁
The root-cause with regards to me not being able to complete the Step 2? 

--> I put my code in helper functions, per best practice. That made the test to fail. Moving the code to the controller, it worked immediately.
@jeronimoburgers ☁@jeronimoburgers ☁
Paras, It might be as simple that you’re declaration of your controller function should follow foo(component, event, helper) instead of foo(component). I had my code in a helper and it failed though functionally and technically correct. Just try. Jeroen
Paras Shah 15Paras Shah 15
I have completed the challenge by updating the code by myself.

Anyways Thanks Jeroen for your response
shashi kumar 58shashi kumar 58
Lightning Component Framework Specialist superbadge step 2 
Solution please follow the below links where i have given all the steps:--
https://developer.salesforce.com/forums/ForumsMain?id=9060G0000005NG8QAM
sai sekhar 1sai sekhar 1
@paras Shah 15 can you please provide your version i got stuck.
Manish Anand 22Manish Anand 22
Hi All,

I am stuck in challenge 2. Functionality is working as expected. But I get error as - Challenge Not yet complete... here's what's wrong: 
The BoatSearch component should instantiate the BoatSearchForm and BoatSearchResults components.

Below is my BoatSearch component.
<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes" access="global" >
    <lightning:card title="Find a Boat"  class="slds-m-top_10px">
        <c.BoatSearchForm/>
    </lightning:card>
    <lightning:card title="Matching Boats">
        <c.BoatSearchResults/>
    </lightning:card>
</aura:component>
Any lead is apprciated.

Thanks,
Manish.
Vipul Sharma 15Vipul Sharma 15
Hi All, 
I am able to pass Step 2 , it uses less code, here we are focusing on main component BoatSearchForm, so below is its component and controller
<aura:component implements="flexipage:availableForAllPageTypes" controller="BoatType" >
    <aura:attribute name ="BoatType" type="BoatType__c[]" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <aura:attribute name ="selectedBoat" type="BoatType__c" />
    <aura:attribute name ="showNew" type="Boolean" />
    <aura:attribute name ="BTselectedValue" type="String" />
    
    <lightning:layout horizontalAlign= "center">
        <lightning:select name="select" value="{!v.BTselectedValue}" >
            <option value="">All Types</option>
            <aura:iteration items="{!v.BoatType}" var="t">
                <option value="{!t.Id}">{!t.Name}</option>
            </aura:iteration>
        </lightning:select>
        <lightning:button variant="brand" label="Search" />
        <aura:if isTrue="{!v.showNew}">
            <lightning:button variant="Neutral" label="New" onclick="{!c.handleClickNew}" />
        </aura:if>
    </lightning:layout>
</aura:component>

controller:
({
    doInit : function(component, event, helper) {
        var isEnabled = $A.get("e.force:createRecord");
        if(isEnabled){
            component.set("v.showNew",true);
        } 
        var action = component.get("c.getBoatNames");
        action.setCallback(this, function(response){
            if(response.getState() === "SUCCESS"){
                component.set("v.BoatType",response.getReturnValue());
            }
        });
        $A.enqueueAction(action);
    },
    handleClickNew : function(component, event, helper) {
        var navEvt = $A.get("e.force:createRecord");
        navEvt.setParams({"entityApiName":"Boat__c"});
        if(component.get("v.BTselectedValue") != ""){
            navEvt.setParams({"defaultFieldValues": {"BoatType__c": component.get("v.BTselectedValue")}});
        }
        navEvt.fire();
    }
})
 
Any advices ..  ... :)
swapna Ravula 22swapna Ravula 22
Hi,
Can some one please help me out with the below issue.
User-added image
Sassi ElhemSassi Elhem
I resolve the same problem by putting the code in the BoatSearchFormController.js instead of helper