Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Needed Code Coverage > 75% #63

Merged
merged 10 commits into from
Feb 1, 2021
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ Documentation
- [Adopting Dependency Injection](https://douglascayers.com/2018/08/29/adopting-dependency-injection/) (webinar)
- [Understanding the Value of Dependency Injection in the Lightning Platform](https://www.youtube.com/watch?v=oce2QO-E_3k) (DF18 session)

Deploy
------
Deploying from this repo ...

Using the SalesforceDX custom plugin ["shane-sfdx-plugins"](https://github.com/mshanemc/shane-sfdx-plugins) will be the simplest way to accomplish this. If you need to install this plugin, execute the following:
ImJohnMDaniel marked this conversation as resolved.
Show resolved Hide resolved

- sfdx plugins:install shane-sfdx-plugins
- Setup the scratch org - note: if you already have a node available, no need to create a scratch org; just substitue the name for 'myForceDIScratch'
### Steps (Deploying from this repo **bjanderson70**)
- sfdx force:org:create -a myForceDIScratch -f config/project-scratch-def.json
- sfdx shane:github:src:install -c -g **bjanderson70** -r force-di -p force-di -u myForceDIScratch

Project Folders
---------------
The "core" framework is found in this project. This includes the following:
Expand Down
16 changes: 14 additions & 2 deletions config/enterprise-project-scratch-def.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
{
"orgName": "Acme DF18 Enterprise Company",
"orgName": "force-di-scratch-ent",
"edition": "Enterprise",
"features": ["MultiCurrency","AuthorApex"],
"settings": {
"communitiesSettings": {
"enableNetworksEnabled": false
},
"mobileSettings": {
"enableS1EncryptedStoragePref2": false
},
"lightningExperienceSettings": {
"enableS1DesktopEnabled": true
"enableS1DesktopEnabled": true
},
"securitySettings": {
"sessionSettings":{
"sessionTimeout": "TwelveHours"
}
}
}
}
16 changes: 14 additions & 2 deletions config/project-scratch-def.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
{
"orgName": "force-di",
"orgName": "force-di-scratch-dev",
"edition": "Developer",
"features": ["MultiCurrency","AuthorApex"],
"settings": {
"communitiesSettings": {
"enableNetworksEnabled": false
},
"mobileSettings": {
"enableS1EncryptedStoragePref2": false
},
"lightningExperienceSettings": {
"enableS1DesktopEnabled": true
"enableS1DesktopEnabled": true
},
"securitySettings": {
"sessionSettings":{
"sessionTimeout": "TwelveHours"
}
}
}
}
5 changes: 5 additions & 0 deletions force-di/main/aura/di_injector/di_injector.cmp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@

<aura:component controller="di_InjectorController">
<aura:attribute name="bindingName" type="String" required="true"/>
<!-- BJA for container id -->
<aura:attribute name="bindingId" type="String" required="false"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<!-- Added by Leon Kempers: Listen to attribute value change -->
<aura:handler name="attributeChangeEvent" event="c:di_injectorAttributeChangeEvent" action="{!c.handleChangeEvent}" includeFacets="true" />

{!v.body}
</aura:component>
38 changes: 38 additions & 0 deletions force-di/main/aura/di_injector/di_injectorController.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,29 @@
// Resolve the given binding
var action = cmp.get("c.getBinding");
action.setParams({ bindingName : cmp.get("v.bindingName") });

action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var bindingInfo = response.getReturnValue();
var injectAttrs = cmp.get("v.body");

// Construct attributes to pass on to injected component
var componentName = null;
var componentAttrs = {};


if(bindingInfo.BindingTypeAsString == 'Flow') {
componentName = 'c:di_injectorFlowProxy';
componentAttrs['flowName'] = bindingInfo.To;
componentAttrs['injectorAttributes'] = injectAttrs;
} else if(bindingInfo.BindingTypeAsString == 'LightningComponent') {
// Added by Leon Kempers: set aura:id
let bindingId = cmp.get('v.bindingId');
if (typeof bindingId === 'undefined') {
cmp.set('v.bindingId', 'di_component');
}
componentAttrs['aura:id'] = cmp.get('v.bindingId');
componentName = bindingInfo.To;
for (var attrIdx in injectAttrs) {
var injectAttr = injectAttrs[attrIdx];
Expand All @@ -52,6 +62,7 @@
console.log("Binding type " + bindingInfo.BindingTypeAsString + ' not supported');
return;
}

// Inject the component bound to the given binding
$A.createComponent(
componentName,
Expand Down Expand Up @@ -88,5 +99,32 @@
}
});
$A.enqueueAction(action);
},

// Added by Leon Kempers: Listen to attribute value change
//
// added a handler to capture the di_injectorAttributeChangeEvent. When it comes in,
// the handleChangeEvent() function looks at the bindingId variable stored in the component,
// finds the component based on this ID, and changes the specified attribute to the 'newValue'.
//
// The only not-so-pretty thing here is that sometimes (e.g. in case of the spinner) the value
// changed while $A.createComponent was still running (i.e. the Lightning Component hadn't
// been put on the DOM yet). So in that case, we just wait 100ms and try again.
handleChangeEvent : function(component, event, helper) {

let bindingId = component.get('v.bindingId');
let auraCmp = component.find(bindingId);

// Sometimes value will change while the Aura Component hasn't
// been added to the DOM yet; wait 100ms and try again
if (typeof(auraCmp) === undefined) {
setTimeout(function() {
this.handleChangeEvent(component, event, helper);
}, 100);
} else {
let name = event.getParam('name');
let newValue = event.getParam('newValue');
auraCmp.set('v.' + name, newValue);
}
}
})
14 changes: 14 additions & 0 deletions force-di/main/aura/di_injectorAttribute/di_injectorAttribute.cmp
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,18 @@
description="Specific data type the value represents. Helps when mapping values to things like input variables of flows."
required="false"/>

<!-- Added by Leon Kempers: Register attribute value change

fix the issue where attribute values passed to a Lightning Component were only
set upon initialization, and subsequent changes were not handled

added a change handler for the "value" attribute, and registered the
di_injectorAttributeChangeEvent. When the "value" attribute changes, it fires
the di_injectorAttributeChangeEvent, and passes along the name and the new value
of the changed attribute
-->
<aura:handler name="change" value="{!v.value}" action="{!c.handleValueChange}"/>
<aura:registerevent name="attributeChangeEvent" type="c:di_injectorAttributeChangeEvent" />


</aura:component>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
({
// Leon Kempers - handle dynamic value change via event
handleValueChange : function(component, event, helper) {
let name = component.get('v.name');
let newValue = event.getParam('value');

let changeEvent = component.getEvent('attributeChangeEvent');
changeEvent.setParams({ 'name' : name, 'newValue' : newValue });
changeEvent.fire();
}
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<!--
Added Event - Leon Kempers
Component Event to indicate when an attribute value has changed
-->
<aura:event type="COMPONENT" description="Event for sending information to encapsulated component">
<aura:attribute name="name" type="String" />
<aura:attribute name="newValue" type="String" />
</aura:event>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<AuraDefinitionBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<description>A Lightning Event Bundle</description>
</AuraDefinitionBundle>
2 changes: 1 addition & 1 deletion force-di/main/classes/di_Binding.cls
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public abstract class di_Binding implements Comparable {
{
if ( this.bindings == null )
{
System.debug('// di_Binding.Resolver :: Loading Bindings //');
//System.debug('// di_Binding.Resolver :: Loading Bindings //');
ImJohnMDaniel marked this conversation as resolved.
Show resolved Hide resolved
// Ask each module to configure and aggregate the resulting bindings
this.bindings = new List<di_Binding>();
for (di_Module module : modules)
Expand Down
68 changes: 34 additions & 34 deletions force-di/main/classes/di_BindingParam.cls
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/
**/

public with sharing class di_BindingParam {

Expand All @@ -32,7 +32,7 @@ public with sharing class di_BindingParam {

@InvocableMethod(
label = 'Get Value'
)
)
public static List<Response> invoke( List<Request> requests ) {

List<Response> responses = new List<Response>();
Expand Down Expand Up @@ -177,18 +177,18 @@ public with sharing class di_BindingParam {

} else {

System.debug( LoggingLevel.WARN, 'BindingParam.parameters.get("' + req + '") is null' );
// System.debug( LoggingLevel.WARN, 'BindingParam.parameters.get("' + req + '") is null' );
ImJohnMDaniel marked this conversation as resolved.
Show resolved Hide resolved

}

} else {

System.debug( LoggingLevel.WARN, 'BindingParam.parameters is null' );
// System.debug( LoggingLevel.WARN, 'BindingParam.parameters is null' );

}

System.debug( 'paramName=' + req );
System.debug( res );
// System.debug( 'paramName=' + req );
// System.debug( res );

responses.add( res );

Expand All @@ -214,8 +214,8 @@ public with sharing class di_BindingParam {

private static Long toLongValue( Date value ) {
return ( value == null ? null : toLongValue(
DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 )
));
DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 )
));
}

private static Long toLongValue( DateTime value ) {
Expand All @@ -235,8 +235,8 @@ public with sharing class di_BindingParam {

private static Decimal toDecimalValue( Date value ) {
return ( value == null ? null : toDecimalValue(
DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 )
));
DateTime.newInstance( value.year(), value.month(), value.day(), 0, 0, 0 )
));
}

private static Decimal toDecimalValue( DateTime value ) {
Expand Down Expand Up @@ -333,8 +333,8 @@ public with sharing class di_BindingParam {

@InvocableVariable(
label = 'Parameter Name'
required = true
)
required = true
)
public String paramName;

}
Expand All @@ -343,72 +343,72 @@ public with sharing class di_BindingParam {

@InvocableVariable(
label = 'Number'
description = 'Whole number (no decimals)'
)
description = 'Whole number (no decimals)'
)
public Long longValue;

@InvocableVariable(
label = 'Decimal'
description = 'Number that may include decimal places'
)
description = 'Number that may include decimal places'
)
public Decimal decimalValue;

@InvocableVariable(
label = 'Text'
description = 'Text value'
)
description = 'Text value'
)
public String stringValue;

@InvocableVariable(
label = 'Boolean'
description = 'true/false'
)
description = 'true/false'
)
public Boolean booleanValue;

@InvocableVariable(
label = 'Date'
)
)
public Date dateValue;

@InvocableVariable(
label = 'Date/Time'
)
)
public DateTime dateTimeValue;

@InvocableVariable(
label = 'Number Collection'
description = 'Collection of whole numbers'
)
description = 'Collection of whole numbers'
)
public Long[] longValues = new Long[] {};

@InvocableVariable(
label = 'Decimal Collection'
description = 'Collection of numbers that may include decimal places'
)
description = 'Collection of numbers that may include decimal places'
)
public Decimal[] decimalValues = new Decimal[] {};

@InvocableVariable(
label = 'Text Collection'
description = 'Collection of text values'
)
description = 'Collection of text values'
)
public String[] stringValues = new String[] {};

@InvocableVariable(
label = 'Boolean Collection'
description = 'Collection of true/false values'
)
description = 'Collection of true/false values'
)
public Boolean[] booleanValues = new Boolean[] {};

@InvocableVariable(
label = 'Date Collection'
description = 'Collection of date values'
)
description = 'Collection of date values'
)
public Date[] dateValues = new Date[] {};

@InvocableVariable(
label = 'Date/Time Collection'
description = 'Collection of date/time values'
)
description = 'Collection of date/time values'
)
public DateTime[] dateTimeValues = new DateTime[] {};

}
Expand Down
Loading