I just did something like this the other day. Not sure if it meets all your needs but it at least illustrates the concept
Component Controller
({
doinit: function(component,event,helper){
<iframe name="pc-frame" src="{!v.iframe-url}" style="width: 100%;height: 770px; border: none;" scrolling="true"/>
$A.createComponent(
"aura:html",
{
tag: "iframe",
HTMLAttributes:{
"id": "pc-frame",
"src": tmp,
"scrolling" : "true",
"onload" : component.getReference("c.handlerFunction") //You can change to onclick if your html element supports it
},
}
function(compo){
var container = component.find("container");
if (container.isValid()) {
var body = container.get("v.body");
body.push(compo);
container.set("v.body", body);
}
}
);
},
handlerFunction : function(component, event,helper){
console.log('something');
}
)}
This is an example with LWC lightning-datatable using button as a column and retriving the information with onrowaction, but, the same should be applied to Aura Component lightning:datatable
onrowaction will return the action trigger in the row, it means, from An action field type, from a button or button-icon.
Javascript event:
- event.detail.action.name => Returns the value of the name set in typeAttributes.
- event.detail.row => Returns an Object with the values of the row
- event.detail.row.columnFieldName => Returns the value in an specific column
Paste this example in LWC Playground and check out the Console:
HTML
<template>
<div style="height: 300px;">
<lightning-datatable
key-field="id"
data={data}
columns={columns}
onrowaction={viewRecord}/>>
</lightning-datatable>
</div>
</template>
Basic.js
import { LightningElement } from 'lwc';
import fetchDataHelper from './fetchDataHelper';
const columns = [
{ label: 'Label', fieldName: 'name' },
{ label: 'Website', fieldName: 'website', type: 'url' },
{ label: 'Phone', fieldName: 'phone', type: 'phone' },
{ label: 'Balance', fieldName: 'amount', type: 'button',
typeAttributes: {
label: { fieldName: 'amount' },
name: 'amount'
},
},
{ label: 'CloseAt', fieldName: 'closeAt', type: 'date' },
];
export default class BasicDatatable extends LightningElement {
data = [];
columns = columns;
viewRecord(event){
console.log(event.detail.action.name);
console.log(event.detail.row.name);
}
// eslint-disable-next-line @lwc/lwc/no-async-await
async connectedCallback() {
const data = await fetchDataHelper({ amountOfRecords: 100 });
this.data = data;
}
}
fetchDataHelper.js
const recordMetadata = {
name: 'name',
email: 'email',
website: 'url',
amount: 'currency',
phone: 'phoneNumber',
closeAt: 'dateInFuture',
};
export default function fetchDataHelper({ amountOfRecords }) {
return fetch('https://data-faker.herokuapp.com/collection', {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify({
amountOfRecords,
recordMetadata,
}),
}).then(response => response.json());
}
Best Answer
Hope it is not too late, I did some digging on my own and did not find enough evidence to set dynamic javascript methods using the set() method. Even returning concrete references did not help in this case. So here is my theory
When we use
We get the following error
As it states "Value provider does not implement set(key,value)", It looks like the set property is not available for the onclick attributes. Maybe it is working as designed. Salesforce does not want us to implement it this way.
Solution :
In our scenario, as you suggested earlier you could use an if-else condition to perform your logic. But it looks messy, you would have to go through 2 methods (openDropdown & showDefaultValue ) every time some-one clicks, and this would add complexity to the logic. Hence I propose the following one.
Use Dynamic Components instead of setting the values. It works kinda similar to the set() approach that you used.
Component :
Controller :
Results :
Lightning button before clicking
Lightning button after clicking, it enters the opendropdown method
Finally, when clicking on the close button, it enters showDefaultValue methd without entering the opendropdown method. This approach kind of works in the same as your component.set() logic but in addition, it creates a dynamic component and sets the v.body attribute of the outer container to the newly created component.