LWC Related List Inline Editing with Dynamic Columns - salesforce

I hope you can help. I'm wanting to create a LWC that uses the Datatable component with Inline Editing. but which get's the columns to display from the Lightning Page Parameters in the JS.Meta file Properties.
For instance, the Properties will have a field for inputting the fields we want to display in the related list in a comma deliminated fashion, and the passes these fields into the component / a dynamic piece of soql to be used in the Edtiable List.
All of the examples i have found have statically declared columns like below. But i really want these to be defined in the Lightning Builder Page so the component can be re-used on multiple objects and with different fields etc:
Class:
public with sharing class ContactController {
#AuraEnabled(cacheable=true)
public static List<Contact> getContactList() {
return [SELECT Id, FirstName, LastName, Title, Phone, Email FROM Contact LIMIT 10];
}
}
HTML:
<template>
<lightning-card title="Datatable Example" icon-name="custom:custom63">
<div class="slds-m-around_medium">
<template if:true={contact.data}>
<lightning-datatable
key-field="Id"
data={contact.data}
columns={columns}
onsave={handleSave}
draft-values={draftValues}>
</lightning-datatable>
</template>
<template if:true={contact.error}>
<!-- handle Apex error -->
</template>
</div>
</lightning-card>
</template>
JS:
import { LightningElement, wire, track } from 'lwc';
import getContactList from '#salesforce/apex/ContactController.getContactList';
import { updateRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '#salesforce/apex';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import FIRSTNAME_FIELD from '#salesforce/schema/Contact.FirstName';
import LASTNAME_FIELD from '#salesforce/schema/Contact.LastName';
import ID_FIELD from '#salesforce/schema/Contact.Id';
const COLS = [
{ label: 'First Name', fieldName: 'FirstName', editable: true },
{ label: 'Last Name', fieldName: 'LastName', editable: true },
{ label: 'Title', fieldName: 'Title' },
{ label: 'Phone', fieldName: 'Phone', type: 'phone' },
{ label: 'Email', fieldName: 'Email', type: 'email' }
];
export default class DatatableUpdateExample extends LightningElement {
#track error;
#track columns = COLS;
#track draftValues = [];
#wire(getContactList)
contact;
handleSave(event) {
const fields = {};
fields[ID_FIELD.fieldApiName] = event.detail.draftValues[0].Id;
fields[FIRSTNAME_FIELD.fieldApiName] = event.detail.draftValues[0].FirstName;
fields[LASTNAME_FIELD.fieldApiName] = event.detail.draftValues[0].LastName;
const recordInput = {fields};
updateRecord(recordInput)
.then(() => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Success',
message: 'Contact updated',
variant: 'success'
})
);
// Clear all draft values
this.draftValues = [];
// Display fresh data in the datatable
return refreshApex(this.contact);
}).catch(error => {
this.dispatchEvent(
new ShowToastEvent({
title: 'Error creating record',
message: error.body.message,
variant: 'error'
})
);
});
}
}
Ideally, i'd like to declare the Object and Fields etc in the JS-Meta file, like below. And have these pass into the class / JS etc:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="EditableRelatedList">
<apiVersion>45.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
</targets>
<targetConfigs>
<!-- Component UI Properties -->
<targetConfig targets="lightning__RecordPage">
<property name="strTitle" type="String" label="Title" description="Enter the title"/>
<property name="objectName" type="String" label="Object Name" description="Enter the object name"/>
<property name="parentFieldAPIName" type="String" label="Parent Field API Name" description="Enter the parent field API Name"/>
<property name="whereClause" type="String" label="WHERE Clause" description="Enter your WHERE clause (Not Required). Do not include 'WHERE'. Eg: firstName = 'David' AND lastName != 'Bradbury'"/>
<property name="fields" type="String" label="Fields" description="Enter the API Names of the fields you would like to use in this Related List seperated by a comma. Eg: FirstName, LastName, CustomField1__c, CustomField2__c "/>
<property name="errorMessage" type="String" label="Error Message" description="Enter your Error Message for when there are 0 records"/>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
Thanks in advance!!

Related

Custom data attributes on Fluent UI dropdown

I have a requirement to add custom data attributes to the Fluent UI dropdown.
In javascript/html I could add them like this.
option data-passign="true" data-minpt="3" data-maxpt="6" value="7">Data Quality</option
Can someone help me achieve this in Fluent UI + React?
In FluentUI/React, it's much easier than that, no need for data- attributes, you can just add your custom data directly to the options list (and get it back in the event handlers, or as the selected value if you are using "controlled" scenario). Means, if you don't have a specific requirement to store additional item data in the HTML data attributes for "something else" (like ui-automation tool), then you could go with something like this (note the data property):
const YourComponent = (props) => {
const options = [
{ key: '7',
text: 'Data Quality',
data: { passign: true, minpt: 3, maxpt: 7 }
},
{ key: '42',
text: 'Weather Quality',
data: { passign: true, minpt: 100500, maxpt: 42 }
},
];
const onChange = (evt, item) => {
const itemData = item.data;
console.log(item.key, item.text, itemData);
};
return (
<Dropdown
label="Select something"
options={options}
defaultSelectedKey='7'
onChange={onChange}
/>
);
}
If you want a "controlled" control instead (this one is "uncontrolled"), check out the sample page for the Dropdown:
https://developer.microsoft.com/en-us/fluentui#/controls/web/dropdown

React Admin - ReferenceInput with multiple fields output

I'm using React with React Admin to populate my database in which I have 2 collections: products and stores
I need to link a store to the product, so normally I should do:
<ReferenceInput label="Store" source="storeId" reference="stores">
<SelectInput optionText="name" />
</ReferenceInput>
But this will generate this structure:
{
id: '...'
// other attributes
storeId: "choosed-store-id"
}
But the final result I need is something like this:
{
id: '...'
// other attributes
store: {
id: "choosed-store-id",
name: "choosed-store-name",
address: "choosed-store-address"
}
}

react-semantic-redux-form selectField multiple

I am attempting to use react-semantic-redux-form SelectField with the multiple options so a user can select multiple options and if there is one already set then this should show as checked.
I am also using redux-form with semantic0ui-react.
I am getting an error attempting to include multiple selections.
My include statement is:
import { SelectField } from "react-semantic-redux-form";
My state is:
state = {
relationships: ["some entry"],
relationshipOptions: [],
};
The element code is:
<Grid.Column>
<Field
component={SelectField}
name="relationships"
label="Your Relationships"
options={relationshipOptions}
multiple
placeholder="Select to add a relationship"
/>
I get the error as below
Dropdown `value` must be an array when `multiple` is set. Received type: `[object String]`.
in Dropdown
The way you have relationshipOptions is wrong, it is supposed array of objects,
const relationshipOptions = [
{ key: "single", value: "single", text: "single" },
{ key: "married", value: "married", text: "married" }
];
Here is the working example, Code Sandbox
Also if you have single, married in array. You can do something like this,
let relationshipOptions = ["single", "married"].map((x) => {
return ({
key: x,
value: x,
text: x
});
});

How to group rows in Kendo UI Grid

I was able to do the following using kendo-ui-recat-wrapper to get a grouped Grid :
let dataSource = {
data: data,
schema: {
model: {
id: 'id',
expanded: true
}
},
group: [
{
field: 'title', // GroupBy goes on this field
dir: 'asc'
} ] }
And Then I can pass this to the dataSource props of Grid.
I updated to kendo-react-grid it seems more coherent to use in a ReactJs project than the jquery wrapper.
But I didn't find how to get the same result ? There is no mention to the group option. Even here in DataState (link here) I didn't get how to use it ?!
EDIT : The option is not ready yet (Kendo ui React roadmap)
Currently, the native Kendo React Grid supports grouping. The syntax is different than as per the jquery wrapper (i.e. there is no dataSource prop) but I believe this is expected. Here is a simplified version of the official grouping example:
import { Grid, GridColumn as Column } from '#progress/kendo-react-grid';
import { groupBy } from '#progress/kendo-data-query';
import products from './products.json';
class App extends React.PureComponent {
render() {
return (
<Grid
groupable={true}
group={[ { field: 'UnitsInStock' } ]}
data={groupBy(products, [ { field: 'UnitsInStock' } ])}
>
<Column field="ProductID" title="ID" width="50px" />
<Column field="ProductName" title="Product Name" />
<Column field="UnitsInStock" title="Units In Stock" />
</Grid>
);
}
}

Angular 2 RC4 - Select ngModel delayed update

I'm trying to create a select control that will bind the value to an Object and on change I can get access to the selected object.
I know there has a been a lot of changes in the forms so not sure if this is a user error or bug or not possible.
Here is where I'm at so far: Link to Plunker
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
template: `
<h1>My First Angular 2 App</h1>
<select (change)="onChange($event)" [(ngModel)]="selected">
<option value=''></option>
<option *ngFor="let d of data" [ngValue]="d">
{{d.name}}
</option>
</select>
`
})
export class AppComponent {
diagnostic;
selected;
data = [
{ id: 1 , name: 'query 1', filters: [
{ 'filter1': 'material = 1'},
{'filter2': 'plant = 2'}
]
},
{ id: 2 , name: 'query 2', filters: [
{ 'filter1': 'material = 1'},
{'filter2': 'plant = 2'}
]
}
];
onChange(event) {
console.log(event.target.value);
console.log(this.selected);
}
}
What I would like to have happen is that when the onChange event is called that either I pass the Object value of the selected item into that method or get access to the selected value through the property bound in ngModel.
//expected
onChange(event) {
console.log(event.target.value) // selected object bound to ngValue
console.log(this.selected) // ngModel updated to object bound to selected option
}
But unfortunately, the event.target.value is a string version of the object and this.selected sort of works but is always behind on being updated.
Is there another way or proper way to handle this? Is the delay in the ngModel a bug?
Any help would be appreciated!
You should define select inputs/outputs as following:
<select [(ngModel)]="selected" (ngModelChange)="onChange()">
<option *ngFor="let d of data" [ngValue]="d">
{{d.name}}
</option>
</select>
and then the model is correctly applied to the property. http://plnkr.co/edit/JGgflTY9LvrDDhqqlSGP?p=preview
Notice that the definition of ngModel and ngModelChange should be ordered as is in example :)

Resources