Is there a good up to date Lightning Component sample app somewhere?

I think because people are exactly looking for that the same team that build Dreamhouse has now built the Mutual Fund Explorer - a complex set of tightly coupled Lightning components that show

  • Caching data with storable actions
  • Caching data with a custom cache
  • Creating a dropdown box from picklist values
  • Creating a dropdown box from a list of records
  • Event bubbling
  • Using application events
  • Using component events
  • Using a third-party JavaScript library
  • Using bound vs unbound expressions

I recently created a large app that controlled several (8 I think) smaller components that depended on it. I used both Abstract and Interface components to enforce a standard API between all components.

The Interface component was used to:

  • Define events that could be emitted by each component (This does not preclude you from adding more events to a particular component, but you can rely on each component being able to emit a basic subset of events).
  • Define certain attributes that each component would be guaranteed to have (eg an opportunityId)

I then created an Abstract component that implemented this interface. This component was responsible for:

  • All calls server-side. This simplified child component server calls greatly.
  • Notifications
  • Spinners
  • A public method "refresh" which could be called on any child that would refresh it's view without having to dispatch an event.
  • Some other utility shared logic (which I considered putting in a utility component and decided against)

To support this, I created an interface in Apex and made all controllers for this meta-app implement this interface - It meant that I could be guaranteed that I would receive a custom Result object which contained three parameters:

  1. A success boolean
  2. A message (generally only used in case of error)
  3. A data string (Results were generally encoded as a JSON string)

So a child component would define a success handler (and optionally an error handler - if not, the Abstract component would handle it).

The child component would also define the method to be called and parameters to be passed to it. The syntax reduced the size of server calls by 2/3.

So, the Abstract component handles server calls, notifications and more and can make calls to it's children.

For the children to communicate with the parent, I defined a DataChange event with some fairly generic attributes - pretty much just the data that changed (an object) + the id of the component (which is set by the parent when it is dynamically created).

I set up a github repo here that partially represents this framework. To simplify things, I left out the Interface component - I'll put it here:

<aura:interface description="Interface that enforces the use of certain events and attributes to tie the app together">

  <aura:attribute name="opportunityId" type="String" description="Id of the Opportunity that this 1003 for is for."/>
  <aura:attribute name="componentId" type="String" description="Id of this component, which should match the aura:id"/>
  <aura:attribute name="opportunity" type="Opportunity" default="{'sobjectType':'Opportunity'}"/>

  <aura:registerEvent name="dataSaved" type="c:DataSaved"/>
</aura:interface>

The main parent component was a list of mostly empty html elements that I used to dynamically create the child components as the user clicked on them (this was easily fast enough) - simplified here:

<ul>
  <li id="First_Component" class="slds-is-active" onclick="{!c.handleNavigationClick}">
  </li>
  <li id="Second_Component" onclick="{!c.handleNavigationClick}">
  </li>
  <li id="Third_Component" onclick="{!c.handleNavigationClick}">
  </li>
</ul>

And finally, the dynamic component creation routine - note the dynamic creation of ids.

createComponent: function(component, selectedNavigationItem, previousNavigationItem, selectedComponentName) {

  //find the existing component and remove it if present
  var itemToDestroy = component.find(previousNavigationItem + "_SelectedDetail");
  if (itemToDestroy) {
    itemToDestroy.destroy();
  }

  //clear body of host component just in case
  var hostComponent = component.find("DetailSection");
  hostComponent.set("v.body", []);

  $A.createComponent(
    selectedComponentName, {
      "aura:id": selectedNavigationItem + "_SelectedDetail",
      "componentId": selectedNavigationItem + "_SelectedDetail"
      "opportunityId": component.get("v.opportunityId")
    },
    function(newComponent, status, errorMessage) {
      //Add the new button to the body array
      if (status === "SUCCESS") {
        var body = hostComponent.get("v.body");
        body.push(newComponent);
        hostComponent.set("v.body", body);
      } else if (status === "INCOMPLETE") {
        console.log("No response from server or client is offline.");
      } else if (status === "ERROR") {
        console.log("Error: " + errorMessage);
      }
    }
  );

},

Hope this helps!


The newly released Sample Gallery needs an answer in its own rights.

https://trailhead.salesforce.com/de/sample-gallery

enter image description here