diff --git a/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainer.cmp b/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainer.cmp index 96b5c93..ec4c08a 100644 --- a/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainer.cmp +++ b/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainer.cmp @@ -1,7 +1,11 @@ +
- + + +
+
\ No newline at end of file diff --git a/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainerController.js b/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainerController.js index e8e37df..b94a39e 100644 --- a/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainerController.js +++ b/src-sample/main/default/aura/SampleLookupContainer/SampleLookupContainerController.js @@ -4,5 +4,27 @@ const serverSearchAction = component.get('c.search'); // Passes the action to the Lookup component by calling the search method component.find('lookup').search(serverSearchAction); + }, + + onSubmit: function(component, e, helper) { + const selection = component.get('v.selection'); + + if (!selection.length) { + component.set('v.errors', [ + { message: 'You must make a selection before submitting!' }, + { message: 'Please make a selection and try again.' } + ]); + } else { + alert('Success! The form was submitted.'); + } + }, + + clearErrorsOnChange: function(component, e, helper) { + const selection = component.get('v.selection'); + const errors = component.get('v.errors'); + + if (selection.length && errors.length) { + component.set('v.errors', []); + } } }) diff --git a/src-sample/main/default/classes/SampleLookupController.cls b/src-sample/main/default/classes/SampleLookupController.cls index 50d7a3a..05b88fe 100644 --- a/src-sample/main/default/classes/SampleLookupController.cls +++ b/src-sample/main/default/classes/SampleLookupController.cls @@ -1,18 +1,18 @@ public with sharing class SampleLookupController { - + private final static Integer MAX_RESULTS = 5; @AuraEnabled public static List search(String searchTerm, List selectedIds) { // Prepare query paramters searchTerm += '*'; - + // Execute search query List> searchResults = [FIND :searchTerm IN ALL FIELDS RETURNING Account (Id, Name, BillingCity WHERE id NOT IN :selectedIds), Opportunity (Id, Name, StageName WHERE id NOT IN :selectedIds) LIMIT :MAX_RESULTS]; - + // Prepare results List results = new List(); diff --git a/src/main/default/aura/Lookup/Lookup.cmp b/src/main/default/aura/Lookup/Lookup.cmp index 9e42825..04c7daf 100644 --- a/src/main/default/aura/Lookup/Lookup.cmp +++ b/src/main/default/aura/Lookup/Lookup.cmp @@ -1,25 +1,28 @@ - - - - + + + + + + - - - - - + + + + + - + + - +
-
+
@@ -27,38 +30,49 @@
- - + + + + +
-
- - - +
+ + + + + + + + onclick="{!c.onClearSelection}" class="{! 'slds-input__icon slds-input__icon_right '+ (empty(v.selection) ? 'slds-hide' : '') }" />
@@ -66,14 +80,16 @@
-
+ + + + + +
diff --git a/src/main/default/aura/Lookup/Lookup.css b/src/main/default/aura/Lookup/Lookup.css new file mode 100644 index 0000000..b3b2860 --- /dev/null +++ b/src/main/default/aura/Lookup/Lookup.css @@ -0,0 +1,30 @@ +.THIS .slds-combobox__input, +.THIS .slds-combobox_container { + transition: border .1s linear, box-shadow .1 linear; +} + +.THIS .slds-combobox__input { + box-shadow: none; +} + +.THIS .slds-combobox__input.has-custom-border { + box-shadow: 0 0 0 2px #fff inset, 0 0 0 3px rgb(221, 219, 218) inset; +} + +.THIS .slds-combobox__input.has-custom-error { + border: 1px solid rgb(194, 57, 52); + box-shadow: rgb(194, 57, 52) 0 0 0 1px inset; +} + +.THIS .slds-combobox_container.has-custom-error { + border: none !important; +} + +.THIS .slds-combobox__input.has-custom-height { + height: 32px !important; +} + +.THIS .form-error { + color: rgb(194, 57, 52); + display: block; +} \ No newline at end of file diff --git a/src/main/default/aura/Lookup/LookupController.js b/src/main/default/aura/Lookup/LookupController.js index aa60aca..9ce39e6 100644 --- a/src/main/default/aura/Lookup/LookupController.js +++ b/src/main/default/aura/Lookup/LookupController.js @@ -1,7 +1,8 @@ ({ search : function(component, event, helper) { const action = event.getParam('arguments').serverAction; - + helper.toggleSearchSpinner(component); + action.setParams({ searchTerm : component.get('v.searchTerm'), selectedIds : helper.getSelectedIds(component) @@ -10,11 +11,13 @@ action.setCallback(this, (response) => { const state = response.getState(); if (state === 'SUCCESS') { + helper.toggleSearchSpinner(component); // Process server success response const returnValue = response.getReturnValue(); component.set('v.searchResults', returnValue); } else if (state === 'ERROR') { + helper.toggleSearchSpinner(component); // Retrieve the error message sent by the server const errors = response.getError(); let message = 'Unknown error'; // Default error message @@ -62,6 +65,14 @@ onResultClick : function(component, event, helper) { const recordId = event.currentTarget.id; helper.selectResult(component, recordId); + + // additional user defined event on result click + // for optional error handling / clearing in consumer + var event = component.getEvent('onSelection'); + + if (event) { + event.fire(); + } }, onComboboxClick : function(component, event, helper) { @@ -85,7 +96,7 @@ // Prevent action if selection is not allowed if (!helper.isSelectionAllowed(component)) { return; - } + } // Delay hiding combobox so that we can capture selected result const blurTimeout = window.setTimeout( $A.getCallback(() => { diff --git a/src/main/default/aura/Lookup/LookupHelper.js b/src/main/default/aura/Lookup/LookupHelper.js index 8e37ef6..a844e36 100644 --- a/src/main/default/aura/Lookup/LookupHelper.js +++ b/src/main/default/aura/Lookup/LookupHelper.js @@ -2,7 +2,7 @@ updateSearchTerm : function(component, searchTerm) { // Cleanup new search term const updatedSearchTerm = searchTerm.trim().replace(/\*/g).toLowerCase(); - + // Compare clean new search term with current one and abort if identical const curSearchTerm = component.get('v.searchTerm'); if (curSearchTerm === updatedSearchTerm) { @@ -11,13 +11,13 @@ // Update search term component.set('v.searchTerm', updatedSearchTerm); - + // Ignore search terms that are too small if (updatedSearchTerm.length < 2) { component.set('v.searchResults', []); return; } - + // Apply search throttling (prevents search if user is still typing) let searchTimeout = component.get('v.searchThrottlingTimeout'); if (searchTimeout) { @@ -71,5 +71,13 @@ isSelectionAllowed : function(component) { return component.get('v.isMultiEntry') || component.get('v.selection').length === 0; + }, + + toggleSearchSpinner : function(component) { + const spinner = component.find('spinner'); + const searchIcon = component.find('search-icon'); + + $A.util.toggleClass(spinner, 'slds-hide'); + $A.util.toggleClass(searchIcon, 'slds-hide'); } }) diff --git a/src/main/default/aura/LookupSelectionEvent/LookupSelectionEvent.evt b/src/main/default/aura/LookupSelectionEvent/LookupSelectionEvent.evt new file mode 100644 index 0000000..1bd5748 --- /dev/null +++ b/src/main/default/aura/LookupSelectionEvent/LookupSelectionEvent.evt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/default/aura/LookupSelectionEvent/LookupSelectionEvent.evt-meta.xml b/src/main/default/aura/LookupSelectionEvent/LookupSelectionEvent.evt-meta.xml new file mode 100644 index 0000000..af6e5bb --- /dev/null +++ b/src/main/default/aura/LookupSelectionEvent/LookupSelectionEvent.evt-meta.xml @@ -0,0 +1,5 @@ + + + 44.0 + A Lightning Event Bundle + \ No newline at end of file