Freezing Users with Lightning Components
Introduction
Back in November 2013 I wrote a blog post about a new feature in the Winter 14 release of Salesforce - freezing users. At the time this was only available via the API, so I came up with a Visualforce solution that leveraged the Ajax Toolkit. This post presents the Lightning Components equivalent.
One Does Not Simply Call the API
Not from a Lightning Component, at least. The docs make this quite clear:
"Make API calls from an Apex controller. You can’t make API calls from JavaScript code."
Luckily the sObject that encapsulates the frozen status of a user, UserLogin, is now available and updatable in Apex, so the Lightning Component will be responsible for allowing an admin to choose which users to freeze/unfreeze, while the actual database changes will be handled by its Apex controller.
TL;DR
The full code is available at the following Gists:
- Apex Controller
- Lightning Component
- Lightning Component JavaScript Controller
- Lightning Component JavaScript Helper
- Lightning Component Style
- Lightning Application
The Lightning Component
The key part of the Lightning Component is the iterator that outputs user information and a checkbox so that the user’s frozen status can be updated. This makes use of a wrapper class that encapsulates the User and UserLogin sObjects for a specific user :
<aura:iteration items="{!v.UserDetails}" var="ud"> <tr> <td>{!ud.user.FirstName}</td> <td>{!ud.user.LastName}</td> <td>{!ud.user.Username}</td> <td id="{!ud.user.Id}"> <ui:inputCheckbox change="{!c.frozenChanged}" value="{!ud.userLogin.IsFrozen}" /> </td> </tr> </aura:iteration>
Note the input checkbox has a handler for when the value is changed - I found I couldn’t just bind the value from the underlying UserLogin field. I suspect this is because I am binding to a field from a complex object rather than directly to a primitive. This meant that I had to fire an event when the value changed, then figure out which user the checkbox was associated with. Ideally I’d have given the inputCheckboxComponent an aura Id that included the user id, but the aura Id for this component must be a string literal, so if I use something like aura:id=“{!’cb-‘ + ud.user.Id}”, then the aura id generated is exactly that - {!’cb-‘ + ud.user.Id}, which isn’t very useful.
Where I can use a dynamically generated id is in the containing element - the table cell in this case. My event handler that is invoked when the value is changed can then use the id of the parent element to determine the user id, and invert the current value of the IsFrozen field:
updateCheckbox : function(cmp, ev) { var value=ev.getSource().get('v.value'); var userId=ev.getSource().getElement().parentElement.id; var userDetails=cmp.get('v.UserDetails'); for (var idx=0; idx<userDetails.length; idx++) { if (userDetails[idx].user.Id==userId) { userDetails[idx].userLogin.IsFrozen=!value; } } cmp.set('v.UserDetails', userDetails); }
The final line once again demonstrates the power of Lightning Components - by updating the component attribute containing the wrapper classes, the component rerenders the user information table with the latest details.
When the changes have been made on the client side, the collection of wrapper classes is then sent back to the server so that the UserLogin records can be updated. Even though I know there is a bug around sending an array as a parameter to the Apex controller, I still spent 15 minutes figuring out why doing exactly this threw an internal server error! Once I remembered I used the now familiar workaround, converting the collection of wrapper classes to a JSON string:
var userDetails=cmp.get('v.UserDetails'); var udAsJSON=JSON.stringify(userDetails); var params={ "toProcessAsJSON" : udAsJSON };
and turning this back into the wrapper class collection server side:
Type udArrType=Type.forName('List<UserFreezer.UserDetails>'); List<UserDetails> toProcess = (List<UserDetails>)JSON.deserialize(toProcessAsJSON, udArrType);
Related Posts
- Freezing Users from Visualforce
- Board Anything with SLDS and Lightning Components
- Lightning Component Wrapper Classes
- Lightning Design System - Edit Parent and Child Records
- Lightning, Visualforce and the DOM
- Lightning Components and JavaScript Libraries
- Lighting Components and CSS Media Queries
- Lightning Component Events
- Lightning Components and Unobtrusive JavaScript
- Lightning Components and Custom Apex Classes
- LDS Activity Timeline, Lightning Components and Visualforce