Streams of Lightning: Part Four

Last week we updated our app to show all of the Poll Question Options as buttons within our parent Poll Question Component. However, it still “does nothing.” What we really need to do is get it to interact somehow, and we will do this by supplying our buttons with a function to call in order to cast our vote.

The first thing we need to do is setup a javascript controller (client side controller) for our Poll Question Item component to talk to. On it we will create a function called “voteItUp” that will in turn call a method on our apex controller that will actually increment the vote count and save our answer.

Open up your PollQuestionItem component in the developer console and in the right-hand side menu, click “Controller” and paste this into the code:

({   
    voteItUp : function(component, event, helper) {
        var optionId = component.get("v.pollOptionId");
        var voteAction = component.get("c.incrementVote");
        voteAction.setParams({ optionId : optionId });
        
        voteAction.setCallback(this, function(response) {
           var state = response.getState();
            if(state === "SUCCESS") {
                document.getElementById(optionId).innerHTML = response.getReturnValue();
            }
        });
        
        $A.enqueueAction(voteAction);
	}
})

What this does is gives us a function that we will use when our button is clicked. In order to determine which button is clicked we will store the option ID of the component that it came from (v.pollOPtionId) in a variable called “optionId.” If you recall we are looping over this component in our parent component and passing it a Poll Option object each time. We then setup the action (the call to the apex method) by looking at our component and finding its declared controller, and telling it to call the “incrementVote” method on that controller. Our apex controller needs to know what option we are voting on so we will have pass in the option ID. This is done with the setParams function and takes a key value pair collection of arguments (voteAction.setParams({ optionId : optionId }) ). We then tell this action what to do when it completes by setting up the callback function. This will run after our callout to apex completes. We’ll then inspect the results and if successful, update the UI.

Please Note: This code is still under some development as I was having some issues locating the output for my vote count. However, this was happening while simultaneously trying to troubleshoot some streaming API issues (coming in part 5). In order to get things to work, I had to resort to using document.getElementById to locate the element in my component to update it. However, that’s also the beauty of this — while its probably not the “blessed” way to do something, while coding you can always “fall back” to tricks like this because your UI, at the end of the day, is still simply HTML and javascript. I would like to come back at some point and fix this, but haven’t found the time :( #StoryOfMyLife

Next we will create the apex controller that our component’s client side controller will call. Simply create a controller using your favorite editor (dev console, sublime, eclipse etc). I called mine PollOptionController. Use the following code:

public class PollOptionController {
	    
    @AuraEnabled
    public static Integer incrementVote(String optionId) {
        Poll_Option__c option = [SELECT Id
                                , Vote_Count__c 
                                FROM Poll_Option__c 
                                WHERE ID = :optionId];
        option.Vote_Count__c += 1;
        update option;
        return option.Vote_Count__c.intValue();
    }
}

Here we take the optionId that we passed in from our client side controller and lookup our custom object by its Id. We then increment its vote count by 1, update it and return the vote count back to our calling function. This will get processed in the “callback” of our action and update our component’s UI with the latest vote count.

Lastly we need to tell our button what function to call when pressed and tell our component which apex controller it needs to be associated with like so:

<aura:component controller="PollOptionController">

    <aura:attribute name="pollOption" type="Poll_Option__c"/>
    <aura:attribute name="pollOptionId" type="String" default="{!v.pollOption.Id}"/>
    
    
    <div style="border:1px solid black;margin:5px;padding:10px;text-align:center;border-radius:5px">
        <ui:button aura:id="voteButton" label="{!v.pollOption.Option_Name__c}" press="{!c.voteItUp}"/>
        <div style="float:right" class="findme" id="{!v.pollOption.Id}">
            {!v.pollOption.Vote_Count__c}
        </div>
        <br/>
    </div>

</aura:component>

We tell our component which apex controller it will be working with by adding the controller attribute to our component declaration: controller=”PollOptionController” and finally we add the “press” attribute to our button to tell it which function to call when its tapped/clicked, etc. One point that may be confusing for some is the use of multiple controllers. Our UI components do not call our apex directly, instead they call our client side controllers (the javascript ones). That is the {!c.voteItUp} notation. However we do tell our component which apex controller it is associated with using the controller attribute in our declaration. So when I say our component is calling a controller function using c.something, I’m making reference to our client side controller, not our apex controller. (For me, it really feels as if the only reason our component mentions the apex controller is so that our client side controller has a place to look up which controller to call a given function on, I could be wrong and it may provide other functionality, but at the moment that bit is unclear to me).

If we load up our application in Salesforce 1, we should now be able to tap the buttons and vote. As you vote you will see the vote count increase. These results are also being persisted to your org as well. We now have a functional lightning app!

I was imagining a use for such an app, and perhaps rather than a “voting” type of application, similar apps could be used on shop floors, in retail etc to reflect an up to date view of inventory. But even better, what if we could stream those results so that users of the app could see an ongoing real-time view of data. For that, we will need some extra javascript libraries, some calls the the streaming API….and another blog entry. Until then…

:wq!

Streams of Lightning: Part Three

As you may or may not know, I was out in San Francisco last week attending my first MVP Summit. For this reason, I did not post part three of my current lightning tutorial. <sarcasm>Since you’re no doubt waiting directly on the edge of your seat<sarcasm>, lets get right back to it.

Last week we left off with a component that was just a tiny bit more flexible than a simple “Hello World” type of component. We were able to add our component to the lightning app builder and configure said component to display the current active poll question. Today we will move on to having this component nest a secondary component that will be responsible for displaying our poll’s options as buttons on the screen. For this, we need to create a brand new custom component, so we’ll begin there.

In the developer console click File->New->Lightning Component. We will call this component “PollItemOption.” Once again we will get the familiar skeleton code, but we’re going to replace it with the following:

<aura:component >

    <aura:attribute name="pollOption" type="Poll_Option__c"/>
    <aura:attribute name="pollOptionId" type="String" default="{!v.pollOption.Id}"/>
    
    <div style="border:1px solid black;margin:5px;padding:10px;text-align:center;border-radius:5px">
        <ui:button aura:id="voteButton" label="{!v.pollOption.Name}" />
        <div style="float:right" class="findme" id="{!v.pollOption.Id}">
            {!v.pollOption.Vote_Count__c}
        </div>
        <br/>
    </div>

</aura:component>

For this component, we are creating a place holder for the Poll Option object itself (pollOption attribute). Remember that we will be using this component “inside” of our Poll Question component that we’ve been working with. That parent component will be passing a Poll Option object to this one. In our case, the Poll Question component will loop over the Options that belong to it and pass them to this component for rendering. We will also likely need the ID of the Option we are working with for updates, etc so we’ll create a place to store that ID as well (pollOptionId attribute).

Next we add some HTML and styling to our component. We will be displaying the poll options as clickable buttons that our users will tap in order to vote for them. I’m wrapping these ui:button pieces in an HTML div for more control over styling. (Once again, I must point out that I am doing this “wrong” during development as style should go in the CSS file that belongs to the component — we’ll get there, but when I’m coding, I like my styles right where I’m working, its just a preference for me). Inside that div we have an instance of ui:button, the label of that button will be the Poll Option’s name field, referred to with our shorthand for accessing attributes in our view: {!v.pollOption.Name}. We can also tell that button what function to call when it is pressed (but we will do that in part 4 next week).

I follow this button up with some HTML markup to assist in styling and then I close it up.

This component, though it will have zero/broken functionality can now be rendered within our parent component, so lets just wire it up briefly so we can track our progress. Open up the Poll Question component that we created in part one. (If you don’t already have it open you will need to go to File->Open Lightning Resources and expand the appropriate folder, highlight the individual pieces and click on the Open Selected button at the bottom of that dialog window).

Now let’s add an iteration over our Poll Options from within our PollQuestion component and have it pass each option to our newest component. Replace the PollQuestion component code with this code (really you only need to add the aura:iteration tag and its contents):

<aura:component implements="flexipage:availableForAllPageTypes"  controller="PollController" >

    <aura:attribute name="pollQuestion" type="Poll_Question__c"/>
    <aura:attribute name="options" type="Poll_Option__c[]"/>
    <aura:attribute name="title" type="String" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />

    <h1 style="text-align:center">{!v.title}</h1>
    <p style="padding:10px;">{!v.pollQuestion.Name}</p>
    <aura:iteration var="option" items="{!v.pollQuestion.Poll_Options__r}">
        <c:PollItemOption pollOption="{!option}" />
    </aura:iteration>

</aura:component>

What we’ve added here is the bit called an aura:iteration. It’s how we loop over collections inside lightning components. You specify the variable that you will be using for each iteration and the items over which to be iterated. In this case our variable is called “option” and our items are our poll options that we retrieve from the pollQuestion (!v.pollQuestion.Poll_Options__r} — we retrieved them in our PollController). Secondly, inside of this iteration we are telling this component to use our PollItemOption component that we just created to render each poll option (<c:PollItemOption pollOption=”{!option}” />). Here the “c:PollItemOption” means we are loading a component called “PollItemOption.” That component also has an attribute called “pollOption” that is expecting a Poll_Option object. So we pass our “option” variable in using pollOption=”{!option}”

If you load up your lightning app in Salesforce1 now, you should see our Current Poll application displaying the question and each option rendered as a button. If you’re following along, from last week we should see something similar to the screenshot below. (NOTE: Your titles will be different since I am re-writing my original app for the blog to help me keep track, and you likely won’t have any vote numbers showing up since we’ve not voted for anything yet):

Screen Shot 2015-05-19 at 9.53.08 PM

Things are starting to look a tad more useful. Next week we will add the necessary logic to allow voting on each item, followed by adding in some functionality to wire in the streaming api so that you can watch the votes increase as users vote.

If you happen to be in the Milwaukee area on Thursday, May 21st (I know its short notice) I will be demoing this application complete with streaming at the Wisconsin User Group meeting at: 250 E Juneau Ave Milwaukee, WI. The meeting starts at 11:30am. Stop on by if you find the time.

:wq!

 

Streams of Lightning Part Deux

Last week I showed you how to make a simple custom lightning component and make it available to the new Lightning App Builder that is going GA with the Summer ’15 Release.  This week, we will create a simple custom Poll Question object and a Poll Option object that will have the Poll object as a parent. We will then write the custom code to show the latest Poll inside of a Salesforce1 app.

Let’s start with creating the Poll Question object itself. We are going to keep it simple for now so there won’t be a ton of configuration wrapped around our app. Create a Poll Question object with the following fields (I added two more fields but haven’t used them yet in my code so I’ve left them out here as well). We will use the standard Name field as the question text so really we have one field here:

Status: Picklist with options 'Open' and 'Closed'

Next create a Poll Option object with the following fields (here we could probably use the standard Name field, but opted to have a custom field hold that information, in our case however they’d be identical, or we could make Name an auto number, etc):

Poll Question: Master/Detail to the Poll Question object
Option Name: Text to present to user for voting
Vote Count: Number, the current count of votes for this option

With that out of the way, we need to modify our component from last week to retrieve the latest poll and display it. Let’s first focus on getting the text of our question to show up in our component. We will need to create another aura:attribute in our component to hold our poll object and a place to show the question text on our component:

<aura:component implements="flexipage:availableForAllPageTypes" >

    <aura:attribute name="pollQuestion" type="Poll_Question__c"/>
    <aura:attribute name="title" type="String" />

    <h1 style="text-align:center">{!v.title}</h1>
    <p style="padding:10px;">{!v.pollQuestion.Name}</p>

</aura:component>

It occurs to me now that I may have forgotten to explain a few things about the attribute names and other markup you’re seeing here so allow me to explain. An aura:attribute has a name and a type. The type can be a custom object, a list of objects, or a primitive like a String. You can then refer to the data stored into these attributes by its name. In this case, we have an aura:attribute of type Poll_Question__c (our Poll Question object) and we refer to that object’s Name with the following markup: {!v.pollQuestion.Name}. In this case the “v” is an automatic variable that points to our visible component, or our “View” (think MVC — Model View Controller). Therefore {!v.pollQuestion.Name} basically says, in this component, find the attribute with the name of “pollQuestion” and get me the data stored there. Since that attribute contains a Poll Question, we can then get its Name for display as we would with any custom object.

So now that we have our component ready to display our Question, we need to tell the component how to get the latest question. We will do that with a “client-side” controller. This will be a bit of javascript that can call out to a custom apex controller that will lookup our poll object. First let’s create our javascript controller — the “client side” controller. It’s worthy to note that this controller is executed on the client, not on the server.

Ensure that you have the PollItem.cmp tab open in your developer console and click on the right-hand side’s menu item labeled “Controller.” This will create a new tab in the console labeled PollItemController.js. It will stub out the following code:

({
    myAction : function(component, event, helper) {	
	
    }
})

We need to modify this code, but before we do that, we know that it will need some logic on the apex side for it to talk to. Rather than add a bunch of code here that won’t make much sense, let’s create our apex controller first. All this controller has to do for us right now is retrieve the latest Poll Question for us. For the apex side of things, you don’t need to use the developer console or any of the menu options on the right. (We will tell our visual component (PollItem.cmp) the name of this controller when we are ready.) So create an apex controller called, PollController using your favorite editor (the dev console is just fine as well). In that code we will have one method called “latestPoll()” and that is what our client side controller will call in order to get a handle on the latest poll. Here is that code:

public class PollController {

    @AuraEnabled
    public static Poll_Question__c latestPoll() {
        Poll_Question__c poll = [SELECT Id
                                 , Name
                                 , Subject__c
                                 , Total_Votes__c
                                 , Highest_Votes__c
                                 , (SELECT Id
                                    , Vote_Count__c
                                    , Option_Name__c 
                                    FROM Poll_Options__r)
                                 FROM Poll_Question__c WHERE Status__c = 'Open' 
                                 ORDER BY CreatedDate LIMIT 1];

        return poll;
    }
}

This looks like standard apex code, because it is. Its just like any other controller you’ve worked with except for the @AuraEnabled annotation. Methods that are to be called from Lightning Components need to have this @AuraEnabled annotation.

With that out of the way we can revisit our client side controller and write the code that will call our apex:

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

        var action = component.get("c.latestPoll");

        action.setCallback(this, function(response) {
            var state = response.getState();
                if(state === "SUCCESS") {
                    component.set("v.pollQuestion", response.getReturnValue());
                }
            });
        $A.enqueueAction(action);
    }
})

Okay — breathe, there’s quite a bit here for the un-initiated, I myself am still catching on, but we’ll get through this, I promise. This bit of javascript magic, when invoked, will look at our component (component.get) and look for our components controller (“c.latestPoll”) as declared (we haven’t added that yet, but we will in a moment). This is a bit of black magic that returns a handle to our apex controller function called “latestPoll()” — however it hasn’t run it yet. Its just setting up the call. The next bit “action.setCallback” is what is going to run AFTER our call to apex completes. Lastly the $A.enqueueAction(action) is what actually sends the call to apex to retrieve our data.

The component, event, and helper arguments to our doInit function are “auto wired” in some fashion that I don’t completely comprehend myself. Basically they are handles to our visual component that is calling this function, the event that is forcing the call to happen, and a helper function (if you create one). The latter is wired up via naming convention and is handled for you on the platform.

The setCallback runs after our call to apex completes and will then inspect the response we get back from our apex controller. If its successful, we will read our return value from the controller (in this case a Poll Question object) and pass that back to our pollQuestion aura:attribute on our visual component. (This javascript knows about the “v.pollQuestion” as well, just like our visual component knows about it {!v.pollQuestion}).

I expect that to be a little muddy right now and that’s okay. It will come to you, trust me. For now, pretend that I did my job and explained it flawlessly so we can move on to our last bit of code for this part. Let us wire up our visual component to our controllers. Here’s the code to do that, and then I’ll explain a few bits. Back in our PollItem.cmp add some code to look like this when you’re done:

<aura:component implements="flexipage:availableForAllPageTypes"  controller="PollController" >

    <aura:attribute name="pollQuestion" type="Poll_Question__c"/>
    <aura:attribute name="options" type="Poll_Option__c[]"/>
    <aura:attribute name="title" type="String" />
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />

    <h1 style="text-align:center">{!v.title}</h1>
    <p style="padding:10px;">{!v.pollQuestion.Name}</p>

</aura:component>

First we’ve added to our component declaration: controller=”PollController” which is what our client side controller will look at for our @AuraEnabled methods to call. Secondly we’ve added something called an aura:handler. This is some code that allows us to hook into events that are occurring within our component. In this case we are hooking into a built in event called “init” which fires when this component is loaded. It has a value of {!this} meaning “this component” and when this event fires its going to look for a client side controller method called doInit ({!c.doInit}). Like the “v” in {!v.pollQuestion.Name} “c” is a built-in reference to a component’s client-side controller. (Again these are wired up via the framework for you…”black magic.” Its voodoo, I’m convinced).

So now when our component loads, it will fire the “init” event and since we have an aura:handler for the init event, it will call our client side controller’s doInit method. If you recall, that doInit method is what calls out to our apex controller which should return to us the latest Poll Question. If successful, it will then set the pollQuestion attribute of our component to the Poll Question object we just retrieved. (Savvy readers will notice I don’t have any error handling, I didn’t write any for this, but potentially you could handle errors gracefully here. Due to lack of time I haven’t gotten around to that yet…)

Let’s save this and use the standard UI to create a Poll Question and a couple Poll Options to display in our app. I created a Poll Question of “What would you like for lunch” and three options: Pizza, Sushi, and Burgers. Do that now, I’ll wait. (You may have to create tabs in your org for these objects, this tutorial assumes you know how to do all of that already).

When you are done, fire up Salesforce1 and go into your app. You should now see the Poll Question listed. Woohoo! Do you realize what you’ve done? You’ve wired up a Lightning Component to Salesforce data, pulled it back, and displayed it on a mobile device. Think about that for a second. Most of you are likely not mobile developers. Yet — here you are.

Next week, we will create a second visual component that we will iterate over in our PollItem component in order to display our options to the user. Until then consider working through the Lightning Module over at Trailhead. If I’ve managed to confuse you beyond belief, they oughtta be able to straighten you out :)

:wq!