In order to bind to something dynamically, you need a reference. Here is a very basic, no-frills, slightly buggy implementation that demonstrates that this basically works.
Notice how I use component.getReference to dynamically link to a field. Also notice how I can bind to the same field twice, which literally lets me modify the same field more than once in real-time, just to prove that they are real references.
With a little more error checking and fact-gathering, this could indeed be a dynamic form with some basic describe data, etc. Notice how I do not use aura:id at all. I simply bound all the fields to a common object, and I could get and retrieve the values at will (in this case, demonstrated through Object.keys). I could also bind this object to, say, a force:recordData to dynamically save the data back to the server, or send it through a server action in Apex.
<aura:application extends="force:slds">
<aura:attribute name="accountRecord" type="Account" default="{ 'sobjectType': 'Account' }" />
<aura:attribute name="edits" type="Aura.Component[]" />
<aura:attribute name="fieldName" type="String" />
<aura:attribute name="output" type="String" />
<aura:handler name="init" value="{!this}" action="{!c.init}" />
{!v.output}
<hr />
{!v.edits}
<ui:inputText value="{!v.fieldName}" />
<ui:button press="{!c.addField}" label="Add" />
<br/>
<ui:button press="{!c.display}" label="Show Data" />
</aura:application>
({
init: function(component, event, helper) {
component.set("v.edits", []);
},
addField: function(component, event, helper) {
var field = component.get("v.fieldName"),
obj = component.get("v.accountRecord");
obj[field] = "";
component.set("v.accountRecord", obj);
$A.createComponent(
"lightning:input", {
value: component.getReference("v.accountRecord."+component.get("v.fieldName")),
label: component.get("v.fieldName"),
type: "Text"
},
$A.getCallback(function(newCmp, status, error) {
var edits = component.get("v.edits");
edits.push(newCmp);
component.set("v.edits", edits);
})
);
},
display: function(component, event, helper) {
var obj = component.get("v.accountRecord");
var results = [];
Object.keys(obj).forEach(function(key) { results.push(key+":"+obj[key])});
component.set("v.output", results.join('\n'));
}
})
Here's a demo of me dynamically binding stuff:
If I am reading your implementation right, then you have got few things wrong here in your implementation. You are not really viewing what is in your component, rather when your component is initialized, you are actually redirecting the flow using force:navigateToSobject
in your donInit
function to the record id mentioned in the function. So you never are in your component.
Going back to force:recordView
, it is a read only representation and does not let you to fetch any further details on the rendered layout viz., fetch specific field values from the view. Though you will have access to the body of the component, but traversing through it to find a field's value will be more cumbersome. If you refer to the documentation, it mentions as below.
If you want granular control over displaying of specific fields, we recommend using lightning:outputField instead.
As for your issue of passing a value from your view to the controller, you have got couple of options.
Option 1 - Modification in your current implementation
Assuming that you want a detail layout using force:recordView
, you can make a server call in your doInit
function to fetch the guid field and populate it on your component. And then when you click the button, use this field's value to pass on to apex controller. Your code will look something like this:
Attribute declaration on component:
<aura:attribute name="guid" type="String" />
In your existing doInit, modify it as:
doInit: function(cmp, event, helper) {
var action = cmp.get('c.getGUID');
action.setParams({ recordId : cmp.get("v.recordId") }
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
cmp.set("v.guid", response.getReturnValue()); // you are setting the guid from server here
}
});
$A.enqueueAction(action);
}
And in your apex controller:
@auraEnabled
public static String getGUID(String recordId) {
// select guid from sso__x where id = :recordId;
// return the guid as retrieved
}
Now you have guid available with your component as an attribute on it, which you can use anywhere in any of the JS function.
So when you click the button, you can fetch the guid in your JS function:
gotoContact: function(cmp) {
var action = ccmp.get('c.getContact');
action.setParams({ guidId : cmp.get("v.guid") }); // notice this line
// call your apex method
// use navigateToSobject here to redirect to the contact id as retrieved.
}
Using this approach, you are using recordView along with a bit of your customization. However note that this may not be most efficient way as this approach is actually making a server trip twice, once for loading the fields with record view and then in your doInit function. But with this approach you easily achieve the detail layout functionality without writing anything around how to render the fields.
Option 2 - Implement using lightning:recordEditForm
With this approach, you will need to write all your fields which you want to display on the page. You can use lightning:inputField with some styling to make it read only, so that it aligns with detail layout, associate the input fields with an aura:id and then retrieve the values in your JS function. You can find more details using lightning:recordEditForm and how to fetch values from it in JS function in this answer here.
Best Answer
Since you are using a mouseover event on div the event.getsource() will not work. event.getSource is limited to lightning:button instead, you need to pass the parameter as a data attribute and access in js using event.target.getAttribute("data-attribute-name"). the data attributes are part of the HTML standard and should work on all standard HTML elements.
Here is a sample code:
Component:
Javascript: