ReactJS Redux Live editing - javascript

I'm trying to build a similar code like the Widget example from React Redux Universal Hot Example. The only exception is that the data is fetched from PostgreSQL database.
The code lists the groups as it should, but when I click on Edit I get the following errors.
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `AdminGroupList`
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of `AdminGroupList`
Here is my AdminGroupList.js
import React, { Component } from 'react';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
import { asyncConnect } from 'redux-async-connect';
import { routeActions } from 'react-router-redux';
// import { Table } from 'react-bootstrap/lib';
import * as groupActions from 'redux/modules/groups';
import {isLoaded, load as loadGroups} from 'redux/modules/groups';
import {initializeWithKey} from 'redux-form';
import { GroupForm } from 'components/Admin/GroupForm';
#asyncConnect([{
deferred: true,
promise: ({store: {dispatch, getState}}) => {
if (!isLoaded(getState())) {
return dispatch(loadGroups());
}
}
}])
#connect(
state => ({
groups: state.groups.data,
editing: state.groups.editing,
error: state.groups.error,
loading: state.groups.loading
}),
{ ...groupActions, initializeWithKey, pushState: routeActions.push })
export default class AdminGroupList extends Component {
static propTypes = {
groups: React.PropTypes.object,
pushState: React.PropTypes.func.isRequired,
error: React.PropTypes.string,
loading: React.PropTypes.bool,
initializeWithKey: React.PropTypes.func.isRequired,
editing: React.PropTypes.object.isRequired,
load: React.PropTypes.func.isRequired,
editStart: React.PropTypes.func.isRequired
}
render() {
const groups = Object.values(this.props.groups);
const handleEdit = (group) => {
const {editStart} = this.props;
return () => editStart(String(group.id));
};
const { error, editing, loading, load} = this.props;
let refreshClassName = 'fa fa-refresh';
if (loading) {
refreshClassName += ' fa-spin';
}
return (
<div className="container">
<h1>
Tuoteryhmät ({groups.length})
<button className="btn btn-success" onClick={load}>
{' '} Reload Groups
</button>
</h1>
<Helmet title="Groups"/>
{error &&
<div className="alert alert-danger" role="alert">
<span className="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
{' '}
{error}
</div>}
{groups && groups.length &&
<table className="table table-striped">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
{
groups.map((group) => editing[group.id] ?
<GroupForm formKey={String(group.id)} key={String(group.id)} initialValues={group}/> :
<tr key={group.id}>
<td>{group.id}</td>
<td>{group.name}</td>
<td>
<button className="btn btn-primary" onClick={handleEdit(group)}>
<i className="fa fa-pencil"/> Edit
</button>
</td>
</tr>)
}
</tbody>
</table>}
</div>
);
}
}
And here is GroupForm.js
import React, {Component, PropTypes} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {reduxForm} from 'redux-form';
import groupValidation from 'utils/GroupValidation';
import * as groupActions from 'redux/modules/groups';
#connect(
state => ({
saveError: state.groups.saveError
}),
dispatch => bindActionCreators(groupActions, dispatch)
)
#reduxForm({
form: 'group',
fields: ['id', 'name'],
validate: groupValidation
})
export default class GroupForm extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
editStop: PropTypes.func.isRequired,
handleSubmit: PropTypes.func.isRequired,
invalid: PropTypes.bool.isRequired,
pristine: PropTypes.bool.isRequired,
save: PropTypes.func.isRequired,
submitting: PropTypes.bool.isRequired,
saveError: PropTypes.object,
formKey: PropTypes.string.isRequired,
values: PropTypes.object.isRequired
};
render() {
const { editStop, fields: {id, name}, formKey, handleSubmit, invalid,
pristine, save, submitting, saveError: { [formKey]: saveError }, values } = this.props;
return (
<tr>
<td>{id.value}</td>
<td>
<input type="text" className="form-control" {...name}/>
{name.error && name.touched && <div className="text-danger">{name.error}</div>}
</td>
<td>
<button className="btn btn-default"
onClick={() => editStop(formKey)}
disabled={submitting}>
<i className="fa fa-ban"/> Cancel
</button>
<button className="btn btn-success"
onClick={handleSubmit(() => save(values)
.then(result => {
if (result && typeof result.error === 'object') {
return Promise.reject(result.error);
}
})
)}
disabled={pristine || invalid || submitting}>
<i className={'fa ' + (submitting ? 'fa-cog fa-spin' : 'fa-cloud')}/> Tallenna
</button>
{saveError && <div className="text-danger">{saveError}</div>}
</td>
</tr>
);
}
}

This error message means you have an issue with your imports.
If you export export GroupForm by default with default class GroupForm, you should import it without the curly brackets in AdminGroupList.js:
Replace this line import { GroupForm } from 'components/Admin/GroupForm' by import GroupForm from 'components/Admin/GroupForm'

Related

HTML button element in React component showing Typescript error "Property 'disabled' does not exist on type"

I am trying to disable a submit button in React when a prop "processing" is true, but the TypeScript compiler is throwing an error.
The component:
import React, { FunctionComponent } from 'react';
interface SubmitButtonProps {
processing: boolean;
}
const SubmitButton: FunctionComponent<SubmitButtonProps> = (props) => {
const { processing } = props;
return (
<button
className="btn btn-primary btn-lg"
type="submit"
aria-disabled={processing}
disabled={processing}
>
{processing ? 'Processing' : 'Open'}
</button>
);
};
export default SubmitButton;
The error:
Type '{ children: string; className: string; type: string; "aria-disabled": boolean; disabled: boolean; }' is not assignable to type 'DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>'
Property 'disabled' does not exist on type 'DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>'. TS2322
Edit:
This is the component for the form element that the submit button is being used in:
import React, { Component, FormEvent } from 'react';
import CSVLoader from '../../modules/csv-loader';
import { IFile } from '../../types';
import FileInput from './FileInput';
import SubmitButton from './SubmitButton';
interface IState {
processing: boolean;
fileTextContent: string;
fileName: string;
}
interface IProps {
onChange: (data: IFile) => void;
}
class FileSelector extends Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = { processing: false, fileTextContent: '', fileName: '' };
}
async handleAttachFile(e: FormEvent): Promise<void> {
const { files } = e.target as HTMLInputElement;
const file = files?.item(0);
const fileText = await file?.text();
const fileName = file?.name;
this.setState({
fileTextContent: fileText ?? '',
fileName: fileName ?? 'untitled',
});
}
async process(e: FormEvent): Promise<void> {
e.preventDefault();
this.setState({ processing: true });
const data = await CSVLoader(
this.state.fileName,
this.state.fileTextContent
);
this.props.onChange(data);
}
render() {
const { processing } = this.state;
return (
<div>
<form onSubmit={(e) => this.process(e)}>
<FileInput onAttachFile={(e) => this.handleAttachFile(e)} />
<div className="mb-3 text-end">
<SubmitButton processing={processing} />
</div>
</form>
</div>
);
}
}
export default FileSelector;
The button was originally inside this component and was throwing the same error before I moved it to its own component to try and isolate the problem.
Edit 2:
It seems to be a configuration issue somehwere. Mousing over a in VSCode shows its type as
"(property) JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.AnchorHTMLAttributes, HTMLAnchorElement>"

React - How Do You Call Methods From One Component To The Other Without Adding Extra Code In The Child Component

I'm building a toast component in React and I'm want to create it so the user can simply import the component and then not have to add any extra code other than calling methods.
For e.g.
Import Toast from './components/Toast;
And then call methods to show different toasts depending on what they want for e.g
Toast.success();
And this will return a toast with success styling and content
Or Toast.error();
And this will return a toast with error styling and content
I don't want them to do anything other than call the method after importing.
I'm struggling to think of the way you would do this.
Here is my current code:
If you look at the 'CSToastAPI' section that's where I'm struggling how I would be able to do that and call in another component. Thanks.
import React, { Fragment } from 'react';
import CSIcon from './CSIcon';
import classNames from 'classnames';
import ReactDOMServer from 'react-dom/server';
export interface CSToastProps {
className?: string;
closeButton?: boolean;
detail?: string;
iconName?: string;
iconVisibility?: boolean;
minWidth?: string;
onClose?: undefined;
text?: string;
textAlign?: string;
position?: string;
}
export interface CSToastState {
variant?: string;
}
const CSToastAPI = {
success: () => {
this.setState({
variant: 'success'
});
}
}
class CSToast extends React.Component<CSToastProps, CSToastState> {
public static defaultProps = {
iconVisibility: true
};
constructor(props: any) {
super(props);
this.state = {
variant: ''
}
}
render() {
const toastClasses = classNames(
'cs-toast-wrapper',
'top-right',
{
[`${this.props.position}`]: this.props.position
}
);
const CSToastHTML = (
<>
<div className={toastClasses}>
<div
style={{minWidth: this.props.minWidth}} className={`cs-toast ${this.state.variant ? `cs-toast-${this.state.variant}` : ''} ${this.props.textAlign ? this.props.textAlign : ''} ${this.props.className ? this.props.className : ''}`} role="alert"
>
{this.props.iconVisibility ? (this.props.iconName ? (
<CSIcon name={this.props.iconName}/>
) : (
<CSIcon name={this.state.variant}/>
)) : null}
<h4 className="cs-toast-text">
{this.props.text}
{this.props.detail ? (
<div className="cs-toast-detail">{this.props.detail}</div>
) : null}
{this.props.children}
</h4>
{this.props.closeButton ? (
<button className="cs-toast-close" onClick={this.props.onClose} aria-label="close">
<CSIcon name="close"/>
</button>
) : null}
</div>
</div>
</>
);
const CSToastAPIView = ReactDOMServer.renderToStaticMarkup(CSToastHTML);
document.body.insertAdjacentHTML("afterbegin", CSToastAPIView);
CSToastAPI.success();
return (
<div>
{CSToastHTML}
</div>
);
}
}
export default CSToast;

Transform a SPFX TS without JS framework to a React TS

I used yo #microsoft/sharepoint to created a webpart to display a list of items.
The solution was created without Javascript framework.
import { Version } from '#microsoft/sp-core-library';
import { BaseClientSideWebPart } from '#microsoft/sp-webpart-base';
import {
IPropertyPaneConfiguration,
PropertyPaneTextField
} from '#microsoft/sp-property-pane';
import { escape } from '#microsoft/sp-lodash-subset';
import styles from './GetSpListItemsWebPart.module.scss';
import * as strings from 'GetSpListItemsWebPartStrings';
import {
SPHttpClient,
SPHttpClientResponse
} from '#microsoft/sp-http';
import {
Environment,
EnvironmentType
} from '#microsoft/sp-core-library';
export interface IGetSpListItemsWebPartProps {
description: string;
}
export interface ISPLists {
value: ISPList[];
}
export interface ISPList {
ID:string;
Title: string;
Summary : string;
NewsCategory: string;
Created:string;
AttachmentFiles:{
Name:string;
Url:string;
ServerRelativeUrl: string;
}
}
export default class GetSpListItemsWebPart extends BaseClientSideWebPart<IGetSpListItemsWebPartProps> {
private _getListData(): Promise<ISPLists> {
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/lists/GetByTitle('News')/items?$select=*&$expand=AttachmentFiles",SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}
private _renderListAsync(): void {
if (Environment.type == EnvironmentType.SharePoint ||
Environment.type == EnvironmentType.ClassicSharePoint) {
this._getListData()
.then((response) => {
this._renderList(response.value);
});
}
}
public titleurl(query:string){
var path="/Lists/News/DispForm.aspx?ID=";
var currdir=this.context.pageContext.web.absoluteUrl;
var result=currdir+path+query;
return result;
}
private _renderList(items: ISPList[]): void {
let html: string = '<table border=1 width=100% style="border-collapse: collapse;">';
html += '<th>ID</th><th>Title</th> <th>Summary</th><th>Created</th><th>Attachments</th>';
items.forEach((item: ISPList) => {
html += `
<tr>
<td>${item.ID}</td>
<td>${item.Title}</td>
<td>${item.Title}</td>
<td>${item.Created}</td>
<td>
<img src="${item.AttachmentFiles[0].ServerRelativeUrl}" width="300px" height="300px" />
</td>
</tr>
`;
});
html += '</table>';
const listContainer: Element = this.domElement.querySelector('#spListContainer');
listContainer.innerHTML = html;
}
public render(): void {
this.domElement.innerHTML = `
<div class="${ styles.getSpListItems }">
<div class="${ styles.container }">
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${ styles.row }">
<div class="ms-Grid-col ms-u-lg10 ms-u-xl8 ms-u-xlPush2 ms-u-lgPush1">
<span class="ms-font-xl ms-fontColor-white">Welcome to SharePoint Modern Developmennt</span>
<p class="ms-font-l ms-fontColor-white">Loading from ${this.context.pageContext.web.title}</p>
<p class="ms-font-l ms-fontColor-white">Retrive Data from SharePoint List</p>
</div>
</div>
<div class="ms-Grid-row ms-bgColor-themeDark ms-fontColor-white ${styles.row}">
<div>NEWS List Items</div>
<br>
<div id="spListContainer" />
</div>
</div>`;
this._renderListAsync();
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
})
]
}
]
}
]
};
}
}
This part was rendered successfully.
I then created a solution yo #microsoft/sharepoint
using the React option.
I am stuck on how to render the HTML documents.
Previous it as used to this.domElement, but it says It is not in the class.
I attempted to creating another class to render seems unsuccessful.
How to print the results?
import * as React from 'react';
import styles from './B.module.scss';
import { IBProps } from './IBProps';
import { escape } from '#microsoft/sp-lodash-subset';
import {
SPHttpClient,
SPHttpClientResponse
} from '#microsoft/sp-http';
import {
Environment,
EnvironmentType
} from '#microsoft/sp-core-library';
import * as ReactDOM from 'react-dom';
export interface ISPLists {
value: ISPList[];
}
export interface ISPList {
ID:string;
Title: string;
Summary : string;
NewsCategory: string;
Created:string;
AttachmentFiles:{
Name:string;
Url:string;
ServerRelativeUrl: string;
}
}
export default class B extends React.Component<IBProps, {}> {
public render(): React.ReactElement<IBProps> {
return (
<div className={ styles.b }>
<div id="spListContainer"></div>
<div className={ styles.container }>
<div className={ styles.row }>
<div className={ styles.column }>
<span className={ styles.title }>Welcome to SharePoint!</span>
<p className={ styles.subTitle }>Customize SharePoint experiences using Web Parts.</p>
<p className={ styles.description }>{escape(this.props.description)}</p>
</div>
</div>
</div>
</div>
);
}
}
export class shownews extends B{
constructor(prop){
super(prop);
public _getListData(): Promise<ISPLists> {
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/lists/GetByTitle('News')/items?$select=*&$expand=AttachmentFiles",SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}
public _renderListAsync(): void {
if (Environment.type == EnvironmentType.SharePoint ||
Environment.type == EnvironmentType.ClassicSharePoint) {
this._getListData()
.then((response) => {
this._renderList(response.value);
});
}
}
public titleurl(query:string){
var path="/Lists/News/DispForm.aspx?ID=";
var currdir=this.context.pageContext.web.absoluteUrl;
var result=currdir+path+query;
return result;
}
private _renderList(items: ISPList[]): void {
let html: string = '<table border=1 width=100% style="border-collapse: collapse;">';
html += '<th>ID</th><th>Title</th> <th>Summary</th><th>Created</th><th>Attachments</th>';
items.forEach((item: ISPList) => {
html += `
<tr>
<td>${item.ID}</td>
<td>${item.Title}</td>
<td>${item.Title}</td>
<td>${item.Created}</td>
<td>
<img src="${item.AttachmentFiles[0].ServerRelativeUrl}" width="300px" height="300px" />
</td>
</tr>
`;
});
html += '</table>';
const listContainer = React.createElement('h1',{},html);
ReactDOM.render(listContainer, document.getElementById('spListContainer'));
this._renderListAsync();
}
}
}
I do apologize If there are many tutorials on SPFX, REACT JS on CRUD operations.
However, I clone it, attempted to npm install or npm i -g, none of the repositories work for me.
2020-01-28
Rewrote the code to get json directly. The html tags won't render
import * as React from 'react';
import styles from './A.module.scss';
import { IAProps } from './IAProps';
import { escape } from '#microsoft/sp-lodash-subset';
import { PageContext } from "#microsoft/sp-page-context";
import { HttpClient, IHttpClientOptions, HttpClientResponse, SPHttpClient, ISPHttpClientOptions, SPHttpClientResponse } from '#microsoft/sp-http';
import {
Environment,
EnvironmentType
} from '#microsoft/sp-core-library';
export interface ISPLists {
value: ISPList[];
};
export interface ISPList {
ID:string;
Title: string;
Summary : string;
NewsCategory: string;
Created:string;
AttachmentFiles:{
Name:string;
Url:string;
ServerRelativeUrl: string;
};
}
export default class A extends React.Component<IAProps, {}> {
public test:any=[];
public data:any=[];
public geturl(query:string){
var path="/Lists/News/DispForm.aspx?ID=";
var currdir=this.props.pagecontext.web.absoluteUrl;
var result=currdir+path+query;
return result;
}
private getListData(){
const opt: ISPHttpClientOptions = { headers: { 'Content-Type': 'application/json;odata=verbose' } };
return this.props.SPHttpClient.get(this.props.pagecontext.web.absoluteUrl + "/_api/lists/GetByTitle('News')/items?$select=*&$expand=AttachmentFiles",SPHttpClient.configurations.v1,opt)
.then((response: SPHttpClientResponse) => {
response.json().then((json: any) => {
for(let i=0;i<json.value.length;i++){
this.data.push(<div><tr>
<td>${json.ID}</td>
<td>${json.Title}</td>
<td></td>
<td>${json.Created}</td>
<td><img src="${json.AttachmentFiles.ServerRelativeUrl}" width="300px" height="300px" /></td>
</tr></div>);
}
});
});
}
/*
private renderList(item: ISPList[]): void {
item.forEach((item: ISPList) => {
this.data.push(`<tr>
<td>${item.ID}</td>
<td>${item.Title}</td>
<td></td>
<td>${item.Created}</td>
<td><img src="${item.AttachmentFiles.ServerRelativeUrl}" width="300px" height="300px" /></td>
</tr>`
);
})
console.log(this.data);
};
*/
/*
private push() {
this.test.push(1);
this.test.push(2);
this.test.push(3);
console.log(this.test);
}
*/
public render(): React.ReactElement<IAProps>{
this.getListData();
console.log(this.data);
return (
<div id="splist">
TEST
<table className={styles.container}>
<tr>
<th>ID</th><th>Title</th> <th>Summary</th><th>Created</th><th>Attachments</th>
</tr>
<tr>
<td></td>
<td>TITLE</td>
<td></td>
<td>Created</td>
<td>
</td>
</tr>
{this.data}
1234
</table>
</div>
);
}
}
2020-01-28 18:15
This Don't Work this.
If I .push (data);
The Table would have ); all over the place.
this.setState({ items:"<td>{item.ID}</td>
<td>{item.Title}</td>
<td>{item.Summary}</td>
<td>{item.Created}</td>
<td>{item.AttachmentFiles[0].ServerRelativeUrl}</td>" });
This do not work
this.Title.push(<span><td>{item.Title}</td></span>);
this.Url.push(<span><td>{item.AttachmentFiles[0].ServerRelativeUrl}</td></span>);
This Works
this.ID.push(item.ID); /* this.Title.push(<span><td>{item.Title}</td></span>); this.Url.push(<span><td>{item.AttachmentFiles[0].ServerRelativeUrl}</td></span>); */ this.forceUpdate();
If I use an array and use .push to send data including HTML tags
the follow screenshot shows the problem.
The Code
public renderList(item: ISPList[]): void {
item.forEach((item: ISPList) => {
this.data.push(<tr>);
this.data.push(<td>{item.ID}</td>);
this.data.push(<td>{item.Title}</td>);
this.data.push(<td>{item.AttachmentFiles[0].ServerRelativeUrl}</td>);
this.data.push(</tr>);
//some brackets...
2020-01-28 1956 Problem TR WITHIN TR
Problem: If I write the HTML tags and data in one line the tags will generate it self. But in the render method, I need to add a tag to wrap it will make my output incorrect format.
//some codes before to get the JSON data
this.data.push(<tr>
<td>{item.ID}</td>
<td>{item.Title}</td>
<td>{item.AttachmentFiles[0].ServerRelativeUrl}</td></tr>);
//some more codes
public render(): React.ReactElement<IAProps>{
return (
<div id="splist">
TEST
<table className={styles.container}>
<tr>
<th>ID</th>
<th>Title</th>
<th>Attachments</th>
</tr>
{this.data}
</table>
</div>
);
}
Firstly, you need to think about your solution in terms of components (having props or states) that you want to render. In context of your solution you can create a component lets say: 'GetandRenderListItems.tsx' and do all ' _getListData()' stuff. You can use 'componentDidMount()' life cycle hook to call _getListData() function everytime after the component is mounted. Then you need to write html template to render retrieved data (all what you have done in '_renderList()' method) have a look at below snippet to get an idea:
public render(): React.ReactElement<IyourcomponentsProps> {
return (
// your dynamic table html and you should not use inline style but define styles in
scss file and use them.
);
}
Then in your 'yourwebpart.ts' file you can render this component in render() method:
public render(): void {
const element: React.ReactElement<IyourwebpartProps > = React.createElement(
GetandRenderListItems,
{
description: this.properties.description,
// similarly assign values to other props
}
);
ReactDom.render(element, this.domElement);
}
Hopefully this will help.
Edit
you could use array.map() e.g. To render a table using your array you could write something like that.
public render () : React.ReactElement<IyourcomponentsProps> {
return(
<div className={styles.someStyle} >
<table className={styles.container}>
<tr>
<th>ID</th><th>Title</th> <th>Summary</th><th>Created</th
<th>Attachments</th>
</tr>
{ yourArray.map(function(item,key){
let url = this.titleurl(item.ID);
return (<tr className={styles.rowStyle} key={key}> //you can use key if you want to track index
<td></td> <td className={styles.someclass}><a href={url}>{item.Title}</a></td>
</tr> );
})}
</table>
</div>
);
}
I used .bind .map functions to make it happen.
For adding state to the project should be next upate.
I was struggling on handling the arrays and trouble printing
The entire component .tsx file
import * as React from 'react';
import styles from './A.module.scss';
import { IAProps } from './IAProps';
import { escape } from '#microsoft/sp-lodash-subset';
import { PageContext } from "#microsoft/sp-page-context";
import { HttpClient, IHttpClientOptions, HttpClientResponse, SPHttpClient, ISPHttpClientOptions, SPHttpClientResponse } from '#microsoft/sp-http';
import {
Environment,
EnvironmentType
} from '#microsoft/sp-core-library';
export interface ISPLists {
value: ISPList[];
};
export interface Istate {
ID:string;
Title: string;
isLoad?: boolean;
Url:string;
AttachmentFiles:{
Name:string;
Url:string;
ServerRelativeUrl: string;
};
}
export interface ISPList {
ID:string;
Title: string;
Summary : string;
NewsCategory: string;
Created:string;
AttachmentFiles:{
Name:string,
Url:string,
ServerRelativeUrl: string,
};
}
/*
MAIN STARTS HERE
2020-01-28
*/
export default class A extends React.Component<IAProps> {
constructor(props){
super(props);
this.loadNews();
this.getListData=this.getListData.bind(this);
this.geturl=this.geturl.bind(this);
this.loadNews=this.loadNews.bind(this);
}
//variables to render html tags
private ID:any = [];
private Title:any = [];
private Url:any = [];
private data:any =[];
private tro:any=[]; //<tr>
private trc:any=[]; //</tr>
private tdo:any=[]; //<td>
private tdc:any=[]; //</td>
private loadNews(){
this.getListData();
/*
this.getListData().then((response) => {
this.renderList(response.value);
});
*/ // when getlist and redner list are different functions
}
public geturl(query:string){
var path="/Lists/News/DispForm.aspx?ID=";
var currdir=this.props.pagecontext.web.absoluteUrl;
var result=currdir+path+query;
return result;
}
private tags(flag:boolean,first:boolean){
// if first data add <tr>
//if last data add </tr>
//
if (flag && first){
document.getElementById("tro").innerHTML = <tr>;
}else if (flag && !first){
document.getElementById("trc").innerHTML = </tr>;
}
}
private getListData() {
const opt: ISPHttpClientOptions = { headers: { 'Content-Type': 'application/json;odata=verbose' } };
this.props.SPHttpClient.get(this.props.pagecontext.web.absoluteUrl + "/_api/web/lists/getbytitle('News')/items?$select=*,AttachmentFiles&$expand=AttachmentFiles/Title&$orderby=ID desc", SPHttpClient.configurations.v1, opt).then((response: SPHttpClientResponse) => {
response.json().then((json: any) => {
for(let i=0;i<json.value.length;i++){
var url=this.geturl(json.value[i].ID);
if(i==0){ // add tags <tr> </tr>
let flag=true; let first=true;
this.tags(flag,first);
}else if(i==json.value.length){
let flag=false; let first=false;
this.tags(flag,first);
}
this.data.push({ID:<td>{json.value[i].ID}</td>,
Title:<td>{json.value[i].Title}</td>,
Url:<td><img src={json.value[i].AttachmentFiles[0].ServerRelativeUrl} width="300px" height="300px" /></td>
});
// debugger;
this.ID.push(json.value[i].ID);
// this.Title.push(json.value[i].Title);
//this.Url.push(json.value[i].AttachmentFiles[0].absoluteUrl);
this.forceUpdate();
}//close for
});// close response.json
});//close private getListData method
}
// json.value[i].Title}
//json.value[i].AttachmentFiles[0].absoluteUrl}
/*
<td>${json.value[i].Title}</td>
<td></td>
<td>${json.value[i].Created}</td>
<td><img src="${json.AttachmentFiles.ServerRelativeUrl}" width="300px" height="300px" /></td>
*/
public render(): React.ReactElement<IAProps>{
console.log(this.data);
return (
<div className={styles.a} >
<div className={styles.container} ></div>
<span className={ styles.title }>News</span>
<div className={styles.Table}>
<div className={styles.Heading}>
<table >
<tr>
<div className={styles.Cell}>Title</div>
<div className={styles.Cell}>Created</div>
<div className={styles.Cell}>IMGSRC</div>
</tr>
<div className={styles.Cell}>
<span id="tro"></span>
{this.data.map((data)=>
<div> {data.ID}</div>
)
}
</div>
<div className={styles.Cell}>
{this.data.map((data)=>
<div> {data.Title}</div>
)
}
</div>
<div className={styles.Cell}>
{this.data.map((data)=>
<div> {data.Url}</div>
)
}
<span id="trc"></span>
</div>
</table>
</div>
</div>
</div>
);
}
}
In render method .map function as follows
<div className={styles.Cell}>
{this.data.map((data)=>
<div> {data.Url}</div>
)
}
<span id="trc"></span>
</div>
To access data objects within array must declare .bind in the constructor after defining the class.
export default class A extends React.Component<IAProps> {
constructor(props){
super(props);
this.loadNews();
this.getListData=this.getListData.bind(this);
this.geturl=this.geturl.bind(this);
this.loadNews=this.loadNews.bind(this);
}
//variables to render html tags
private data:any =[];
Halfway through.
This is the prototype.
once I am able to extract the data , I can then style the CSS
Thank you for your help.

Proper way to build bootstrap modals and notifications in React JS?

I would like to have modals and notifications in my app and coming from using old jQuery Bootstrap, creating modals and notifications were really easy but now I am pretty confused on how to implement this in the virtual DOM using the react component system.
This is what I believe the standard react way to build modals in React within a component:
Index/Router Component >
Main Layout Component >
{...Page Components... }
{...Child Component}
{<Modal /> or <Notification />}
The issue with this is I dont want to constantly have to import and create a <Modal> or <Notification /> component within my sub components, instead maybe just call a utility function such as {app.notify({type: 'success', message: 'some message'})} or app.modal({...customconfig}) and have both defined within my Main layout component which get triggerd through any child components.
Any help on this would be great, thanks!
You do not need to keep your Modal component in a hierarchy. Your Modal component should be an independent component which would take appropriate props to decide what needs to be displayed. E.g.
<Modal message={"This is my modal"} showOkCancel={true} showYesNo={false} handleOkYes={()=>console.log("OK clicked")} handleCancelNo={()=>console.log("Cancel clicked"} />
In the above example, the Modal accepts a number of props which would help it decide the message to display, the buttons to display and the actions that need to take on said button click.
This kind of a component can reside outside your component hierarchy and can be imported into any component that needs to show a modal. The parent component would just need to pass the appropriate props to show the modal.
Hope this helps.
So here is the approach I took to resolve this.
First here is how you want to structure the modal and notification components:
{Index/Router Component}
{Main Layout Component <Modal /> or <Notification />}
{...Page Components... }
{...Child Component calls app.modal({...config}) or app.notify(...config)}
For notifications, I used a plugin called react-notification-system and for modal, I just wrote it myself.
Here is my code:
Layout.js
import React from "react";
import {Link} from 'react-router';
import NotificationSystem from 'react-notification-system';
import AppHeader from "#/ui/header/AppHeader";
import AppFooter from "#/ui/footer/AppFooter";
import Modal from "#/ui/modals/modal/Modal";
import "#/main.scss";
import './layout.scss';
export default class Layout extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
app.notify.clear = this.refs.notificationSystem.clearNotifications;
app.notify = this.refs.notificationSystem.addNotification;
app.modal = this.refs.modal.updateProps;
}
render() {
return (
<div class="app">
<div class="header">
<AppHeader page={this.props.location.pathname.replace('/', '')}/>
</div>
<div class="body">
{this.props.children}
</div>
<div class="footer">
<AppFooter />
</div>
<NotificationSystem ref="notificationSystem" style={false} />
<Modal ref="modal" />
</div>
);
};
}
Modal.js
import React from "react";
import ReactDOM from 'react-dom';
import SVGInline from "react-svg-inline";
import {closeSvg} from '#/utils/Svg';
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
showHeader: true,
showFooter: false,
title: "",
size: '',
className: '',
id: '',
footerContent: null,
showSubmitBtn: true,
showCancelBtn: true,
cancelBtnText: "Cancel",
successBtnText: "Save Changes",
onModalClose: () => {},
showModal: false,
html: () => {}
}
this.updateProps = this.updateProps.bind(this);
this.hideModal = this.hideModal.bind(this);
}
componentWillMount() {
var self = this;
var $modal = $(ReactDOM.findDOMNode(this));
}
componentDidUpdate(prevProps, prevState) {
if(this.state.showModal) {
$('body').addClass('modal-open');
} else {
$('body').removeClass('modal-open');
}
}
componentWillUnmount() {
// $('body').removeClass("modal-open");
}
componentWillReceiveProps(nextProps) {
console.log(nextProps);
}
updateProps(args) {
let merged = {...this.state, ...args};
this.setState(merged);
}
hideModal() {
this.setState({
showModal: false
});
this.state.onModalClose();
}
buildFooter() {
if(this.props.footerContent) {
return (
<div class="content">
{this.props.footerContent}
</div>
)
} else if(this.props.showCancelBtn && this.props.showSubmitBtn) {
return (
<div class="buttons">
<button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>{this.props.cancelBtnText}</button>
<button type="button" class="btn btn-success">{this.props.successBtnText}</button>
</div>
);
} else if(this.props.showCancelBtn) {
return (<button type="button" class="btn btn-default" data-dismiss="modal" onClick={this.props.onModalClose}>Close</button>);
} else if(this.props.showSubmitBtn) {
return (<button type="button" class="btn btn-success">Save changes</button>);
}
}
render() {
let {
id,
className,
onModalClose,
size,
showHeader,
title,
children,
showFooter,
showModal,
html
} = this.state;
return (
<div class={`modal-wrapper`} >
{
showModal ?
<div class={`modal fade in ${className}`} role="dialog">
<div class="bg" ></div>
<div class={`modal-dialog ${size}`}>
<div class="modal-content">
{ showHeader ?
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<SVGInline svg={closeSvg} />
</button>
<h4 class="modal-title">{ title }</h4>
</div> : '' }
<div class="modal-body" >
{html()}
</div>
{ showFooter ?
<div class="modal-footer">
{ this.buildFooter() }
</div> : ''
}
</div>
</div>
</div>
: ''
}
</div>
);
}
}
then in any of your child components you can just call within your render function:
app.notify({
message: message,
level: 'error'
});
or
app.modal({
showModal: true,
className: "fullscreen-image-modal",
size: "modal-lg",
html: () => {
return (<img src={listingManager.LISTINGS_PATH + imgUrl} />);
}
})

i want to display JSON result in reactJs

This is my JSON result
Using Map function to display JSON array elements in reactJs.I have tried with the following code. I'm unable to get results and it says "Cannot read property '_currentElement' of null". Kindly help me to solve this.
import React, { Component } from 'react';
import Header from './js/components/Header';
import './App.css';
import './dist/css/bootstrap.css';
import cookie from 'react-cookie';
import Request from 'superagent';
import { browserHistory } from 'react-router';
export default class Performance extends Component {
constructor() {
super();
this.state = {
fullName : cookie.load('fullName'),
empId : cookie.load('empId'),
userResults : false
};
if(cookie.load('empId') === undefined ){
browserHistory.push('/login')
}
}
getInitialState(){
return {userResults:false};
}
componentDidMount() {
var self = this;
var url = 'http://192.168.1.93:8081/employee/dashboard';
Request
.get(url)
.query({ empId: this.state.empId })
.set('Content-Type', 'application/x-www-form-urlencoded;charset=utf-8')
.set('Authorization', 'Basic aHJtczox')
.set('Accept', 'application/json')
.end(function(err, res){
self.setState({userResults: res.body});
console.log(self.state.userResults);
});
}
render() {
return (
<div>
<Header />
<div className="container ">
<form className="form-signin1">
<h2 className="form-signin-heading">Customer Orientation{this.props.userButtons}</h2>
<table className="table text-center" >
<thead>
<th >Deliverables</th>
</thead>
<tbody>
{
this.state.userResults.response.QuestionSection.map(function(res){
res.question.map(function(res1){
return (
<tr>
<td>{res1.question}</td>
</tr>
)
})
})
}
<tr><td>sdfsdf</td></tr>
</tbody>
</table>
<button className="btn btn-lg btn-primary btn-block" type="button">Sign in</button>
</form>
</div>
</div>
);
}
}
Since this.state.userResults.response doesn't exist initially you get this error. Its is better of performing a check before iterating. Also you need to return the result of inner map function too like
{
this.state.userResults.response && this.state.userResults.response.QuestionSection.map(function(res){
return res.question.map(function(res1){
return (
<tr>
<td>{res1.question}</td>
</tr>
)
})
})
}

Categories