How to get Kendo UI grid React wrapper to refresh - reactjs

I'm using the code below
Broke
const dataSourceSchema = {
model: {
fields: {
name: { type: 'string' },
description: { type: 'string' }
}
}
};
const gridOptions = {
...
};
class ItemsContainer extends React.Component {
componentDidMount() {
this.props.getItems();
}
render() {
const { items } = this.props;
const dataSource = {
schema: dataSourceSchema,
data: items
}
return (
<Grid {...gridOptions} dataSource={dataSource} />
);
}
}
And I get the following error
Error
But if I used this code that hard codes the dataSource.data then it works.
Works
const gridOptions = {
dataSource: {
data: [{name: 'foo', description: 'bar'}],
schema: {
model: {
fields: {
name: { type: "string" },
description: { type: "string" }
}
}
},
pageSize: 20
},
...
columns: [
"name",
"description"
]
};
class ItemsContainer extends React.Component {
componentDidMount() {
this.props.getItems();
}
render() {
const { items } = this.props;
return (
<Grid {...gridOptions}/>
);
}
}
What am I doing wrong. I was spreading out the dataSource property because it looks like the kendo wrapper is checking it's reference (as it should).

Related

Split Tables based on Effective Date (typescript)

We are adding a new feature where we can create multiple product lists. The differentiator will be the effective date of the list. So the list will have the same products, same costs and different prices/effective dates. I need to create two or more separate data tables based on the effective dates but so far I havent been able to figure out how to split them up. Here is what the table looks like now:
Here is my code:
#inject('stores')
#observer
class AdminOperatorDetails extends React.Component {
public props: any;
public operator: IOperator = new IOperator();
public effectiveDate: IOperatorRegionPrice = new IOperatorRegionPrice();
public operatorDisposer: any;
public operatorPriceDisposer: any;
public operatorExpenseDisposer: any;
public adminStore: AdminStore;
public MessageStore: MessageStore;
private UserStore: UserStore;
private TenantStore: TenantStore;
private operatorPricesHeader = [
"Product Name",
"Primary Category",
"Taxable",
"Size",
"Unit",
"Specific Gravity",
"Weight",
"Cost",
"Price",
"Effecitve Date"
];
private operatorPriceHeaderButtons: any;
public state = {
downloadSelected: 'products',
editingGroupEmail: false,
effectiveDate: this.effectiveDate,
groupEmail: new GroupEmail(),
groupEmailModal: false,
isDirty: false,
modal: false,
operator: this.operator,
operatorExpenseData: { headers: this.operatorExpenseHeader, rows: []} as IList,
operatorExpensePrices: [] as IOperatorRegionExpensePrice[],
operatorId: '',
operatorPrices: [] as IOperatorRegionPrice[],
operatorRegionData: { headers: this.operatorPricesHeader, rows: []} as IList,
redirect: false,
region: new IRegion(),
regionId: '',
regions: [] as IRegion[],
rowIndex: 0,
selectedEbp: [] as boolean[],
selectedProducts: [] as boolean[],
selectedRegions: [] as boolean[],
showDownloadModal: false,
showExpenses: false,
showPriceListModal: false,
showProducts: false,
showRegionModal: false,
};
constructor(props: any) {
super(props);
this.adminStore = this.props.stores.AdminStore;
this.MessageStore = this.props.stores.MessageStore;
this.UserStore = this.props.stores.UserStore;
this.TenantStore = this.props.stores.TenantStore;
this.initializeHeaders();
}
public componentDidMount() {
this.createDisposers();
this.operatorExportHeaderButtons = [
{
content: this.renderExportHeader,
type: 'render'
}
];
}
public componentWillUnmount() {
this.clearDisposers();
}
public createDisposers() {
this.operatorDisposer = intercept(this.adminStore, 'operator', (change: any) => {
const selectedRegions = this.setSelectedRegions(change.newValue);
this.setState({
operator: change.newValue,
selectedRegions
});
return change;
});
this.operatorPriceDisposer = intercept(this.adminStore, 'operatorProductPrices', (change: any) => {
this.setState({
operatorPrices: change.newValue
}, () => {
this.formatOperatorPriceData();
});
return change;
});
public clearDisposers() {
this.operatorDisposer();
this.operatorPriceDisposer();
}
public handleChange = (event: any) => {
const operator = this.state.operator;
operator[event.target.name] = event.target.value;
this.setState({
isDirty: true,
operator
});
}
private toggleList = (toggleName:string) => () => {
this.setState({
[toggleName]: !this.state[toggleName]
});
}
private formatOperatorPriceData = () => {
const operatorPrice = this.state.operatorPrices;
const rows:any = [];
operatorPrice.forEach((regionPrice, index) => {
const tempRow = [
{
content: regionPrice.name
},
{
content: regionPrice.category,
},
{
content: this.renderTaxableCheckbox('operatorPrices', regionPrice, index),
sortItem: regionPrice.isTaxable,
type: 'render',
},
{
content: regionPrice.size
},
{
content: regionPrice.unit
},
{
content: regionPrice.specificGravity,
},
{
content: regionPrice.weight,
},
{
content: this.renderCostInput(regionPrice, index),
sortItem: regionPrice.cost,
type: 'render',
},
{
content: this.renderPriceInput(regionPrice, index),
sortItem: regionPrice.price,
type: 'render'
},
{
content: regionPrice.effectiveDate
}
];
rows.push(tempRow);
});
this.setState({operatorRegionData: { headers: this.operatorPricesHeader, rows}});
}
{
this.state.operatorPrices.length > 0 &&
<React.Fragment>
<Row>
<Col>
{/* {
this.state.operatorPrices && this.state.operatorPrices.map((value, index) =>
<React.Fragment key={value.id}>
{
this.renderPriceLists(index)
}
</React.Fragment>
)
} */}
{
<h4 onClick={this.toggleList('showProducts')}><OpenArrow color={this.TenantStore.iconColor} open={this.state.showProducts} />Operator Product Lists</h4>
},
</Col>
</Row>
{
this.state.showProducts &&
<Row>
<Col>
<DataTable
list={this.state.operatorRegionData}
headerButtons={this.operatorPriceHeaderButtons}
maxHeight='50vh'
/>
</Col>
</Row>
}
</React.Fragment>
}

Row level operations on react-table: React Js

I am trying to implement a feature where in on click of each row, I need to get the info of the row that is been clicked and corresponding row color should be changed to something else. And when I select multiple rows using Ctrl+mouse-click the corresponding rows color should also get changed, and need to get the info of corresponding rows in the form of array. I need to have a common getTrProps function that should implement both of this . Can someone help me out with this
Codesandbox: https://codesandbox.io/s/react-table-row-table-0bbyi
App
import * as React from "react";
import { render } from "react-dom";
import DataGrid from "./DataGrid";
import { Column } from "react-table";
interface IProps {}
interface IState {
data: IUser[];
columns: Column<IUser>[];
}
export interface IUser {
firstName: string;
status: "Submitted" | "Pending" | "Approved";
age: string;
}
export interface IColum {
Header: string;
accessor: string;
}
class App extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
data: [],
columns: []
};
}
componentDidMount() {
this.getData();
this.getColumns();
}
getData = () => {
const data: IUser[] = [
{ firstName: "Jack", status: "Submitted", age: "14" },
{ firstName: "Simon", status: "Pending", age: "15" },
{ firstName: "Pete", status: "Approved", age: "17" }
];
this.setState({ data });
};
getColumns = () => {
const columns: IColum[] = [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Status",
accessor: "status"
},
{
Header: "Age",
accessor: "age"
}
];
this.setState({ columns });
};
onClickRow = (rowInfo: IUser) => {
console.log("You clicked: " + JSON.stringify(rowInfo));
};
render() {
return (
<>
<DataGrid
data={this.state.data}
columns={this.state.columns}
rowClicked={this.onClickRow}
/>
<DataGrid data={this.state.data} columns={this.state.columns} />
</>
);
}
}
DataGrid
import * as React from "react";
import ReactTable, {
RowInfo,
Column,
ComponentPropsGetterR
} from "react-table";
import "react-table/react-table.css";
import { IUser, IColum } from ".";
interface IProps {
data: IUser[];
columns: Column<IUser>[];
// The ? makes it optional
rowClicked?: (user: IUser) => void;
}
export default class DataGrid extends React.Component<IProps> {
rowClick: ComponentPropsGetterR = (state: any, rowInfo: RowInfo) => {
const rowClicked = this.props.rowClicked;
return rowClicked
? {
onClick: () => rowClicked(rowInfo.original as IUser)
}
: {};
};
render() {
return (
<ReactTable
data={this.props.data}
columns={this.props.columns}
getTrProps={this.rowClick}
/>
);
}
}
Here is Your Final Answer :
https://codesandbox.io/s/react-table-row-table-3xwxi
you can now hold Ctrl Key and Select as many row as you want and you can toggle between.
and if you don't hold the key you can select one
you can see each time you choose a row color of the row Changes.
and you have all the data in this.state.allData.
and all of this in typescript as you want from your sandbox.

Office UI Fabric React people picker not populating suggested drop down

When I'm using the office ui fabric react component for people picker, it's not populating the suggested people in the dropdown.
Two errors that I'm getting are
Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
and
Exception in Layer.componentDidUpdate(): Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
I've only been able to find this issue on github https://github.com/OfficeDev/office-ui-fabric-react/issues/1952, but there isn't much to go on. I am using office-ui-fabric-react version 4.5.1
The query is working from what I can see because I can console.log the results and it has people in there.
Here's what it looks like right now.
import * as React from 'react';
import { css,} from 'office-ui-fabric-react';
import { IReactRequestProps } from './IReactRequestProps';
import {
CompactPeoplePicker,
IBasePickerSuggestionsProps,
ListPeoplePicker,
NormalPeoplePicker
} from 'office-ui-fabric-react/lib/Pickers';
import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona';
const suggestionProps: IBasePickerSuggestionsProps = {
suggestionsHeaderText: 'Suggested People',
noResultsFoundText: 'No results found',
loadingText: 'Loading'
};
import {
BaseComponent,
assign,
autobind
} from 'office-ui-fabric-react/lib//Utilities';
import { people } from './PeoplePickerExampleData';
import { Label } from 'office-ui-fabric-react/lib/Label';
import { IPeopleDataResult } from './IPeopleDataResult';
import { IPersonaWithMenu } from 'office-ui-fabric-react/lib/components/pickers/PeoplePicker/PeoplePickerItems/PeoplePickerItem.Props';
import { IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu';
import { SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
export interface IOfficeUiFabricPeoplePickerState {
currentPicker?: number | string;
delayResults?: boolean;
}
export interface IPeopleSearchProps {
JobTitle: string;
PictureURL: string;
PreferredName: string;
}
export default class ReactRequest extends React.Component<IReactRequestProps, IOfficeUiFabricPeoplePickerState> {
private _peopleList;
private contextualMenuItems: IContextualMenuItem[] = [
{
key: 'newItem',
icon: 'circlePlus',
name: 'New'
},
{
key: 'upload',
icon: 'upload',
name: 'Upload'
},
{
key: 'divider_1',
name: '-',
},
{
key: 'rename',
name: 'Rename'
},
{
key: 'properties',
name: 'Properties'
},
{
key: 'disabled',
name: 'Disabled item',
disabled: true
}
];
constructor() {
super();
this._peopleList = [];
people.forEach((persona: IPersonaProps) => {
let target: IPersonaWithMenu = {};
assign(target, persona, { menuItems: this.contextualMenuItems });
this._peopleList.push(target);
});
this.state = {
currentPicker: 1,
delayResults: false
};
}
public render(): React.ReactElement<IReactRequestProps> {
if (this.props.typePicker == "Normal") {
return (
<NormalPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
} else {
return (
<CompactPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
}
}
#autobind
private _onFilterChanged(filterText: string, currentPersonas: IPersonaProps[], limitResults?: number) {
if (filterText) {
if (filterText.length > 2) {
return this.searchPeople(filterText, this._peopleList);
}
} else {
return [];
}
}
private searchPeople(terms: string, results: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> {
//return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
return new Promise<IPersonaProps[]>((resolve, reject) =>
this.props.spHttpClient.get(`${this.props.siteUrl}/_api/search/query?querytext='*${terms}*'&rowlimit=10&sourceid='b09a7990-05ea-4af9-81ef-edfab16c4e31'`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ PrimaryQueryResult: IPeopleDataResult }> => {
return response.json();
})
.then((response: { PrimaryQueryResult: IPeopleDataResult }): void => {
let relevantResults: any = response.PrimaryQueryResult.RelevantResults;
let resultCount: number = relevantResults.TotalRows;
let people = [];
let persona: IPersonaProps = {};
console.log(relevantResults);
console.log('really relevant');
if (resultCount > 0) {
relevantResults.Table.Rows.forEach(function (row) {
row.Cells.forEach(function (cell) {
//person[cell.Key] = cell.Value;
if (cell.Key === 'JobTitle')
persona.secondaryText = cell.Value;
if (cell.Key === 'PictureURL')
persona.imageUrl = cell.Value;
if (cell.Key === 'PreferredName')
persona.primaryText = cell.Value;
});
people.push(persona);
});
}
resolve(people);
console.log(people);
console.log("PEOPLE");
}, (error: any): void => {
reject(this._peopleList = []);
}));
}
private _filterPersonasByText(filterText: string): IPersonaProps[] {
return this._peopleList.filter(item => this._doesTextStartWith(item.primaryText, filterText));
}
private _removeDuplicates(personas: IPersonaProps[], possibleDupes: IPersonaProps[]) {
return personas.filter(persona => !this._listContainsPersona(persona, possibleDupes));
}
private _listContainsPersona(persona: IPersonaProps, personas: IPersonaProps[]) {
if (!personas || !personas.length || personas.length === 0) {
return false;
}
return personas.filter(item => item.primaryText === persona.primaryText).length > 0;
}
private _filterPromise(personasToReturn: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> {
if (this.state.delayResults) {
return this._convertResultsToPromise(personasToReturn);
} else {
return personasToReturn;
}
}
private _convertResultsToPromise(results: IPersonaProps[]): Promise<IPersonaProps[]> {
return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
}
private _doesTextStartWith(text: string, filterText: string): boolean {
return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0;
}
}
i got that error when using later versions of fabric. works fine with older versions,

Error: UserCreatePayload.viewer field type must be Output Type but got: undefined

The code below works when the entire schema is in a single file, but I'm getting the above error when I try to split it into individual files.
I'm importing all the types and functions.
I have to add more details, but I'm not sure what to say. I think it's a sequencing problem since it works in a single file, but not split up.
Thanks a lot.
const UserCreateMutation = mutationWithClientMutationId({
name: 'UserCreate',
inputFields: {
email: {type: new GraphQLNonNull(GraphQLString)},
password: {type: new GraphQLNonNull(GraphQLString)}
},
outputFields: {
viewer: {
type: viewerType,
resolve() {
return viewerGet();
}
},
field: {
type: userType,
resolve(node) {
return node;
}
}
},
async mutateAndGetPayload({email, password}, {db, req}) {
export const viewerType = new GraphQLObjectType({
name: 'Viewer',
fields() {
return {
id: globalIdField('Viewer', ({_id: viewerLocalId}) => {
return viewerLocalId;
}),
_id: {type: GraphQLID},
user: {
type: userType,
resolve(parent, args, {req: {user}}) {
return user || {};
}
},
profile: {
type: profileConnectionType,
args: {
id: {type: GraphQLID},
searchTerm: {type: GraphQLString},
...connectionArgs
},
resolve(parent, {id: profileGlobalId, searchTerm, ...connectionArgs}, {db}) {
const query = (() => {
const q = {};
if (profileGlobalId) {
const {id: profileLocalId} = fromGlobalId(profileGlobalId);
Object.assign(
q,
{_id: new ObjectID(profileLocalId)}
);
}
if (searchTerm) {
Object.assign(
q,
{
$text: {
$search: `\"${searchTerm}\"`
}
}
);
}
return q;
})();
const sort = {_id: -1};
const limit = 0;
return connectionFromPromisedArray(
promisedArrayGet(
query,
sort,
limit,
profileCollectionName,
db
),
connectionArgs
);
}
}
};
},
interfaces: [nodeInterface]
});
class Viewer extends Object {}
export const viewerGet = () => {
return Object.assign(
new Viewer(),
{
_id: 'Viewer'
}
);
};
import { viewerType, userType, viewerGet }
Not sure if this is the problem but sometimes module-loading order is an issue. If it is the problem, you can solve it by making outputFields a thunk, i.e. a function that returns the object instead of a plain object.
outputFields: () => ({
viewer: {
type: viewerType,
resolve() {
return viewerGet();
}
},
field: {
type: userType,
resolve(node) {
return node;
}
}
}),

No Variables in Relay generated mutation query

I'm pretty new to Relay so perhaps it's a very stupid error.
I'm trying to make a simple mutation that add a defect to a photo.
Here is my Relay.Mutation object :
AddDefectMutation.js
export default class AddDefectMutation extends Relay.Mutation {
getMutation() {
return Relay.QL`mutation { addDefect }`;
}
getVariables() {
return{
photoId: this.props.photoId,
title: this.props.title
}
}
getFatQuery() {
return Relay.QL`
fragment on AddDefectMutationPayload {
updatedPhoto {
issues
}
}
`
}
getConfigs() {
return [{
type : 'FIELDS_CHANGE',
fieldIDs : {
updatedPhoto : this.props.photoId
}
}]
}
}
And here is the part of the GraphQl schema
const AddDefectMutation = mutationWithClientMutationId({
name: 'AddDefectMutation',
description: 'Add a new defect and return all the defects.',
inputFields: {
photoId: {
description: 'Photo of this defect',
type: new GraphQLNonNull(GraphQLString)
},
title: {
description: 'A short description of the defect',
type: GraphQLString
}
},
outputFields: {
updatedPhoto: {
type: PhotoGraphQLType,
resolve: ({localIdIssue}) => driver.getIssuePhoto(localIdIssue)
}
},
mutateAndGetPayload: ({photoId, title}) =>
driver.addIssue(photoId, title).then(localIdIssue => ({localIdIssue}))
})
const MutationGraphQLType = new GraphQLObjectType({
name: 'Mutation',
fields: () => ({
addDefect: AddDefectMutation
})
})
My problem is that when I make this call :
Relay.Store.commitUpdate(new AddDefectMutation(
{photoId: this.props.pictureId, title: this.props.title}), {
onSuccess: ()=> console.log("Mutation Success !"),
onFailure: transaction => console.error(transaction.getError() || new Error('Mutation failed.'))
})
Relay generate the good mutation query without problem but it doesn't place the variables given in the constructor.
EDIT : Here the fragment of mutation generated by relay
mutation AddDefect($input_0:AddDefectMutationInput!) {
addDefect(input:$input_0) {
...F4,
clientMutationId
}
}
And the problem is that $input_0 is an empty object
The variable title is not passed properly to the mutation constructor. In your Relay.Store.commitUpdate function call, change {photoId: this.props.pictureId, this.props.title}) to
{photoId: this.props.pictureId, title: this.props.title})

Resources