Whenever you are building data intensive applications, 

  1. tiny null value can cause entire application crash
  2. API loading time can cause entire application crash
  3. User actions can cause entire application crash
  4. API errors can cause entire application crash
But how will you find out ?, mostly end users don't complain about them, they just refresh the screen. But we should provide them an option to raise an issue, in that way developers will be more cautious about frontend issues.

Library:

Created Java Script library, which can be used with all frameworks like React, Angular, jQuery etc..

React Application:

Lets get into example. Here I will implement react application with crash-report-js. 

1. Create ErrorBoundary.js to catch errors on application

import React from "react";
import { addTrack, getAllTracks } from "crash-report-js";

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
this.submitCrashReport = this.submitCrashReport.bind(this);
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
addTrack({
type: 'log',
target: error,
value: errorInfo,
});
}

submitCrashReport() {
// Add your logic here to submit report to backend
console.log('has error', this.state.hasError);
console.log('crash report', getAllTracks());
}
render() {
if (this.state.hasError) {
return <div>
<div style={{margin: 8}}>Something wrong</div>
<div style={{margin: 8}}>
<button onClick={this.submitCrashReport}>Submit Crash Report</button>
</div>
</div>;
}
return this.props.children;
}
}

export default ErrorBoundary;

2. Now include your React App into this ErrorBoundary

import { useEffect } from 'react';
import { clearTracks, initTracks} from 'crash-report-js';
import AppContainer from './AppContainer';
import ErrorBoundary from './ErrorBoundary';

export default function App() {

// init crash-report-js, first clear all tracking data then initiate tracking session
useEffect(() => {
clearTracks();
initTracks();
}, []);

return (
// including whole app into ErrorBoundary
<ErrorBoundary>
<AppContainer />
</ErrorBoundary>
);
}


Whenever your application crashes, 'Submit Crash Report' button will appear, on click on that button, all tracking data will be submitted to backend. You can see crash report data in the session storage

crash-report-js-extension

How to inspect and test this crash report ?
  1. Install chrome extesion https://chromewebstore.google.com/detail/crash-report-js-extension/pacgfjjelhfpalaoniejckhjpkibonib
  2. Open chrome side panel, and follow below steps







Read More

 If you are building frontend application, Sometimes you need to track the user actions for debugging or performance improvement or for A/B testing. What are the important actions essential for these use cases

  1. click
  2. URL change
  3. API calls
  4. input change event
How to do this ?
  1. Storing this tracking data in sessionStorage is a good idea since it won't share with other tabs.
  2. If user performs above actions, then store those info in  sessionStorage as array of actions with time
Here is the code snippet

const generateXPathWithNearestParentId = element => {
let path = '';
let nearestParentId = null;

// Check if the current element's has an ID
if (element.id) {
nearestParentId = element.id;
}

while (!nearestParentId && element !== document.body) {
const tagName = element.tagName.toLowerCase();
let index = 1;
let sibling = element.previousElementSibling;

while (sibling) {
if (sibling.tagName.toLowerCase() === tagName) {
index += 1;
}
sibling = sibling.previousElementSibling;
}

if (index === 1) {
path = `/${tagName}${path}`;
} else {
path = `/${tagName}[${index}]${path}`;
}

// Check if the current element's parent has an ID
if (element.parentElement.id) {
nearestParentId = element.parentElement.id;
break; // Stop searching when we find the nearest parent with an ID
}

element = element.parentElement;
}
if (nearestParentId) {
path = `//*[@id='${nearestParentId}']${path}`;
return path;
}
return path; // No parent with an ID found
};

const handleClick = event => {
const tracks = JSON.parse(
sessionStorage.getItem('tracks') || '[]'
);
const target = generateXPathWithNearestParentId(event.target);
const track = {
type: 'click',
target,
time: new Date(),
};
tracks.push(track);
sessionStorage.setItem('tracks', JSON.stringify(tracks));
};

const handleChange = event => {
const tracks = JSON.parse(
sessionStorage.getItem('tracks') || '[]'
);
const prevCommand =
tracks && tracks.length ? tracks[tracks.length - 1] : null;
const target = generateXPathWithNearestParentId(event.target);
const track = {
type: 'change',
target,
value: event.target.value,
time: new Date(),
};
if (
prevCommand &&
prevCommand.type === 'change' &&
prevCommand.target === target
) {
tracks.pop();
}
tracks.push(track);
sessionStorage.setItem('tracks', JSON.stringify(tracks));
};

const handleDocumentLoad = () => {
let oldHref = document.location.href;
const body = document.querySelector('body');
const observer = new MutationObserver(mutations => {
if (oldHref !== document.location.href) {
oldHref = document.location.href;
const tracks = JSON.parse(
sessionStorage.getItem('tracks') || '[]'
);
const track = {
type: 'url',
value: oldHref,
time: new Date(),
};
tracks.push(track);
sessionStorage.setItem('tracks', JSON.stringify(tracks));
}
});
observer.observe(body, { childList: true, subtree: true });
};
document.addEventListener('click', handleClick);
document.addEventListener('input', handleChange);
window.onload = handleDocumentLoad;


Read More

We display images according to the width of the parent div. If you need to position items on that image based on x, y coordinates, you must calculate the final x, y coordinates based on the resize factor of that image. The following code snippet will assist you in obtaining the resize factor. Using this factor, you can resize the image for a specific width and height and retrieve the dimensions of the final image with the applied resize factor.

const getImageDimension = (url, adjustWidth, adjustHeight) => {
return new Promise(async (resolve, reject) => {
if (url) {
const img = new Image();
img.onload = element => {
const hFactor = element.target.height / adjustHeight;
const wFactor = element.target.width / adjustWidth;
if (hFactor > wFactor) {
const dim = {
width: element.target.width,
height: element.target.height,
factor: element.target.height / adjustHeight
};
if (adjustHeight) {
dim.width = element.target.width * (adjustHeight / dim.height);
dim.height = adjustHeight;
}
resolve(dim);
} else {
const dim = {
width: element.target.width,
height: element.target.height,
factor: element.target.width / adjustWidth
};
if (adjustWidth) {
dim.height = element.target.height * (adjustWidth / dim.width);
dim.width = adjustWidth;
}
resolve(dim);
}
};
img.onerror = () => {
reject(new Error('Image not found'));
};
img.src = url;
} else {
reject(new Error('Invalid Image URL'));
}
});
};
Read More
Recently, I tried to generate XPath for an HTML element using available coding snippets. Most of them are generated using class names. However, since React MUI uses dynamic class names through make-styles, the above method of generating XPaths is not always reliable. Therefore, I developed a code that uses only IDs to generate XPath. If you are also facing the same issue as mine, this will be useful for you.
export const generateXPathWithNearestParentId = (element) => {
    let path = '';
    let nearestParentId = null;

    // Check if the current element's has an ID
    if (element.id) {
        nearestParentId = element.id;
    }

    while (!nearestParentId && element !== document.body) {
        const tagName = element.tagName.toLowerCase();
        let index = 1;
        let sibling = element.previousElementSibling;

        while (sibling) {
            if (sibling.tagName.toLowerCase() === tagName) {
                index += 1;
            }
            sibling = sibling.previousElementSibling;
        }

        if (index === 1) {
            path = `/${tagName}${path}`;
        } else {
            path = `/${tagName}[${index}]${path}`;
        }

        // Check if the current element's parent has an ID
        if (element.parentElement.id) {
            nearestParentId = element.parentElement.id;
            break; // Stop searching when we find the nearest parent with an ID
        }

        element = element.parentElement;
    }

    if (nearestParentId && nearestParentId !== 'doodlemars-nav-gpt-section') {
        path = `//*[@id='${nearestParentId}']${path}`;
        return path;
    }
    return null; // No parent with an ID found
}
Read More
HTML5 web sockets provides stable connectivity to servers. By using these web sockets we can setup a stable connection between browser and sever, and then we can send or receive messages.

Like shown in below image, users send and receive messages on real time


Observe below GIF, One is chrome and another is firefox, Whatever we type in chrome, that will be displayed in firefox.

Lets write java program for sharing editor

Java Program

To run below program, you need add java_websocket dependency. Here it is the maven dependency xml.
<dependency>
  <groupId>org.java-websocket</groupId>
  <artifactId>Java-WebSocket</artifactId>
  <version>1.3.0</version>
</dependency>

Once you install the above dependencies, run below program
import java.net.InetSocketAddress;
import java.util.HashSet;
import java.util.Set;

import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;

public class App extends WebSocketServer {

    private static int TCP_PORT = 4444;
    private String value = "";

    private Set<WebSocket> conns;

    public App() {
        super(new InetSocketAddress(TCP_PORT));
        conns = new HashSet<WebSocket>();
    }

    @Override
    public void onOpen(WebSocket conn, ClientHandshake handshake) {
        conns.add(conn);
        conn.send(value);
        System.out.println("New connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
    }

    @Override
    public void onClose(WebSocket conn, int code, String reason, boolean remote) {
        conns.remove(conn);
        System.out.println("Closed connection to " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
    }

    @Override
    public void onMessage(WebSocket conn, String message) {
        System.out.println("Message from client: " + message);
        value = message;
        for (WebSocket sock : conns) {
            sock.send(message);
        }
    }

    @Override
    public void onError(WebSocket conn, Exception ex) {
        //ex.printStackTrace();
        if (conn != null) {
            conns.remove(conn);
            // do some thing if required
        }
        System.out.println("ERROR from " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
    }
    
    public static void main(String[] args) {
        new App().start();
    }
}

HTML Code 

This code contains textarea element. Whatever user types in that textarea, it will be sent to java web socket server. Java server will send that message to all its connections. That is how one user's text will be shown to all users. 
<!DOCTYPE html>
<html>
    <head>
    <style>
        .layout {
            width:800px;
            margin:auto;
        }
        
        textarea {
            max-width:800px;
            width:80%;
            border:1px solid #ccc;
            font-size:14px;
            height:400px;
        }
    </style>
    <script>
        var ws = new WebSocket("ws://127.0.0.1:4444/");
        var elm = document.getElementById('myTextArea');
    
        ws.onopen = function() {
            console.log("Opened!");
        };
    
        ws.onmessage = function (evt) {
            myTextArea.value = evt.data;
        };
    
        ws.onclose = function() {
            alert("Closed!");
        };
    
        ws.onerror = function(err) {
            alert("Error: " + err);
        };
    
        function share(event) {
            ws.send(event.target.value);
        }
    </script>
    </head>
    <body>
       <div class="layout">
        <h1>Sharing editor</h1> 
        <textarea id="myTextArea" onkeyup="share(event)" rows="100" cols="50"></textarea>
       </div>
    </body>
</html>
Read More
react-bootstrap-date-time-picker is built on react-bootstrap and moment, so make sure that you have react-bootstrap and moment in your modules.  Lets see some code.

Install

npm install react-bootstrap-date-time-picker --save

Import

import DateTimePicker from 'react-bootstrap-date-time-picker';

Main Features

  • Can be used as simple date picker
  • Can be used as simple time picker
  • Can be used as simple date-time picker
  • Calendar placement
  • Restricting date-time range

Properties

Here are some important properties of DateTimePicker
  1.   defaultValue - string - default input value
  2.   value - string - input value
  3.   onChange - callback function on change of input value
  4.   onClear - callback function on clear of input value
  5.   onBlur - callback function on blur of input
  6.   onFocus - callback function on focus of input
  7.   autoFocus - bool - setting focus automatically
  8.   disabled - bool - disabling input value
  9.   showClearButton - bool - showing clear button
  10.   calendarPlacement - string - calendar placement, ex: "top", "bottom"
  11.   dateFormat - string- input format, ex: "MM/DD/YYYY HH:mm:ss"
  12.   showTodayButton - bool - showing To Day button calendar ,
  13.   todayButtonLabel - string - To Day button text
  14.   from - Date - lowest possible date for selection
  15.   to - Date - highest possible date for selection
  16.   calendarOnly - bool - If you want to display as only calendar
  17.   timeOnly - bool - If you want to display as only time

Limit Range

The default range is 20 years (10 years back from current date to 10 years after from current date). You can give your own range by passing from and to values. Observe below code 
<DateTimePicker 
 from={new Date("2017-03-15T14:28:06+05:30")} 
 to={new Date("2017-03-30T14:28:06+05:30")} 
 onChange={this.handleChange} 
 value={this.state.date} 
/>

Date Format

Here this library uses momentjs for formatting the date string, So just follow the same formate specifications. Here are some useful formats
  1. DD/MM/YYYY - It will show just date
  2. DD/MM/YYYY HH:mm:ss - It will show date and time 24 hours format
  3. DD/MM/YYYY hh:mm:ss A - It will show date and time 12 hours format
You can follow your own customised date formats based on momentjs
<DateTimePicker 
 dateFormat="DD/MM/YYYY hh:mm:ss A"
/>

Display Calendar only 

Use calendarOnly property to display calendar only and hiding time
<DateTimePicker 
 calendarOnly={true}
/>

Display Time Only

Use timeOnly property to display time only
<DateTimePicker 
 timeOnly={true}
/>

Show or hide clear button

Use showClearButton property to display or hide clear button. Here if you should pass dateFormat, from and to
<DateTimePicker 
 showClearButton={false}
 dateFormat="HH:hh:ss"
 from={fromValue}
 to={toValue}
/>
Read More
This React library allows you to enlarge part of an image with a CSS3 based magnifying glass effect. When user mouse over on the image, it will show original enlarged image in magnifying glass. 
react-tweet-parser source on Github       DEMO

Install react-magnify

npm install react-magnify --save

Import Magnify

import Magnify from 'react-magnify';

Properties

It supports all image properties. src property is mandatory property 
  1. src - source of the image

Usage

Use Magnify component like below
<Magnify style={{
          width:'200px'
        }} src="http://thecodeplayer.com/uploads/media/iphone.jpg"></Magnify

Full Example 

Find below for full example
import React from 'react';
import Magnify from 'react-magnify';
import '../../node_modules/react-magnify/lib/react-magnify.css'

export default class App extends React.Component {

  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div style={{
        width:'500px',
        margin:'auto'
      }}>
        <h1>It Works with react-magnify</h1>
        <Magnify style={{
          width:'200px'
        }} src="http://thecodeplayer.com/uploads/media/iphone.jpg"></Magnify>
      </div>
    )
  }
}
Read More

Blogroll

Popular Posts