How to create Material UI Dialog with OK Cancel

Install the latest Material UI core package from npm:

npm install @material-ui/core @latest

Import the following components required for the Dialog box:

import React from "react";
import { withStyles } from "@material-ui/core/styles";
import Checkbox from "@material-ui/core/Checkbox";
import Dialog from "@material-ui/core/Dialog";
import DialogContent from "@material-ui/core/DialogContent";
import DialogActions from '@material-ui/core/DialogActions';
import { DialogContentText } from "@material-ui/core";
import MuiDialogTitle from "@material-ui/core/DialogTitle";
import CloseIcon from '@material-ui/icons/Close';
import Typography from '@material-ui/core/Typography';
import Button from "@material-ui/core/Button";
import IconButton from '@material-ui/core/IconButton';

Add the following styles for the Dialog content and buttons:

const styles = theme => ({
    root: {
      margin: 0,
      padding: theme.spacing(2),
    },
    closeButton: {
      position: 'absolute',
      right: theme.spacing(1),
      top: theme.spacing(1),
      color: theme.palette.grey[500],
    },
    dialogText: {
      color: theme.palette.blue
    }
  });

The following component will be used in the Dialog Title bar:

const DialogTitle = withStyles(styles)(props => {
    const { children, classes, onClose, ...other } = props;
    return (
      <MuiDialogTitle disableTypography className={classes.root} {...other}>
        <Typography variant="h6">{children}</Typography>
        {onClose ? (
          <IconButton aria-label="close" className={classes.closeButton} onClick={onClose}>
            <CloseIcon />
          </IconButton>
        ) : null}
      </MuiDialogTitle>
    );
  });

Add the class Component that will render the Dialog box:

class MyForm extends React.Component {
    constructor(props) {
      super(props);
	  this.handleChange = this.handleChange.bind(this);
	  this.handleDialogClose = this.handleDialogClose.bind(this);
	  this.handleDialogOK = this.handleDialogOK.bind(this);
	  this.state = {
		dialogText: '',
        isDialogOpen: false,
		isChecked: false
	  }
	}
	
	handleDialogOK() {
      console.log('Clicked OK!');
      this.setState({
        isDialogOpen: false
      });
    }
	
	handleDialogClose() {
      this.setState({
        isDialogOpen: false
      });
    }
	
	handleChange(e) {
      const target = e.target;
	  const value = target.checked;
	  
	  this.setState({
		isChecked: value,
		isDialogOpen: true
	  }, ()=> {console.log('Open Dialog')});
	}
	
	render() {
      const { classes } = this.props;
      return (
		<div>
			<Checkbox id="chkOpenDialog" onChange={this.handleChange} checked={this.state.isChecked}></Checkbox>
			<Dialog
                open={this.state.isDialogOpen}
                onClose={this.handleDialogClose}
                aria-labelledby="alert-dialog-title"
                aria-describedby="alert-dialog-description"
            >
              <DialogTitle id="customized-dialog-title" onClose={this.handleDialogClose}>
                  {"Message from Application"}
              </DialogTitle>
              <DialogContent>
                <DialogContentText id="alert-dialog-description" className={classes.dialogText}>
                  {this.state.dialogText}
                </DialogContentText>
                <DialogActions>
                  <Button color="primary" onClick={this.handleDialogOK}>
                      OK
                  </Button>
                  <Button color="primary" onClick={this.handleDialogClose}>
                      Cancel
                  </Button>
                </DialogActions>
              </DialogContent>  
          </Dialog>
		</div>
	  );
    }
}

export default withStyles(styles, { withTheme: true })(MyForm);

Setting the isDialogOpen to true on clicking checkbox will open the Dialog box with OK and Cancel Action buttons. Each Action button has it’s own handler.

Upload file in ReactJS to WebAPI

Create a new React App using create-react-app as explained in this Post. The sample ReactJS code is available here.

In the index.js file change the code as below:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

For the App.js file, change the code as below:

import React from 'react';       
import './App.css';
import Fileupload from './FileUpload'
function App() {    
  return (    
    <div className="App">    
      <Fileupload></Fileupload>
    </div>    
  );    
}
export default App;

Now comes the FileUpload component as FileUpload.js:

import React from 'react';
import axios from 'axios';

class Fileupload extends React.Component {

    constructor(props) {    
            super(props);    
            this.state = {    
                    file: '',    
        };    
    }

    async submit(e) {    
        e.preventDefault();    
        const url = `http://url`;    
        const formData = new FormData();    
        formData.append('body', this.state.file);    
        const config = {    
            headers: {    
                'content-type': 'multipart/form-data',
                'token': 'xxx'                
            },
        };
        const HTTP = axios.create({
            withCredentials: true
        });

        //return post(url, formData, config);
        return HTTP.post(url, formData, config);
    }
    setFile(e) {    
        this.setState({ file: e.target.files[0] });    
    }

    render() {    
        return (    
                <div className="container-fluid">    
                        <form onSubmit={e => this.submit(e)}>    
                                <div className="col-sm-12 btn btn-primary">    
                                        File Upload    
                        </div>    
                                <h1>File Upload</h1>    
                                <input type="file" onChange={e => this.setFile(e)} />    
                                <button className="btn btn-primary" type="submit">Upload</button>    
                        </form>    
                </div>    
        )    
    }
}
export default Fileupload

Here I’m using axios to call the API via Post request. Passing the credentials in the call with create.
The token part is optional in the Headers, you can add/remove headers based on your requirement.

From the WebAPI end, I’m using .Net core. You can receive the file in the Action method as below:

[HttpPost]
[Route("upload")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public IActionResult UploadForm([FromQuery] string username)
{
	var request = HttpContext.Request;
            
	if (request.Form.Files.Count > 0)
	{
		filename = request.Form.Files[0].FileName;
		extension = filename.Substring(filename.LastIndexOf(".")).ToLower();
		if (!string.IsNullOrEmpty(extension) && extension.Equals(".docx"))
		{
			using (var memoryStream = new MemoryStream())
			{
				request.Form.Files[0].CopyTo(memoryStream);
				
				// Upload the file if less than 2 MB
				if (memoryStream.Length < 2097152)
				{
					string check = Service.CheckifValid(username);
					if (check.Equals("ok"))
					{
						//Process the stream and pass the data to the back-end in the Service Layer.
						result = Service.UploadStream(memoryStream, filename, extension, username);
					}
					else
					{
						return Ok(check);
					}
				}
				else
				{
					return BadRequest("File size too large");
				}
			}
		}
		else
		{
			return BadRequest("File format not recognised.");
		}
	}
	//Other ToDos...
}

Download word file using axios get from WebAPI

The below code is using axios get method with Headers token to be passed with credentials which in this case would be Windows Authentication to the WebAPI.

The response returned by the Promise contains the header “content-disposition” which has the name of the file being downloaded.

The content-disposition header value is as below:

attachment; filename="SomeFile.docm"; filename*=UTF-8''SomeFile.docm

The content-type required for this file from the API is:

application/vnd.openxmlformats-officedocument.wordprocessingml.document

The returned response has the blob in the data property which then requires to be converted to a downloadble link. The filename is being extracted from the content-disposition header.

const HTTP1 = axios.create({
                  withCredentials: true
                });
const response = HTTP1.get('http://path/worddoc?userid=<someid>', {
		        headers: {
		          'token': 'xxxxx'
		        },
				responseType: 'blob'
		      }).then((response) => {
			
				const headerval = response.headers['content-disposition'];
				var filename = headerval.split(';')[1].split('=')[1].replace('"', '').replace('"', '');
				
				const downloadUrl = window.URL.createObjectURL(new Blob([response.data]));
				const link = document.createElement('a');
				link.href = downloadUrl;
				link.setAttribute('download', filename); //any other extension
				document.body.appendChild(link);
				link.click();
				link.remove();
			  });

Use package react-svg-radar-chart to create Radar chart ReactJS

Create a basic ReactJS App using the create-react-app Post here.

Our final aim is to generate a Radar Chart using the npmjs package react-svg-radar-chart. Also, the dot markings on the chart should be able to show the current index and key, values on the chart on Hover as shown below.

The code is available in my Github profile.

Install the Package in your Project by running the following command in the Terminal:

npm install react-svg-radar-chart

Replace the code for the index.js file as shown below:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

Create the App.js file for the App component and add the below code:

import React, { Component } from "react";
import MyComp from "./MyComp";
import MyRadarComp from "./MyRadarComp";

export default class App extends Component {
    render() {
        return (
          <div className="App">
            <MyRadarComp />
          </div>
        );
      }
}

Create MyRadarComp.js file and add the below code:

import React from 'react';
 
import RadarChart from 'react-svg-radar-chart';
import 'react-svg-radar-chart/build/css/index.css'
 
export default class MyRadarComp extends React.Component {
  render() {
    const tooltipstyle = {
        position: 'relative',
        display: 'inline-block',
        borderBottom: '1px dotted black'
    }

    const tooltiptextstyle = {
        visibility: 'hidden',
        width: '220px',
        backgroundColor: 'black',
        color: '#fff',
        textAlign: 'center',
        borderRadius: '6px',
        padding: '5px 0',
    
        /* Position the tooltip */
        position: 'absolute',
        zIndex: '1',
    }

 	 const data = [
      {
        data: {
          battery: 0.5,
          design: .7,
          useful: 0.985,
          speed: 0.57,
          weight: 0.7
        },
        meta: { color: 'blue' }
      },
      {
        data: {
          battery: 0.6,
          design: .85,
          useful: 0.5,
          speed: 0.6,
          weight: 0.7
        },
        meta: { color: 'red' }
      },
      {
            data: {
              battery: 0.7,
              design: .8,
              useful: 0.9,
              speed: 0.67,
              weight: 0.8
            },
            meta: { color: '#58FCEC' }
        }
    ];
 
    const captions = {
      // columns
      battery: 'Battery Capacity',
      design: 'Design',
      useful: 'Usefulness',
      speed: 'Speed',
      weight: 'Weight'
    };

    const noSmoothing = points => {
        let d = 'M' + points[0][0].toFixed(4) + ',' + points[0][1].toFixed(4);
        for (let i = 1; i < points.length; i++) {
          d += 'L' + points[i][0].toFixed(4) + ',' + points[i][1].toFixed(4);
        }
        return d + 'z';
      };
       
      const defaultOptions = {
        size: 200,
        axes: true, // show axes?
        scales: 3, // show scale circles?
        captions: true, // show captions?
        captionMargin: 10,
        dots: true, // show dots?
        zoomDistance: 1.2, // where on the axes are the captions?
        setViewBox: (options) => `-${options.captionMargin} 0 ${options.size + options.captionMargin * 2} ${options.size}`, // custom viewBox ?
        smoothing: noSmoothing, // shape smoothing function
        axisProps: () => ({ className: 'axis' }),
        scaleProps: () => ({ className: 'scale', fill: 'none' }),
        shapeProps: () => ({ className: 'shape' }),
        captionProps: () => ({
          className: 'caption',
          textAnchor: 'middle',
          fontSize: 10,
          fontFamily: 'sans-serif'
        }),
        dotProps: () => ({
          className: 'dot',
          mouseEnter: (dot) => { 
              document.getElementById("tooltip").innerText = "index: " + dot.idx + ", key: " + dot.key + ", value: " + dot.value;
              document.getElementById("tooltip").style.visibility = "visible";
            },
          mouseLeave: (dot) => { 
              document.getElementById("tooltip").innerText = "";
              document.getElementById("tooltip").style.visibility = "hidden";
            }
        })
      };
 
    return (
      <div>
        <RadarChart
            captions={{
              // columns
              battery: 'Battery Capacity',
              design: 'Design',
              useful: 'Usefulness',
              speed: 'Speed',
              weight: 'Weight'
            }}
            data={data}
            size={400}
            options={defaultOptions}
          />
          <div id="divtool" style={tooltipstyle}><label id="tooltip" style={tooltiptextstyle}></label></div>
        </div>
    );
  }
}

Run the Project:

npm start

A few points about the MyRadarComp component:

  1. The code is taken from the npmjs package sample provided in the package description.
  2. I’ve modified the css a bit to show the dots on the chart and also show the values on the Hover event of the dots.
  3. The caption labels and the data property names should match in order to correctly display the data.

Setup Github Repo from Visual Studio Code

  1. Create the Project or directory on your file system. My local folder is called formik-sample. You can also create using the create-react-app Post here for a sample ReactJS App.
  2. Create a repository on Github. I’ve named it sample-form-reactjs.
  3. Click on Clone or Download. Copy the SSH link.
  4. Open the local folder in VS Code as created in Step 1.
  5. In the Terminal Window in VS Code, type the following commands:
  6. git config –global user.name someid
  7. git clone git@github.com:someid/sample-form-reactjs.git
  8. After this is done, just follow the same steps for git stage/commit/push etc.

For # 3:

However, if Step 5. gives error like below:

Check your network firewall settings if you’re doing it from Office. Try it out from your home and it should work.

Also, you can clone git@github which is SSH version but for that you have generate ssh keys and have to set it in local environment and if you don’t want to set up that then just use https version in the above clone command.

If you face branch related errors, since you might have already created a repo on Github, you can create a new branch as below:

git checkout -b some-sample

Then push the changes to the new branch:

git push --set-upstream origin some-sample

Using Fetch with React example async await

I’ve created a basic React App as described in my previous post. This is just a demo on how you can use fetch API to load data in the componentDidMount() lifecycle method with/without
async/await. I’ve not used any error handling yet.

The basic structure of the React App contains index.js and index.html files. The code is added to my Github profile.

Replace the code of the index.js file as below:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));

Create App.js file under the src directory and add the below code:

import React, { Component } from "react";
import MyComp from "./MyComp";
export default class App extends Component {
    render() {
        return (
          <div className="App">
            <MyComp />
          </div>
        );
      }
}

It’s time to create MyComp which is the sample component that will call the placeholder JSON API to show the list of users using Fetch GET request.

The code for MyComp is as shown below:

import React from "react";
export default class MyComp extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            usernames : []
        };
    }
    componentDidMount() {
        fetch('https://jsonplaceholder.typicode.com/users')
            .then(res => res.json())
            .then(json => this.setState({ usernames: json }));
    }
    render() {
        return(
            <div>
                Hey guys!
                <ul>
                {this.state.usernames.map(user => (
                    <li key={user.username}>
                    Hello, {user.username}
                    </li>
                ))}
                </ul>
            </div>
        );
    }
}

Run the App using as below:

npm start

The above code will now use async/await. It is a clean asynchronous way to call the API by writing unblocking code just like promises and callbacks.

Run the following command in the terminal:

npm i @babel/preset-env @babel/plugin-transform-runtime @babel/runtime --save

Replace the componentDidMount() code as below:

async componentDidMount() {
        const response = await fetch(`https://jsonplaceholder.typicode.com/users`);
        const json = await response.json();
        this.setState({ usernames: json });
    }

The async function which in this case is the componentDidMount contains the await expression that pauses the execution of the async function. It waits until the passed Promise is resolved. It then resumes the async function’s execution and evaluates as the resolved value.

Run the App again to see the results which are the same in this case.

You can also include headers and credentials in the Fetch call as shown below:

const myHeaders = new Headers();
myHeaders.append('token', 'xxxx');
const response = fetch(`http://someurl/home/details?username=someuser`, {
	credentials: 'include',
	headers: myHeaders,
	cors: 'cors'
  });

How to use package save-svg-as-png to download png image

This post explains how to use the package save-svg-as-png to download the png image of the contents in your svg element in your React component.

Create a basic React App as previously discussed in this post.

Create a component ImageWrapper as shown below:

import React from 'react'


export default class ImageWrapper extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
    }
  }

  render() {
    return (
      <div>
          <svg id={"svg-chart"} viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
            <rect x="0" y="0" width="100%" height="100%"/>
            <circle cx="50%" cy="50%" r="2" fill="white"/>
          </svg>
      </div>
    )
  }
}

Install the following package in your App with the command:

npm install save-svg-as-png

Modify the code in your App.js file as shown below:

import React, { Component } from "react";
import "./App.css";
import ImageWrapper from "./components/ImageWrapper";

const saveSvgAsPng = require('save-svg-as-png')

const imageOptions = {
  scale: 5,
  encoderOptions: 1,
  backgroundColor: 'white',
}

class App extends Component {

  handleClick = () => {
    saveSvgAsPng.saveSvgAsPng(document.getElementById('svg-chart'), 'shapes.png', imageOptions);
  };

  render() {
    return (
      <div className="App">
        <ImageWrapper />
        <br />
        <button onClick={this.handleClick}>Download Image</button>
      </div>
    );
  }
}

export default App;

Run the App with:

npm start

Click on the button Download Image to test.