What would cause difference between data after usage in ExtJS store - javascript

I use the function at the bottom to (re)create a store every time a grid within a (popup) window renders. However I don't understand why typeDetails is different from what gets logged on the longish line with Ext.pluck (based on https://stackoverflow.com/a/5709096/34806).
The former console log always prints what I expect, in the default case [{"label":"","value":""}], or when typeDetails is pre-populated something such as:
[{"label":"foo","value":"bar"},{"label":"what","value":"ever"}]
But the latter console.log always indicates an empty array, and I always get an empty grid. Could the line with pluck be at fault? That answer, though not the accepted or top-scoring, has been up-modded over 20. What else can I do to work through this.
listeners: {
render: {
fn: function (grid) {
var typeDetails = this.typeDetails || [{ 'label': '', 'value': ''}];
var store = Ext.create('Ext.data.Store', {
fields: ['label', 'value'],
data: [typeDetails]
});
console.log(Ext.encode(typeDetails));
console.log(Ext.encode(Ext.pluck(grid.store.data.items, 'data')));
grid.reconfigure(store);
}
}
}
UPDATE/OUTPUT
In response to Evan's comment "In the case where it defaults data, the store data will be [[{label: '', value: ''}]]" below is what is actually directly copied/pasted from my console:
[{"label":"","value":""}]
[]
However I think this is because the logging is before grid.reconfigure. Nevertheless shifting my console/logging as follows:
grid.reconfigure(store);
console.log(Ext.encode(this.typeDetails));
console.log(Ext.encode(typeDetails));
console.log(Ext.encode(Ext.pluck(grid.store.data.items, 'data')));
Results in the following mysterious output in the non-default case (when this.typeDetails is pre-populated):
[{"label":"foo","value":"bar"},{"label":"what","value":"ever"}]
[{"label":"foo","value":"bar"},{"label":"what","value":"ever"}]
[{"label":"","value":""}]
It's an editable grid, and the non-default values can only exist after the default empty row, so it's as though that empty row is being retained.

The following alternative approach works:
listeners: {
render: {
fn: function (grid) {
var store = Ext.create('Ext.data.Store', {
fields: ['label', 'value'],
data: []
});
if (this.typeDetails) {
for (var i = 0, n = this.typeDetails.length; i < n; i++) {
store.add(this.typeDetails[i]);
}
}
else {
store.add({ 'label': '', 'value': '' });
}
grid.reconfigure(store);
}
}
}

Related

Refresh table LWC

I've been trying to rerender a table when I update an Account record with a lightning-record-form.
I tried looking up a solution to this with similar questions I found here but I'm still not able to achieve this.
In this case I hardcoded the recordId with the Account with the name 'Gonzalo' shown in the preview below all the code. So the wanted result is to update the account name or any field and see the instant outcome in the table.
Here's my code:
Apex method (just in case):
#AuraEnabled(cacheable=true)
public static List<Account> getCuentas() {
return [SELECT id, Name, Phone FROM Account LIMIT 5];
}
Form (HTML):
<lightning-record-form
object-api-name="Account"
record-id="0015e00000F2JoWAAV"
fields={fields}
onsubmit={handleSubmit}
>
</lightning-record-form>
Table (HTML):
<lightning-datatable
key-field="pk"
data={cuentas}
columns={columnas}
onrowselection={action}
hide-checkbox-column
onrowaction={handleRow}
default-sort-direction={defaultSortDirection}
sorted-direction={sortDirection}
sorted-by={sortedBy}
onsort={onHandleSort}
>
</lightning-datatable>
Related code (JS):
***Imports***
import { refreshApex } from '#salesforce/apex';
import NAME from '#salesforce/schema/Account.Name';
import PHONE from '#salesforce/schema/Account.Phone';
import getCuentas from '#salesforce/apex/ProbandoJSON.getCuentas';
import { LightningElement, api, wire, track } from 'lwc';
***Vars for the form fields***
fields = [NAME, PHONE];
***Columns***
columnas = [
{
label: 'View',
type: 'button',
initialWidth: 75,
typeAttributes: {
label: {
fieldName: 'Boton'
},
title: 'Preview',
alternativeText: 'View',
variant: 'border-filled'
}
},
{
label: 'Name',
fieldName: 'Name',
sortable: true
},
{
label: 'Phone',
fieldName: 'Phone'
}
];
***Accounts***
#track cuentas = [];
_wiredResult;
#wire(getCuentas)
wireCuentas(result) {
this._wiredResult = result;
if(result.data) {
console.log('cuentas');
console.log(result.data);
for(var i in result.data) {
let obj = {};
obj.Id = result.data[i].Id;
obj.Name = result.data[i].Name;
obj.Phone = result.data[i].Phone;
obj.Boton = parseInt(i) + 1;
this.cuentas = [...this.cuentas, obj];
}
console.log('cuentas de nuevo');
console.log(this.cuentas);
} else if(result.error) {
console.log('error cuentas');
console.log(result.error);
}
}
***Submit handler for the Save button in the form***
handleSubmit(event) {
console.log('saving...')
return refreshApex(this._wiredResult);
}
Preview of the component:
Table
Form
Looks like a cache issue.
We can solve this in a couple of ways as follow:
Removing cacheable
You need to remove (cacheable=true) and then have to call the apex method imperatively on each form updates or while loading initial data.
Creating an unnecessary parameter in apex method which will be having new value on each call
You need to receive an additional parameter as a integer in the apex method, and then in lwc just create a var initializing it with 0, and on each update increment it by 1.
Then use same var to call the apex method via wire or in imperative calls.

Clean input before change

I'm using handsontable 0.35.1 with a float column. Aim is to allow users to copy paste from spreadsheets (and csvs opened in excel). Problem is, that it comes with some junk that i need to get rid of. Some examples of inputs which are not correctly validated are:
1,000.00
USD 100.00
'10000.00 ' //note there are trailing spaces
I would like to find a way i can manipulate input right before it's written. The only way i've found so far is with beforeChange, but the problem is validation. The system changes input, but seems to have validated already. If i blur in and blur out again, it works.
Here's the fiddle. Steps to reproduce: Enter number a123 -- which should be corrected to 123 and validated as a correct number.
I've tried using beforeValidation instead, but it doesn't work as i intend.
You can use beforePaste callback to clean your input
options = {
columns: [
{ type: 'date' },
{ type: 'numeric', numericFormat: {pattern: '0,0.00'} }
],
colHeaders: ["Date", "Float"],
beforePaste: (data, coords) => {
data.forEach((col, colIndex) => {
col.forEach((row, rowIndex) => {
let value = row.trim().replace(/[^0-9\.\-\+]/g, '')
data[colIndex][rowIndex] = value
})
})
return true
},
}
$('#hot-sheet').handsontable(options)
here is fiddle https://jsfiddle.net/xpvt214o/348195/
Note: you can't create new data array, you've to update data array instead of creating new.
I updated the example https://jsfiddle.net/fma4uge8/29/ this works all in 1 function.
function trimFloat(value) {
return value.trim().replace(/[^0-9\.\-\+]/g, '');
}
options = {
columns: [
{ type: 'date' },
{ type: 'numeric', numericFormat: {pattern: '0,0.00'}, trimWhitespace: true }
],
colHeaders: ["Date", "Float"],
beforeChange: function(changes, source){
let that = this;
_.each(changes, function(change){
if (_.isString(change[3])) {
let value = trimFloat(change[3]);
//prevent endless loop
if (value !== change[3]) {
change[3] = trimFloat(change[3]);
that.setDataAtCell(change[0], change[1], change[3]);
}
}
})
}
}
$('#hot-sheet').handsontable(options)

How setup valuegetter for auto Group Column in Ag-Grid

I have autoGroupColumnDef and I want to setup text filter. But values of the column come from getDataPath method. But I need another value in the filter.
autoGroupColumnDef: {
headerName: "Systems",
filter: 'text',
valueGetter: function(params) {
var result = params.data.hospName || params.data.hospitalSystem;
return result;
},
cellRendererParams: {
suppressCount: true,
innerRenderer: function(params) {
var result = params.data.hospName || params.data.hospitalSystem;
return result;
}
}
},
After trying on couple of things,
Option 1: You can make use of [filterParams][1]. This only helps to play around with options/choices in the filterMenu..
function filterCellRenderer(params) {
//other than params.value nothing else will be there..
// params.data won't be there when its called from filter popup
return params.value+" Custom";
}
var gridOptions= {
...,
treeData: true,
components: {
...,
filterCellRenderer: filterCellRenderer
},
autoGroupColumnDef: {
...,
filterParams: {
cellRenderer: 'filterCellRenderer',
//values: ["A", "XYZ"] //you can feed directly specific values. These need to be part of filePath. Else filtering won't work.
}
}
}
Option 2: If you are looking for custom filter (tweak with GUI), or you want to post processing after it has been configured by ag-grid you can define the following:
var gridOptions = {
...
getMainMenuItems: getMainMenuItems,// function to build your own menu
postProcessPopup: function(params){
// edit the popup..
//params.type gives whether its column menu or not.
//params.ePopup gives handler to popup which you can modifiy.
},
...
}
OR you can build your own custom filter as described here

array copy keeps changing without edition

I am working on a simple list builder, i can create and edit the list, basicly i have a modal where i build the list after that i can edit it, my issue is if i edit and change the number of items inside the list without pressing the edit, the changes to the list apply. all the rest that i change and don't press edit, works well.
Here is a example:
my modal edition:
data () {
return {
newItem: '',
listItem: 0,
showNewItem: false,
bulletList: {
currentSymbol: '•',
key: 'List',
items: [
],
ordered: false,
numbering: 38
},
listOptions: [
{ 'symbol': '•', 'number': 37 },
{ 'symbol': '1', 'number': 1 }
]
}
},
in my edition the only thing that can change is the bulletList object, so when i press the edition section it loads the object like this:
mounted () {
console.log('MOUNTED', this.bulletList.items)
var sectionKey = this.$store.getters.getCurrentEditionKey
this.bulletList =_.clone(this.$store.getters.getDocumentAttributes[sectionKey])
}
when i add a item to edit my bulletList and close the configuration modal it added(it shouldn't) the only thing i do when i add a new item is to push it to the local object inside my component, and not the one that i copied from vuex store, strange issue any help? it has something to do with the array behaviour?
removeItem () {
this.bulletList.items.splice(this.listItem, 1)
this.listItem = 0
},
addNewItem () {
this.bulletList.items.push(this.newItem)
this.newItem = ''
},

Rally SDK: Retrieving all available State values for Defects

I want to retrieve all available State values for Rally Defect.
The following code works good for Features:
this.states = [];
this.stateStore = Ext.create('Ext.data.Store', {
fields: ['_ref', 'name']
});
Ext.create('Rally.data.wsapi.Store', {
model: 'State',
autoLoad: true,
filters: [
{
property: 'Enabled',
operation: '=',
value: true
},
{
property: 'TypeDef.Name',
operation: '=',
value: 'Feature'
}
],
listeners: {
load: function (store, data) {
for (var i = 0; i < data.length; i++) {
this.stateStore.add({ '_ref': data[i].data._ref, 'name': data[i].data.Name });
}
this.statesLoaded = true;
this._initialLoad();
},
scope: this
}
});
With this approach, we load all available State values for features. However, when I change 'Feature' TypeDef.Name filter to 'Defect', I get nothing despite the fact that there are many active States for Defect defined.
Does anybody know why this happens and how get State values for Defect?
Maybe Defects use some other states, not like features, suer stories etc?
In WS API there is a full State object that represents State of PortfolioItems. It is different from the State or ScheduleState of such artifacts as Defect or UserStory, which are only string values in the dropdown field. There is no such thing as State.Name for a Defect.
Using promises, this may look like this:
launch: function(){
this._getModel().then({
success: this._getAllowedValues,
scope:this
}).then({//...})
},
_getModel:function(){
return Rally.data.ModelFactory.getModel({
type:'Defect'
});
},
_getAllowedValues:function(model){
var deferred = Ext.create('Deft.Deferred');
var allowedStateValues = [];
model.getField('State').getAllowedValueStore().load({
callback: function(records,operation,success){
Ext.Array.each(records,function(allowedValue){
allowedStateValues.push(allowedValue.get('StringValue'));
});
if(success){
deferred.resolve(allowedStateValues);
}
else{
deferred.reject();
}
}
}) ;
return deferred.promise;
},//...
See this example that retrieves allowed values for Priority and Severity of defects. Since those allow null values, null values are removed in this app example, but State does not have null values so you may skip that step.

Categories