I am trying to save PivotGrid state for future load. I have two problems
1: the expand property of row items is not changed at run time. Test here https://dojo.telerik.com/#Mzand/obIkEdAY : When the user expands an item at runtime the expand property of the returned row by dataSource.rows() is the same as what it was at initialization.
2: I can't find a way to save/load the selected feilds (slices) using the "Fields to Include" menu along side with rows,columns and measures.
I'm working in React but you should be able to do something similar.
This is a bug, to work around it you can listen to expandMember and collapseMember events to manually track the axis and path of expanded rows/columns. see code below.
If you mean the Configurator, just set its dataSource to that of the pivot grid after you create it. See below in createGrid().
Bonus, see the end of createGrid to auto expand the items in the Configurator.
createGrid = () => {
$(`#pivot-grid`).kendoPivotGrid({
dataSource: {
data: data,
schema: schema,
columns: this.state.columns,
rows: this.state.rows,
measures: this.state.measures,
filter: this.state.filter
},
expandMember: this.onExpand,
collapseMember: this.onCollapse
});
let grid = $(`#pivot-grid`).data('kendoPivotGrid');
if (grid) {
if (this.state.expands) {
this.state.expands.forEach(expand => {
if (expand.axis === 'rows') {
grid.dataSource.expandRow(expand.path);
} else {
grid.dataSource.expandColumn(expand.path);
}
});
}
$(`#pivot-config`).kendoPivotConfigurator({
dataSource: grid.dataSource,
filterable: true
});
}
// Expand the items in the configurator fields.
let tree = $('.k-treeview').data('kendoTreeView');
if (tree) {
tree.expand('.k-item');
}
};
onExpand = e => {
this.setState({
expands: [...this.state.expands, {
axis: e.axis,
path: e.path
}]
});
};
onCollapse = e => {
this.setState({
expands: this.state.expands.filter(ex => ex.axis !== e.axis && JSON.stringify(ex.path) !== JSON.stringify(e.path))
});
};
Here is my try on this
what i like is, that it actually updates the data source as you would expect
function onExpandOrCollapseMember(e, expand) {
var pivot = e.sender;
var axisToUpdate = '_' + e.axis;
var field = _.find(pivot.dataSource[axisToUpdate], f => JSON.stringify(f.name) === JSON.stringify(e.path));
field.expand = expand;
}
And on the pivot options i pass in
expandMember: e => onExpandOrCollapseMember(e,true),
collapseMember: e => onExpandOrCollapseMember(e, false),
Related
I am trying to only load and save a work order record using the map-reduce script. But I don't see logs for loaded work orders or saved work orders. the script is executing only until work_order_Id. Please Help!
Below is my code...
function getInputData(){
var process_data =[];
try{
var workorderSearchObj = search.create({
type: "workorder",
filters:
[
["type","anyof","WorkOrd"],
"AND",
["mainline","is","T"],
"AND",
["status","anyof","WorkOrd:A","WorkOrd:B","WorkOrd:D"]
],
columns:
[
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: "tranid", label: "Document Number"})
]
});
var searchResultCount = workorderSearchObj.runPaged().count;
log.debug("workorderSearchObj result count",searchResultCount);
workorderSearchObj.run().each(function(result){
// .run().each has a limit of 4,000 results
var work_Order = result.getValue({name:'internalid'});
var document_no = result.getValue({name:'tranid'});
process_data.push({
'work_Order':work_Order,
'document_no':document_no
});
return true;
});
}catch(error){
log.debug(error);
}
return process_data;
}
function map(context){
var process_data=JSON.parse(context.value);
log.debug('process_data',process_data);
var work_order_Id = process_data.work_Order;
log.debug("work_order_Id",work_order_Id);
var work_Order_obj = record.load({
type: record.Type.WORK_ORDER,
id: work_order_Id,
isDynamic: true
});
log.debug("work_Order_obj",work_Order_obj);
var recId=work_Order_obj.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("recId",recId);
}
I am trying to load and save work order record. But its not executing.I am trying to load and save a work order record. but it's not loading.
I usually like to simply return saved searches in getInputData because it's consistent to work with and you don't have to fuss with the going over 4k search results and having to return arrays of objects that you put together yourself. Usually transforming data to be in the format you want is best done in the map stage.
/**
* #NScriptType MapReduceScript
* #NApiVersion 2.x
*/
define(["N/search", "N/record"], function (search, record) {
function getInputData() {
// run a saved search of work orders
return search.create({
type: "workorder",
filters: [
["type","anyof","WorkOrd"],
"AND",
["mainline","is","T"],
"AND",
["status","anyof","WorkOrd:A","WorkOrd:B","WorkOrd:D"]
],
columns: [
search.createColumn({name: "internalid", label: "Internal ID"}),
search.createColumn({name: "tranid", label: "Document Number"}),
]
});
}
function map(context) {
// get the work order id
var workOrderId = JSON.parse(context.value).id;
log.debug("workOrderId", workOrderId);
// load the work order
var wordOrderRecord = record.load({
type: record.Type.WORK_ORDER,
id: work_order_Id,
isDynamic: true,
});
log.debug("wordOrderRecord", wordOrderRecord);
// save the work order
var recId = wordOrderRecord.save({
enableSourcing: true,
ignoreMandatoryFields: true
});
log.debug("recId",recId);
}
function summarize(context) {
// log any errors that might occur
context.mapSummary.errors.iterator().each(function (_, errJson) {
var error = JSON.parse(errJson);
log.error({title: error.name, details: error.message});
return true;
});
}
return {
getInputData: getInputData,
map: map,
summarize: summarize,
};
})
I tried reactive form valueChanges but valueChanges method doesn't return input field name which has changed.
I thought code like this. but I think this is not smart way. Because I have to compare every each input field. so I need more smart way.
// get init view data from local storage
this.localstorageService.getPlaceDetail().subscribe(data => {
this.initPlaceDetail = data;
// watch changed value
this.editPlaceForm.valueChanges.subscribe(chengedVal => {
if (chengedVal['ja_name'] !== this.initPlaceDetail.languages.ja.name.text) {
this.changedJA = true;
}
if (chengedVal['ja_romaji'] !== this.initPlaceDetail.languages.ja.name.romaji) {
this.changedJA = true;
}
// ...... I have to check all input fields??
});
});
I'm adding form controls from an array and something like this worked for me. Just reference the item you need instead of expecting the valueChanges observable to pass it to you.
myFields.forEach(item => {
const field = new FormControl("");
field.setValue(item.value);
field.valueChanges.subscribe(v => {
console.log(item.name + " is now " + v);
});
});
This is my way to get changed control in form.
I shared for whom concerned.
Method to get list control changed values
private getChangedProperties(form): any[] {
let changedProperties = [];
Object.keys(form.controls).forEach((name) => {
let currentControl = form.controls[name];
if (currentControl.dirty)
changedProperties.push({ name: name, value: currentControl.value });
});
return changedProperties;
}
If you only want to get latest changed control you can use
var changedProps = this.getChangedProperties(this.ngForm.form);
var latestChanged = changedProps.reduce((acc, item) => {
if (this.changedProps.find(c => c.name == item.name && c.value == item.value) == undefined) {
acc.push(item);
}
return acc;
}, []);
Instead of listening to whole form changes you can listen to value changes event for each form control as shown in below code:
this.myForm.get('ja_name').valueChanges.subscribe(val => {
this.formattedMessage = `My name is ${val}.`;
});
I am using custom multi-select code to filter a column. Currently I can get it to filter based on one selection, but am unable to filter based on multiple values. I need the logic to read, if any of the selected checkboxes are checked, then show the selections in the grid. The way I have it written right now, its filtering each one, but if one of the selections is false, it deletes it from the grid even if one of the other selections are true.
var filter = dataSource.filter() || { logic: "or", filters: [] };
var fieldFilters = $.map(element.find(":checkbox:checked"), function (input) {
return {
field: field,
operator: "eq",
value: input.value
};
});
if (fieldFilters.length) {
removeFiltersForField(filter, field);
filter.filters.push({
logic: "or",
filters: fieldFilters
});
var filterType = filter.filters[0].filters;
if (filter.filters[0].filters.length > 1) {
var filterLogic = { logic: "or", filters: filter.filters };
dataSource.filter(filterLogic.filters[0]);
} else {
dataSource.filter(filterType); // This works, but its only one selection
}
}
I need it to return if any selections are true and ignore the ones that are false. Currently, it goes in order, so if the first selection is true, it shows it in the grid, but if the next one is false, then it removes it from the grid.
OK I was able to make it work doing this. If someone has a more efficient way to do it, add it here. For now, this works:
var multipleFilters = [];
if (filterType.length > 1) {
$(filterType).each(function (i, value) {
var simpleFilter = { field: value.field, operator: value.operator, value: value.value };
multipleFilters.push(simpleFilter);
})
if (multipleFilters == 2) {
dataSource.filter(multipleFilters[0] || multipleFilters[1]);
} else if (multipleFilters == 3) {
dataSource.filter(multipleFilters[0] || multipleFilters[1] || multipleFilters[2]);
} else {
dataSource.filter(multipleFilters[1] || multipleFilters[2] || multipleFilters[3]);
}
} else {
dataSource.filter(filterType);
}
I'm using the DropdownList component from react-widget. In my code, there are a couple of dropdowns that get their values from an Ajax call. Some of them, like a list of languages, are too big and it's very slow to get the list from Ajax and render it (takes 4 to 5 seconds!). I would like to provide to the dropdwon a small list of languages and an 'Extend' or 'Load Full List' option; if clicking on Extend the dropdown would be refreshed with the full list of languages.
Here is my solution: the code of the parent component:
const languages = ajaxCalls.getLanguages();
const langs = {"languages": [["eng", "English"], ["swe", "Swedish"], ["deu", "German"], ["...", "Load Full List"]]};
const common_langs = langs.languages.map(([id, name]) => ({id, name}));
<SelectBig data={common_langs} extend={languages} onSelect={x=>this.setValue(schema, path, x)} value={this.getValue(path)} />;
And here is the code for SelectBig component:
import React from 'react/lib/ReactWithAddons';
import { DropdownList } from 'react-widgets';
const PT = React.PropTypes;
export const SelectBig = React.createClass({
propTypes: {
data: PT.array,
value: PT.string,
onSelect: PT.func.isRequired,
},
maxResults: 50,
shouldComponentUpdate(nextProps, nextState) {
console.log("nextProps = " , nextProps, " , nextState = ", nextState);
const len = x => (x && x.length !== undefined) ? x.length : 0;
// fast check, not exact, but should work for our use case
return nextProps.value !== this.props.value
|| len(nextProps.data) !== len(this.props.data);
},
getInitialState(){
return {
lastSearch: '',
results: 0,
dataList: [],
};
},
select(val) {
if(val.id === "..."){
this.setState({dataList: this.props.extend})
}
this.props.onSelect(val.id);
},
filter(item, search) { .... },
renderField(item) { .... },
render() {
const busy = !this.props.data;
let data;
if(!this.props.extend){
data = this.props.data || [];
} else {
data = this.state.dataList;
}
return (
<DropdownList
data={data}
valueField='id'
textField={this.renderField}
value={this.props.value}
onChange={this.select}
filter={this.filter}
caseSensitive={false}
minLength={2}
busy={busy} />
);
}
});
But it doesn't look good: When the user chooses 'Load Full List', the dropdown list will be closed and user need to click again to see the updated list. Does anyone have a better solution or a suggestion to improve my code?
The picture shows how it looks like right now!
https://www.npmjs.com/package/react-select-2
Better go with this link, it will work
Hello stackoverflow community,
is it somehow possible to disable the sorting mechanism in a grid for every column on a condition? Like...
if the grid hasn't any data loaded,
the sorting should be disabled,
else enabled.
I have the problem that if there is no data and you click on a column to sort, the remote sorting mechanism, will start loading the whole data and sorts it, too ...
This behaviour isn't needed or wished, so I want to disable the sorting possibility.
Your help is appreciated.
Thanks in advance and have a nice day.
This is a bit of a hack, but seems to work OK:
http://jsfiddle.net/q43HC/6/
var data = [{
data1: 'test',
data2: 'test'
}, {
data1: 'test2',
data2: 'test2'
}];
var store = Ext.create('Ext.data.Store', {
fields: ['data1', 'data2'],
data: data
});
Ext.define('SampleGrid', {
extend: 'Ext.grid.Panel',
store: store,
height: 250,
width: 400,
title: 'My Window',
columns: [{
text: 'test',
dataIndex: 'data1'
}, {
text: 'test2',
dataIndex: 'data2'
}],
bbar: [{
text: 'Clear Store',
handler: function() {
store.removeAll();
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
cols[i].doSort(null);
cols[i].__toggleSortState = cols[i].toggleSortState;
cols[i].toggleSortState = function() {};
}
}
}, {
text: 'Reload Store',
handler: function() {
store.loadData(data);
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
if (cols[i].__toggleSortState) {
cols[i].toggleSortState = cols[i].__toggleSortState;
}
}
}
}],
renderTo: Ext.getBody()
});
Ext.onReady(function() {
var grd = new SampleGrid();
});
I am just changing the sort state when the data is removed in order to remove any current sorting then replacing the toggleSortState function with an empty one so clicking the header will not sort the column. When reloading the store I put the function back.. You will have to adapt this to your project, but could create a store aware grid with similar logic.
You can do this globally by overriding the Ext.data.Store.sort method. The system I was working on uses remoteSort and hence hits the server everytime the user clicks the column header to sort, even if the grid itself is empty, pretty much same with your problem.
This is the code that you only need to declare in a single location (ie. your ext-overrides file or commons file), instead of in every single grid:
Ext.define('Ext.overrides.data.Store', {
override: 'Ext.data.Store',
sort: function() {
//prevents the grid from submitting a request if store is empty, for remote sort
if (this.count() > 0) {
this.callParent(arguments);
}
}
});
I have written the following function to achieve the same solution:
function disableColumnSorting(disable){
var grid = Ext.getCmp('billRecordGrid'),
cols = grid.query('gridcolumn'),
colLength = cols.length,
i = 0;
for(i; i < colLength; i++) {
if (disable) {
cols[i].sortable= false;
} else {
cols[i].sortable= true;
}
}
}
Thanks to drew630, you gave me a helpful hint, so I could solve my problem on my own.
If you do not want anything to happen when the grid is empty, you could put this in the store of the grid:
listeners: {
beforeload: function() {
return false when my conditions is met.;
}
}
This way your store will not load and nothing will happen. This is also handy when you have a pager component on the grid and where your server expects e.g. extraParams that are not yet set. If you expect extraParams, and when not yet set, the user clicks the refresh on the pager, you end up with exceptions. But with this check, you can prevent a call to the back-end if conditions are not met.
I sometimes set my api.read URL to undefined, (in cases where the store needs extraParams that are not yet set) and only when those params are available, I also set the URL (with a call in the store itself where the url is already set e.g. activateRead(). In the beforeload, I then test if the api.read is undefined or not.
Hope it helps.
Regards
Lawrende