Picture Competition Web App – Node JS, Mongo DB, Vue JS

Picture Competition is a mobile responsive real-time web application developed in Node JS and Mongo DB. Its frontend is designed in Bootstrap and Vue JS. You can create competition between 2 people and the others can vote on the person based on looks or skills etc.

Demo:

https://github.com/adnanafzal565/picture-competition-web-app-node-js

FeaturesFreePremium $100
Login and registrationYesYes
Create competitionsYesYes
Search & sortYesYes
Vote on CompetitionYesYes
Delete CompetitionYesYes
Reset PasswordNoYes
Email VerificationNoYes
Adult Image ValidationNoYes
SMTP Configurations Admin PanelNoYes
Real-time VotesNoYes
Real-time Admin Panel StatisticsNoYes
Real-time CommentsNoYes
User ProfileNoYes
Realtime update via socketsNoYes
NotificationsNoYes
Load more buttonNoYes
Admin panelNoYes
Manage competitionsNoYes
Free customer supportNoYes

Mongo DB Backend

competition’s collection

1. Login and Registration

It uses login authentication using JWT (JsonWebToken). It does not use the browser session due to the following reasons:

  1. Sessions are destroyed once your app is restarted from terminal.
  2. Sessions are not linked with the server, they are stored in browser only.

The benefit of using JWT is that you can always log out a user from your Mongo DB. Just go to the “users” collection and find the specific user. Then empty the “accessToken” field of that user’s document.

Login and Registration

2. Create Competitions

Registered users can create competitions between 2 users. You can enter name and upload 1 picture of each competitor. There is no limit in the number of competitions to create, you can create as many as you want. You can view your created competitions on your “My Competitions” page.

As soon as you create a competition, it will automatically be displayed to all the users as well as to the admin in real-time. Users do not have to refresh the page to see new competitions. It uses Socket IO to display data in real-time.

Create Competition

3. Search

Users can search competitions by the name of competitors. Data is filtered and rendered using Vue JS. There is no need to press the enter key, the data is filtered as soon as the user starts typing in the search box.

Search and Sort

4. Sort

Users can also sort the competitions by any of the following for sorting functions:

  1. Highest votes to lowest.
  2. Lowest votes to highest.
  3. Oldest to newest.
  4. Newest to oldest (default).

5. Vote on Competition

Logged-in users can vote on the competition. You can either vote on one of the competitors. Once the vote is cast on one competitor, it cannot be removed. Also, you can cast your vote on only one of the competitors, not on both of them. It is also real-time, as soon as the vote is cast, it will automatically be displayed to all the users and the counter is incremented. The counter displays the number of votes cast on each competitor.

Votes

6. Delete Competition

Competitions can only be deleted by either of the users who created the competition, or by the admin. Once the competition is deleted, all the uploaded images will be deleted too. As soon as the competition is deleted, it will automatically be removed from all the other users too, without having them refresh the page.

7. Realtime Update using Sockets

Sockets are used for real-time communication. Instead of fetching the data from the server after regular intervals, sockets attach listeners to the client-side. Listeners are listening to the events sent from the server. The server will emit the event and the client will listen to that event and respond accordingly. In this project, sockets are used for the following features:

  1. When competition is created.
  2. When competition is deleted.
  3. To increase the counter after vote is casted to the competition.
  4. Notifications.

8. Notifications

When a competition is deleted by the admin, the admin will write the reason for the deletion. Thus, a notification will be sent to the user along with the reason why his competition was removed. By default, notification status is “unread” and they are highlighted. As soon as the user clicks on any of the notifications, that notification will be marked as “read” and it will no longer be highlighted.

Notifications

9. Load More Button

When the data in the database increases, it is not feasible to load all the data in a single AJAX request. So a “load more” button is created to solve this problem. For example, 10 records are fetched in the first AJAX request. The next 10 records will be fetched when the “load more” button is clicked, and so on.

Load More

10. Admin Panel

Admin panel is created so you (administrator) can delete any competition you find offensive. The default email and password of admin are:

email = admin@gmail.com
password = admin

11. Manage Competitions

Admin can delete competitions that he finds offensive. However, the admin must give the reason why that competition is deleted. A notification will be sent to the user who created that competition and he will be able to view it from the top navigation bar.

12. Reset Password

Now you will be able to reset your password if you ever forgot. You just need to enter your email address and an email will be sent to you with a link to reset the password. We are using the nodemailer module to send an email.

Forgot Password
Reset Password

13. Email Verification

When a new user registers, we are sending a verification email to the user’s entered email address. The user will not be able to log in until he verifies his email address. When a user clicks the link on his email address, he will receive a message that says that his account is verified. Then he will be able to log in successfully.

Email Verification

14. SMTP Configurations from Admin Panel

To send an email, you will need an SMTP server. Every SMTP server requires some configurations to set up that include, host, port, email, and password. You can write these values directly hardcoded in your code, but to update these values in the future, you have to find these values in the code and update them.

In this project, you can set these configurations directly from the admin panel. Once the values are set, new emails will be sent using the new configurations.

SMTP configurations from admin panel

15. Adult Image Validation

This is a must-have feature if you are creating a website that allows users to upload pictures and they will be seen to the world. Anyone can upload an image that contains adult content, and it will not be good for your business. So when the user is uploading pictures while creating competition, the system will automatically check if the image is safe to upload.

If the image is an adult image, then an error will be shown to the user and it will not be uploaded.

16. Admin Panel Stats

Admin can see total users, total competitions, and total votes cast so far. They are also real-time, so when a new user is registered, or new competition is created, or event a new vote is cast, it will automatically be incremented here.

Also, when competition is deleted, the number will automatically get decremented as well, without having the admin refresh the page.

Admin Panel Stats

17. Real-time Comments

Users can comment on each competition. And they are also real-time as well. Once a new comment is added, it will immediately be displayed to all the other users as well. They do not have to refresh the page to see new comments.

Real-time Comments

18. User Profile

Users can now update their names and profile pictures. We are using the fs (file system) module to upload the picture. User can also add their bio, date of birth, country, and social media links. Media links include Facebook, Instagram, google plus, Twitter, and LinkedIn.

User can also change their account password. In order to change the password, the user must enter the current password. The new password should be entered twice for confirmation.

User Profile

19. Free Customer Support

This is not a feature of the project, but it is a free service provided for the pro version only. That means if you find any difficulty in installing or configuring the project, we will help you install it. Also, if you encounter any error or a bug in the released version, then it can be fixed too.

These are all the features we have right now in the picture competition web app. We are open to more ideas. If you have more ideas to add, kindly do let us know.

Financial Ledger in Node JS, Mongo DB, and Vue JS

A Financial Ledger script is created in Node JS, Mongo DB, and Vue JS. A financial ledger is used to track your daily finances, for example, your income, your expenses, etc. This script allows you to track your total income, total spending, and your current total balance. They are referred to as “stats” in the script. You can debit the entry by entering the amount that is negative. And you can credit an entry by simply writing its amount.

We have used the HTML and CSS code from this codepen. We have made it dynamic by using the latest technologies like, Vue JS for front-end, Node JS for back-end, and Mongo DB as the database. It has complete CRUD (Create, Read, Update, Delete) operation. It has the following features:

  1. Insert data in Mongo DB using Node JS.
  2. Fetch all documents from Mongo DB.
  3. Update specific document in Mongo DB.
  4. Delete documents from Mongo DB.
  5. Case-insensitive search in Mongo DB documents.
  6. Search by sub-string from Mongo DB document’s keys.
  7. Realtime data insert.
  8. Real-time update.
  9. Realtime deletes.
  10. “Load more” capability.
  11. Datetimepicker library.
  12. EJS templating engine.
  13. Express-formidable for handling form fields.
  14. Skip, limit and sort in Mongo DB.

Video tutorial:

1. Insert Data in Mongo DB using Node JS

An interface that allows you to enter the values (time, description, and amount), created in Vue JS. It binds those input field values to the Vue JS model. To enter the time, we are using a library datetimepicker. We are calling an AJAX request to the Node JS server with the input field values as FormData object when the form submits. That will simply insert a new document in Mongo DB collection “entries”. When the data is inserted, it is also inserted in the Vue JS array. This allows the new data to be appended automatically without having to refresh the page. The stat values automatically are updated based on if the entry is debit or credit.

2. Fetch All Documents from Mongo DB

An AJAX request is sent from the client to view all the data from the database. The server will return all the documents sorting from latest to oldest i.e. newest records will be shown first. The sorting is performed based on the date field selected during insertion. When the data is returned, it is concatenated in the Vue JS array that allows the user to view the data when the page loads. When the data is fetched, the stats are also updated automatically.

3. Update Specific Document in Mongo DB

To update specific documents, we are using Mongo DB auto-generated ObjectId field “_id”. This allows you to search the document, then we can perform the update query. To update the document, we are using HTML’s contenteditable attribute that allows you to edit the HTML node innerHTML by just typing in it. When the content of that div changes, we are sending an AJAX request to the Node JS server that performs the update query. If you update the amount value, then the stats will also get a change in real-time.

4. Delete Documents from Mongo DB

Deleting an entry will remove the document from the Mongo DB collection too. The row will be removed and the stats will be updated too.

5. Case insensitive Search Mongo DB

You can search the entries by description you have put during the insertion, or you can search the entries by either they are debited or credited. For example, you can write “debit” in the search box and it will show all the entries that are debited. The same goes for the “credit” search query.

6. Sub-string Search Mongo DB

While searching by description, you do not need to know the exact words. You can type the part of the description you have remembered and it will search the record anyway.

7. Realtime Mongo DB Data Insert

When a new entry is added, it is automatically prepended in the list using Vue JS. You do not have to refresh the page to view the new entries.

8. Realtime Update in Mongo DB

The same goes for the updation. You can update the entry’s description or the amount by simply typing in its box. When you start typing it automatically gets updated in the Mongo DB too. Also, the stats values also get updated if there is any change in the amount.

9. Realtime Delete in Mongo DB

With each entry, there is a minus (-) sign. On clicking that button, it will remove the entry from the list and also from the Mongo DB. The stats also gets updated accordingly.

10. Load More Capability

In the real-world, when you are creating a financial ledger, there will be hundreds of entries. So loading all entries when the page loads will slow down your application. So what we do is, load a few entries when the page loads. Then we show a button called “Load more”. Upon clicking that button, we will fetch the next entries from Mongo DB and so on. We will be using AJAX to fetch more entries.

11. Datetimepicker Javascript

In the financial ledger, it is important to enter the date the entry was added. So on the web, we have a library called datetimepicker by XDSoft. We are using this library to enter dates and times easily.

12. EJS Templating Engine in Node JS

In Node JS, to render files, there is an engine called EJS. It is used to render HTML files. The rendered files will have an extension “.ejs” instead of “.html” or “.php”.

13. Express Formidable Module in Node JS

In Node JS, to handle FormData object sent using AJAX, we are using a Node JS module named express-formidable. As the complete app is in Javascript, so there are a lot of AJAX requests in this app. Each AJAX request will send a FormData object to send values that the server will process.

14. Skip, Limit and Sort in Mongo DB

While fetching the records from Mongo DB, you can skip the records that are already been displayed to the user. Similarly, to load the data faster, you can limit the number of records to be fetched from Mongo DB in one request. To display the latest entries added, you can sort the records fetched from Mongo DB.

You can download the required assets from here:

Use SweetAlert confirmation dialog – HTML & Javascript

In this tutorial, we are going to show you, how you can show a sweetalert confirmation dialog when submitting a form. For example, if you have a form that when submits delete the data from the database. In that case, you must verify with the user because he might click that button by accident. So you can show a nice dialog using the Sweetalert library. Suppose you have the following form:

<form method="POST" action="do-something.php" onsubmit="return submitForm(this);">
	<input type="text" name="name" />
	<input type="submit" />
</form>

When the form submits, we are calling a Javascript function submitForm and passing the form as a parameter. Then you need to download the Sweetalert library from here. After downloading, paste that into your project and include it in your HTML file:

<script src="sweetalert.min.js"></script>

Now, we can create that Javascript function that will ask for confirmation. Once confirmed, it will submit the form.

<script>
	function submitForm(form) {
		swal({
			title: "Are you sure?",
			text: "This form will be submitted",
			icon: "warning",
			buttons: true,
			dangerMode: true,
		})
		.then(function (isOkay) {
			if (isOkay) {
				form.submit();
			}
		});
		return false;
	}
</script>

At this point, if you submit the form, you will see a SweetAlert confirmation dialog first. All the form fields will be submitted correctly on the server-side. You can check it by printing out all the values received from the form:

<?php
print_r($_POST);

Checkout 10 javascript libraries for every web project.

Track hand rotational angle – Leap + Javascript

In this tutorial, we are going to teach you how you can track your hand rotation using Leap Motion Controller. Leap Motion Controller is a device that allows you to detect your hand motions and gestures, and perform any desired action on them. It provides SDK in Java, Javascript, Python, C++, and Unreal Engine. We will be using Javascript in this tutorial.

You can buy the Leap Motion Controller from their official website. After buying, connect the device with your computer using a USB or USB-C port. Then download the SDK from here and do the installation.

If you prefer the video tutorial:

From the above video, you can see what we are going to create. So you will need a Doctor Strange time-spell video and some images. You will also need the Leap JS library to connect with Leap Motion Controller. You can find all 3 in the source files below.

Setup the Project

The following code helps you to reverse a video and concatenate 2 videos using FFmpeg:

// reverse a video
// ffmpeg -i Pentagramm2_green.mp4 -vf reverse reversed.mp4

// concatenate 2 videos
// ffmpeg -i Pentagramm2_green.mp4 -i reversed.mp4 -filter_complex "[0:v] [0:a] [1:v] concat=n=2:v=1:a=1 [v] [a]" -map "[v]" -map "[a]" output.mp4

Then create a video tag for the time-spell video.

<video src="output.mp4" muted id="time-spell"></video>

After that, create a div to show the image and text below it.

<div style="position: absolute; right: 50px; top: 50px;">
    <img src="images/2021.JPG" id="image" />
    <h1 id="title">2021</h1>
</div>

Now include the Leap JS library in your project.

<script src="leap-0.6.4.min.js"></script>

Then apply some CSS styles to display the video, image, and text properly.

<style>
    /* remove margin and set background color as black */
    body {
        margin: 0px;
        background-color: black;
    }

    /* set width of time spell and its position */
    #time-spell {
        width: 1200px;
        position: absolute;
        left: -275px;
        top: 30px;
    }

    /* set width and height of image and fit inside container */
    #image {
        width: 800px;
        height: 600px;
        object-fit: contain;
    }

    /* set color, position, alignment, font size and background color of image text */
    #title {
        color: white;
        position: relative;
        bottom: 129px;
        text-align: center;
        font-size: 70px;
        background-color: rgba(0, 0, 0, 0.7);
    }
</style>

Then create an array of images and their text in Javascript.

<script>

    // list of images and their text
    var images = [{
        "src": "images/2021.JPG",
        "title": "2021"
    }];

    // index is out of bound right now
    var index = images.length;

</script>

After that, initialize some variables that we will be using throughout the tutorial.

// total duration of time spell video
var totalDuration = 40;

// state of time spell (back or forward)
var state = "";

// previous state of time spell
var previousState = "";

// hand rotation from Leap Motion Controller
var handRotation = "";

// is time spell start rotating
var isMediaPlaying = false;

// video tag
var media = document.getElementById("time-spell");

Leap motion controller connection

Now is the time to connect our Javascript app with Leap Motion Controller.

// setup Leap loop with frame callback function
var controllerOptions = {};

Leap.loop(controllerOptions, function(frame) {
    // get all hands in frame
    var hands = frame.hands;

    // if there is any hand
    if (hands.length > 0) {

        // get the first hand
        var hand = hands[0];

        // ignore if the hand is left
        if (hand.isLeft) {
            return false;
        }

        // get direction of hand (x,y,z co-ordinates)
        var axis = hand.direction;

        // get x-axis
        axis = axis[0];

        if (axis > 0 && axis < 0.9) {
            // if hand is rotated to right
            handRotation = "right";
        } else if (axis > -0.09 && axis < -0.01) {
            // if hand is in center (no rotation)
            handRotation = "center";

            media.pause();
        } else if (axis < 0 && axis < -0.5) {
            // if hand is rotated to left
            handRotation = "left";
        }
    } else {
        // if there is no hand in the frame, simply pause the time spell
        if (media != null) {
            media.pause();
        }
    }
});

For explanation, comments have been added with each line. Now we need to call a function every 0.5 seconds and rotate the time spell to the left if the hand is rotated to left, and right if the hand is rotated to right. Also, it will call a function to change the image as per hand rotation.

// called every 0.5 seconds
setInterval(function () {
    
    // if hand is rotating to right
    if (handRotation == "right") {
        
        // only called once to rotate time spell
        if (state == "") {
            // rotate to right
            mediaBackward();
        }

        // if time spell starts rotating
        if (isMediaPlaying) {
            // show next image
            nextImage();
        }

        // make it empty to give a delay to show next image
        handRotation = "";
    } else if (handRotation == "left") {

        // only called once to rotate time spell
        if (state == "") {
            // rotate to left
            mediaForward();
        }

        // if time spell starts rotating
        if (isMediaPlaying) {
            // show previous image
            previousImage();
        }

        // make it empty to give a delay to show previous image
        handRotation = "";
    } else if (handRotation == "center") {
        // pause the time spell, when hand is in center of Leap Motion Controller
        media.pause();
    }
}, 500);

Now we just need to create these 4 functions called from the above code.

// when hand is rotated right
function mediaBackward() {

    // "back" means reverse
    state = "back";

    // starts rotating time spell
    media.play();

    // current time of video
    var currentTime = media.currentTime;

    // if video stops playing
    if (currentTime <= 0) {
        // starts from middle to move right
        currentTime = totalDuration / 2;
    }

    // this condition becomes true only when the
    // time spell was rotating forward (left side)
    if (previousState != state) {
        // change direction of time spell
        var newTime = totalDuration - currentTime;
        media.currentTime = newTime;
    }
}

// when hand is rotated left
function mediaForward() {

    // "forward" means original video
    state = "forward";

    // starts rotating time spell
    media.play();

    // current time of video
    var currentTime = media.currentTime;

    // if video stops playing
    if (currentTime <= 0) {
        // starts from zero to move left
        currentTime = totalDuration;
    }

    // this condition becomes true only when the
    // time spell was rotating backward (right side)
    if (previousState != state) {
        // change direction of time spell
        var newTime = totalDuration - currentTime;
        media.currentTime = newTime;
    }
}

// show next image from images array
function nextImage() {
    // increment the index
    index++;

    // check if the index is out of bound
    if (index >= images.length || index < 0) {
        return false;
    }

    // get source of image
    var src = images[index].src;

    // get text of image
    var title = images[index].title;

    // update image
    document.getElementById("image").setAttribute("src", src);

    // update title
    document.getElementById("title").innerHTML = title;
}

// show previous image from images array
function previousImage() {
    // decrement the index
    index--;

    // check if the index is out of bound
    if (index < 0 || index >= images.length) {
        return false;
    }

    // get source of image
    var src = images[index].src;

    // get text of image
    var title = images[index].title;

    // update image
    document.getElementById("image").setAttribute("src", src);

    // update title
    document.getElementById("title").innerHTML = title;
}

Finally, 2 event listeners are added to check when the time spell is rotating and when is paused. Based on that, we will set our variables to change images.

// called when the time spell starts rotating
media.onplaying = function () {
    // set the variable to true
    setTimeout(function () {
        isMediaPlaying = true;
    }, 100);
};

// called when the time spell is paused
media.onpause = function () {
    // get the previous state
    previousState = state;

    // set the current state as empty
    state = "";
    
    // set the variable to false
    isMediaPlaying = false;
};

Following this tutorial, you will be able to track hand rotations using Leap motion controller and Javascript.

Download source code:

[wpdm_package id=’1271′]

Social networking site in Laravel – Node JS, Socket IO

When you hear the word “social networking site”, the first name that came to your mind must be Facebook. Then Instagram, Twitter, etc. We create a social networking site project just to give you an idea of how things work. It is not the exact code used in tech giants like Facebook. But it gives you an idea of how they do it.

Demo

FeaturesFreePremium ($100)
AuthenticationYesYes
Profile UpdateYesYes
Create posts (with images and videos)YesYes
Like, comments and repliesYesYes
Share postsYesYes
Friends post on your wallYesYes
Search usersYesYes
Create friendsYesYes
Admin panelYesYes
Email verificationNoYes
Reset passwordNoYes
NotificationsNoYes
Realtime post update and deleteNoYes
NoYes
Search pages, and groupsNoYes
Create pages, and groupsNoYes
Private user-to-user chatNoYes
List of people who viewed your profileNoYes
Infinite scrollNoYes
people who liked and shared your postNoYes
Chat messages encryptionNoYes
Customer supportNoYes
Ban users, posts, pages, and groupsNoYes
Adult image validationNoYes
Show emails generated by systemNoYes
Online / offline statusNoYes
User last sceneNoYes
User activity logsNoYes

Previously, we create a Social Networking Site in Node JS and Mongo DB. But many people were asking that we create the same project in Laravel too, for PHP lovers. So here it is.

We have added 4 more features to it.

  1. Track system mails: All the emails sent from the system (Mail::to) function will be stored in a database. And the admin can view all the emails from the admin panel.
  2. Online/offline status: Now you can know when your friends are online and when they are offline. This will be helpful because you can just leave a message if the person is currently offline.
  3. Last scene of the user: You can also see your friend’s last scene active. This will help in situations like earthquakes etc. you can know which friends are not active in recent times.
  4. Track user activity: Admin can view the activities of users like when they are logged in when they created a page when they joined a group etc.

Task management & time tracking script – Javascript

We are going to create customized task management and time tracking script using simple HTML and Javascript. Since we are creating our own script, so we can customize it as much as we need. You can check the demo from here.

Video tutorial

Include libraries

First, we need to include all the libraries that we are going to use. We will be using Bootstrap for design and SweetAlert for displaying pop-up messages.

<!-- to make responsive -->
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<!-- include bootstrap css -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" />

<!-- include jquery and bootstrap js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.min.js"></script>

<!-- include sweetalert for displaying dialog messages -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/2.1.2/sweetalert.min.js"></script>

Add project

Then we are going to create a button that when clicked will display a Bootstrap modal to add a task.

<div class="container" style="margin-top: 50px; margin-bottom: 50px;">
    
    <!-- button to add task -->
    <div class="row" style="margin-bottom: 50px;">
        <div class="col-md-12">
            <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addTaskModal">Add Task</button>
        </div>
    </div>

</div>

Then we are going to create a Bootstrap modal. It will have a form with project and task name fields. It will also have a dropdown from which the user can select his already created projects.

<!-- modal to add project and task -->
<div class="modal fade" id="addTaskModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Add Task</h5>
                <button class="close" type="button" data-dismiss="modal">x</button>
            </div>

            <div class="modal-body">
                <form method="POST" onsubmit="return taskObj.addTask(this);" id="form-task-hour-calculator">
                    
                    <!-- select project from already created -->
                    <div class="form-group">
                        <label>Project</label>
                        <select name="project" id="add-task-project" class="form-control" required></select>
                    </div>

                    <!-- create new project -->
                    <div class="form-group">
                        <label>New Project</label>
                        <input type="text" name="new_project" id="add-project" class="form-control" placeholder="Project Name">

                        <button type="button" onclick="taskObj.addProject();" class="btn btn-primary" style="margin-top: 10px;">Add Project</button>
                    </div>

                    <!-- enter task -->
                    <div class="form-group">
                        <label>Task</label>
                        <input type="text" name="task" class="form-control" placeholder="What are you going to do ?" required />
                    </div>
                </form>
            </div>

            <!-- form submit button -->
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                <button type="submit" form="form-task-hour-calculator" class="btn btn-primary">Add Task</button>
            </div>
        </div>
    </div>
</div>

Then we need to create a Javascript function “addProject” inside the “taskObj” object. It will first check if there is any project selected, if not, then it will show an error message. Then it will create an empty array in local storage if not already created. Then it will create a new project object with empty “tasks” array. Finally, it will push the project into an array and update the local storage value, and also it will reload the projects and tasks.

// main object
var taskObj = {

    // local storage key
    key: "projects",

    // add project
    addProject: function () {

        // check if project is selected
        if (document.getElementById("add-project").value == "") {
            swal("Please enter project name");
            return false;
        }

        // initialize local storage if not already initialized
        var option = "";
        if (localStorage.getItem(this.key) == null) {
            localStorage.setItem(this.key, "[]");
        }

        // get stored object from local storage
        var data = JSON.parse(localStorage.getItem(this.key));

        // project object
        var project = {
            id: data.length,
            name: document.getElementById("add-project").value,
            tasks: []
        };

        // push new project in local storage
        data.push(project);
        localStorage.setItem(this.key, JSON.stringify(data));

        // re-load all projects
        this.loadAllProjects();

        // show all tasks
        this.showAllTasks();
    },

};

To load all the projects, we will be using the following 2 functions inside this object:

// get all stored projects
getAllProjects: function() {
    if (localStorage.getItem(this.key) == null) {
        localStorage.setItem(this.key, "[]");
    }
    return JSON.parse(localStorage.getItem(this.key))
},

// load all projects in dropdown
loadAllProjects: function () {
    var projects = taskObj.getAllProjects();
    projects = projects.reverse();
    var html = "<option value=''>Select Project</option>";
    for (var a = 0; a < projects.length; a++) {
        html += "<option value='" + projects[a].id + "'>" + projects[a].name + "</option>";
    }
    document.getElementById("add-task-project").innerHTML = html;
    document.getElementById("form-task-hour-calculator-all-projects").innerHTML = html;
},

We will do the “showAllTasks” function later. Now, when the page loads, we need to fetch all the projects and tasks and display them.

// when page loads
window.addEventListener("load", function () {
    // show all projects and tasks
    taskObj.loadAllProjects();
    taskObj.showAllTasks();
});

At this point, you will be able to create projects and see them in the dropdown. Now we need to add tasks.

Add task

To add a task, we will get the project and task name. Then we will push the newly created task object into the “tasks” array. Finally, we will update the local storage value, hide the Bootstrap modal and reload the tasks.

// add new task
addTask: function (form) {

    // get selected project and entered task
    var project = form.project.value;
    var task = form.task.value;

    // add task in project's array
    var projects = this.getAllProjects();
    for (var a = 0; a < projects.length; a++) {
        if (projects[a].id == project) {
            var taskObj = {
                id: projects[a].tasks.length,
                name: task,
                status: "Progress", // Progress, Completed
                isStarted: false,
                logs: [],
                started: this.getCurrentTimeInTaskStartEndFormat(),
                ended: ""
            }
            projects[a].tasks.push(taskObj);
            break;
        }
    }

    // update local storage
    localStorage.setItem(this.key, JSON.stringify(projects));

    // hide modal
    jQuery("#addTaskModal").modal("hide");
    jQuery('.modal-backdrop').remove();

    // re-load all tasks
    this.showAllTasks();

    // prevent form from submitting
    return false;
},

You might have see the function “getCurrentTimeInTaskStartEndFormat”. Our task management script will save the date and time in format YYYY-MM-DD HH:mm:ss e.g. 2021-06-15 20:53:15.

// get current datetime in proper format (e.g. 2021-06-15 20:53:15)
getCurrentTimeInTaskStartEndFormat() {
    let current_datetime = new Date();
    var date = current_datetime.getDate();
    date = (date < 10) ? "0" + date : date;
    var month = (current_datetime.getMonth() + 1);
    month = (month < 10) ? "0" + month : month;
    var hours = current_datetime.getHours();
    hours = (hours < 10) ? "0" + hours : hours;
    var minutes = current_datetime.getMinutes();
    minutes = (minutes < 10) ? "0" + minutes : minutes;
    var seconds = current_datetime.getSeconds();
    seconds = (seconds < 10) ? "0" + seconds : seconds;
    let formatted_date = current_datetime.getFullYear() + "-" + month + "-" + date + " " + hours + ":" + minutes + ":" + seconds;
    return formatted_date;
},

Show all tasks

To show all tasks, we need to create a table where we will display all tasks created.

<!-- show all tasks -->
<table class="table">
    <caption class="text-center">All Tasks</caption>
        <tr>
            <th>Task</th>
            <th>Project</th>
            <th>Status</th>
            <th>Duration</th>
            <th>Date</th>
            <th>Action</th>
        </tr>

    <tbody id="all-tasks"></tbody>
</table>

Now is the time to create a function “showAllTasks” in our “taskObj” object. This will be a long function, so we will explain the working of this function step-by-step:

// show all tasks in table
showAllTasks: function () {
    var html = "";

    // get all projects
    var projects = this.getAllProjects();
    for (var a = 0; a < projects.length; a++) {
        projects[a].tasks = projects[a].tasks.reverse();

        // get tasks in each project
        for (var b = 0; b < projects[a].tasks.length; b++) {
            html += "<tr>";
                html += "<td>" + projects[a].tasks[b].name + "</td>";
                html += "<td>" + projects[a].name + "</td>";
                if (projects[a].tasks[b].isStarted) {
                    html += "<td><label class='started'>Started</label></td>";
                } else {
                    if (projects[a].tasks[b].status == "Completed") {
                        html += "<td><label class='completed'>" + projects[a].tasks[b].status + "</label></td>";
                    } else {
                        html += "<td>" + projects[a].tasks[b].status + "</td>";
                    }
                }

                // get total duration of each task using it's logs
                var duration = 0;
                for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                    var log = projects[a].tasks[b].logs[c];
                    if (log.endTime > 0) {
                        duration += log.endTime - log.startTime;
                    }
                }

                // convert millisecond into hours, minutes and seconds
                duration = Math.abs((duration / 1000).toFixed(0));
                var hours = Math.floor(duration / 3600) % 24;
                hours = (hours < 10) ? "0" + hours : hours;
                // var days = Math.floor(diff / 86400);
                var minutes = Math.floor(duration / 60) % 60;
                minutes = (minutes < 10) ? "0" + minutes : minutes;
                var seconds = duration % 60;
                seconds = (seconds < 10) ? "0" + seconds : seconds;

                // show timer if task is already started
                if (projects[a].tasks[b].isStarted) {
                    var dataStartedObj = {
                        "duration": duration,
                        "project": projects[a].id,
                        "task": projects[a].tasks[b].id
                    };
                    html += "<td data-started='" + JSON.stringify(dataStartedObj) + "'>" + hours + ":" + minutes + ":" + seconds + "</td>";
                } else {
                    html += "<td>" + hours + ":" + minutes + ":" + seconds + "</td>";
                }

                // show task duration if completed
                if (projects[a].tasks[b].status == "Completed") {
                    html += "<td>" + projects[a].tasks[b].started + "<br><span style='margin-left: 30px;'>to</span><br>" + projects[a].tasks[b].ended + "</td>";
                } else {
                    html += "<td>" + projects[a].tasks[b].started + "</td>";
                }

                // form to change task status
                html += "<td>";
                    html += "<form method='POST' id='form-change-task-status-" + projects[a].id + projects[a].tasks[b].id + "'>";
                        html += "<input type='hidden' name='project' value='" + projects[a].id + "'>";
                        html += "<input type='hidden' name='task' value='" + projects[a].tasks[b].id + "'>";
                        html += "<select class='form-control' name='status' onchange='taskObj.changeTaskStatus(this);' data-form-id='form-change-task-status-" + projects[a].id + projects[a].tasks[b].id + "'>";
                            html += "<option value=''>Change status</option>";
                            if (projects[a].tasks[b].isStarted) {
                                html += "<option value='stop'>Stop</option>";
                            } else {
                                html += "<option value='start'>Start</option>";
                            }
                            if (projects[a].tasks[b].status == "Progress") {
                                html += "<option value='complete'>Mark as Completed</option>";
                            } else {
                                html += "<option value='progress'>Make in Progress Again</option>";
                            }
                            html += "<option value='delete'>Delete</option>";
                        html += "</select>";
                    html += "</form>";
                html += "</td>";
            html += "</tr>";
        }
    }
    document.getElementById("all-tasks").innerHTML = html;
},

The step number corresponds to the highlighted line above.

  1. First, we are looping through all projects and each project’s tasks.
  2. Displaying the task name and project name.
  3. If the task status is “started” then displaying a started message. (we will do this later).
  4. And if the task status is “completed”, then displaying a message for the completed task.
  5. Then we will get the total duration of each task.
  6. The duration will be in milliseconds, so we will convert that into days, hours, minutes, and seconds.
  7. If the task is started, then we will attach an attribute “data-started” to the <td> tag. This will allow us to continuously update the timer every second.
  8. And if the task is completed, then we will display the start and end times of the task. So you can know when the task started and when it is finished.
  9. And finally, we are creating a form from which we can change the status of the task.

Change task status

Now we need to create a function to change the status of the task. Again, this will be a long function, we will explain that step-by-step too.

// change task status
changeTaskStatus: function (self) {

    // if task is not selected
    if (self.value == "") {
        return;
    }

    // loop through all projects
    var formId = self.getAttribute("data-form-id");
    var form = document.getElementById(formId);
    var projects = this.getAllProjects();
    for (var a = 0; a < projects.length; a++) {

        // if project matches
        if (projects[a].id == form.project.value) {

            // loop through all tasks of that project
            for (var b = 0; b < projects[a].tasks.length; b++) {

                // if task matches
                if (projects[a].tasks[b].id == form.task.value) {

                    // if the status is set to delete
                    if (self.value == "delete") {

                        // ask for confirmation
                        swal({
                            title: "Are you sure?",
                            text: "Deleting the task will delete its hours too.",
                            icon: "warning",
                            buttons: true,
                            dangerMode: true,
                        })
                        .then((willDelete) => {
                            if (willDelete) {

                                // remove task from array
                                projects[a].tasks.splice(b, 1);

                                // update local storage
                                localStorage.setItem(this.key, JSON.stringify(projects));

                                // re-load all tasks
                                this.showAllTasks();
                            } else {

                                // reset dropdown
                                self.value = "";
                            }
                        });
                    } else if (self.value == "complete") {
                        // mark as completed
                        projects[a].tasks[b].status = "Completed";

                        // stop the timer
                        projects[a].tasks[b].isStarted = false;

                        // log end time
                        projects[a].tasks[b].ended = this.getCurrentTimeInTaskStartEndFormat();
                        for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                            if (projects[a].tasks[b].logs[c].endTime == 0) {
                                projects[a].tasks[b].logs[c].endTime = new Date().getTime();
                                break;
                            }
                        }
                    } else if (self.value == "progress") {
                        // mark as in progress
                        projects[a].tasks[b].status = "Progress";

                        // stop the timer
                        projects[a].tasks[b].isStarted = false;
                    } else if (self.value == "start") {
                        // ask for confirmation
                        swal({
                            title: "Are you sure?",
                            text: "This will start the timer.",
                            icon: "warning",
                            buttons: true,
                            dangerMode: true,
                        })
                        .then((doStart) => {
                            if (doStart) {
                                
                                // mark as started
                                projects[a].tasks[b].isStarted = true;

                                // add in log
                                var logObj = {
                                    id: projects[a].tasks[b].logs.length,
                                    startTime: new Date().getTime(),
                                    endTime: 0
                                };
                                projects[a].tasks[b].logs.push(logObj);

                                // update local storage
                                localStorage.setItem(this.key, JSON.stringify(projects));

                                // re-load all tasks
                                this.showAllTasks();
                            } else {

                                // reset dropdown
                                self.value = "";
                            }
                        });
                    } else if (self.value == "stop") {

                        // ask for confirmation
                        swal({
                            title: "Are you sure?",
                            text: "This will stop the timer.",
                            icon: "warning",
                            buttons: true,
                            dangerMode: true,
                        })
                        .then((doStop) => {
                            if (doStop) {

                                // mark as stopped
                                projects[a].tasks[b].isStarted = false;

                                // update end time in log
                                for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                                    if (projects[a].tasks[b].logs[c].endTime == 0) {
                                        projects[a].tasks[b].logs[c].endTime = new Date().getTime();
                                        break;
                                    }
                                }

                                // update local storage
                                localStorage.setItem(this.key, JSON.stringify(projects));

                                // re-load tasks
                                this.showAllTasks();
                            } else {

                                // reset dropdown
                                self.value = "";
                            }
                        });
                    }
                    break;
                }
            }
            break;
        }
    }

    // delete, start and stop are already handled above
    if (self.value == "delete"
        || self.value == "start"
        || self.value == "stop") {
        //
    } else {
        // update local storage and re-load tasks
        localStorage.setItem(this.key, JSON.stringify(projects));
        this.showAllTasks();
    }
},

Comments have been added with each line for an explanation. If you still find it difficult, please feel free to mention it in the comments section below.

At this point, you will be able to start and stop the timer. Upon stopping, you will be able to see the start and end time of the task along with the total duration of the task.

Now, we need to update the timer each second if the task is started. You need to write the following lines in your window “load” event listener:

// call this function each second
setInterval(function () {

    // increment 1 second in all running tasks
    var dataStarted = document.querySelectorAll("td[data-started]");
    for (var i = 0; i < dataStarted.length; i++) {
        var dataStartedObj = dataStarted[i].getAttribute("data-started");
        var dataStartedObj = JSON.parse(dataStartedObj);
        dataStartedObj.duration++;

        // convert timestamp into readable format
        var hours = Math.floor(dataStartedObj.duration / 3600) % 24;
        hours = (hours < 10) ? "0" + hours : hours;
        // var days = Math.floor(diff / 86400);
        var minutes = Math.floor(dataStartedObj.duration / 60) % 60;
        minutes = (minutes < 10) ? "0" + minutes : minutes;
        var seconds = dataStartedObj.duration % 60;
        seconds = (seconds < 10) ? "0" + seconds : seconds;
        dataStarted[i].innerHTML = hours + ":" + minutes + ":" + seconds;

        // update log end time
        var projects = taskObj.getAllProjects();
        for (var a = 0; a < projects.length; a++) {
            if (projects[a].id == dataStartedObj.project) {
                for (var b = 0; b < projects[a].tasks.length; b++) {
                    if (projects[a].tasks[b].id == dataStartedObj.task) {
                        for (var c = 0; c < projects[a].tasks[b].logs.length; c++) {
                            if (c == projects[a].tasks[b].logs.length - 1) {
                                projects[a].tasks[b].logs[c].endTime = new Date().getTime();

                                // update local storage
                                window.localStorage.setItem(taskObj.key, JSON.stringify(projects));

                                // update timer
                                dataStarted[i].setAttribute("data-started", JSON.stringify(dataStartedObj));

                                break;
                            }
                        }
                        break;
                    }
                }
                break;
            }
        }
    }
}, 1000);

For explanation, comments have been added. Feel free to ask if you are having trouble understanding something.

Delete project

You are now able to create projects, now is the time to have the ability to delete them. So create a simple form that displays a list of all created projects in a dropdown:

<!-- form to delete project -->
<form method="POST" onsubmit="return taskObj.deleteProject(this);" style="display: contents;">
    <select name="project" class="form-control" style="display: initial; width: 200px; margin-left: 5px; margin-right: 5px;" id="form-task-hour-calculator-all-projects"></select>
    <input type="submit" class="btn btn-danger" value="Delete Project">
</form>

Then we need to create a function “deleteProject” in our “taskObj” object that will delete the project from local storage and refresh the projects and tasks UI.

// delete project
deleteProject: function (self) {

    // check if any project is selected
    if (self.project.value == "") {
        swal("Please select a project to delete");
        return false;
    }

    // ask for confirmation
    swal({
        title: "Are you sure?",
        text: "Deleting the project will delete its tasks too.",
        icon: "warning",
        buttons: true,
        dangerMode: true,
    })
    .then((willDelete) => {
        if (willDelete) {

            // remove from array and update local storage
            var projects = taskObj.getAllProjects();
            for (var a = 0; a < projects.length; a++) {
                if (projects[a].id == self.project.value) {
                    projects.splice(a, 1);
                    localStorage.setItem(taskObj.key, JSON.stringify(projects));

                    // re-load data
                    taskObj.loadAllProjects();
                    taskObj.showAllTasks();

                    break;
                }
            }
        } else {

            // reset project dropdown
            self.project.value = "";
        }
    });
    return false;
}

Applying CSS Styles

This may not be the major concern for you, but just to highlight the task when it is started and when it is completed, we are applying some CSS styles to it.

/* style when project is started */
.started {
    color: white;
    font-weight: bold;
    background: green;
    padding: 5px;
    border-radius: 5px;
}

/* style when project is completed */
.completed {
    color: white;
    font-weight: bold;
    background: greenyellow;
    padding: 5px;
    border-radius: 5px;
}

Congratulations ! You just created your own task management and time tracking script in Javascript. Feel free to add more features in it as per your needs.

[wpdm_package id=’1219′]

PHP object as argument to Javascript function

Suppose you have a PHP variable or an object which you want to pass as an argument to a Javascript function whenever a button is clicked. Following this tutorial, you will be able to do so.

We will not be directly sending the PHP variable, but instead, we will attach the PHP variable to the HTML tag attribute and then send that tag to the Javascript function.

<?php
    $variable = "Adnan";

    $object = new \stdClass();
    $object->my_value = 2021;
?>

<button type="button"
    data-variable="<?php echo $variable; ?>"
    data-object="<?php echo htmlentities(json_encode($object)); ?>"
    onclick="buttonClicked(this);">Button</button>

<script>
    function buttonClicked(self) {
        var variable = self.getAttribute("data-variable");
        console.log(variable);

        var object = self.getAttribute("data-object");
        object = JSON.parse(object);
        console.log(object.my_value);
    }
</script>

When the button is clicked, we are sending a PHP object to the Javascript function as an argument. We are also sending a complete PHP object too. PHP objects can be sent by first converting them into JSON string format. You can learn more about the htmlentities function from PHP official documentation. Then we will convert the JSON string characters into HTML entities.

And on the Javascript side, we simply have to parse the JSON string back into a Javascript array or object. If you face any problems implementing this in your project, please let us know in the comments section.

You can also check our more tutorials on PHP.

[wpdm_package id=’1217′]

Count extended fingers – Leap Motion Controller + Javascript

In this tutorial, we are going to show you can count extended fingers of your hand using Leap and Javascript. Extended fingers mean your stretched or opened fingers. If you prefer a video tutorial, you can check our video tutorial on YouTube.

Leap Motion Controller is a device used to detect hand motions and gestures. It came with a software development kit (SDK) for different languages i.e. C++, C#, Python, Javascript, Java, Unity, and Unreal Engine. You can buy Leap Motion Controller from here. You can get all the languages SDK from this link.

Video tutorial

We are going to show different images based on extended fingers. If you have downloaded the Javascript SDK then you will find a file named “leap-0.6.4.min.js” in it. You need to copy that file in your project. We have created a folder named “images”. In this folder, we have placed 3 images named “1.jpg”, “2.jpg” and “3.jpg”.

We will be using “index.php” file as the main file. The following code will show images based on your hand’s extended fingers.

<script src="leap-0.6.4.min.js"></script>

<img id="image" style="display: none;" />

<script>
    // Setup Leap loop with frame callback function
    var controllerOptions = {};

    Leap.loop(controllerOptions, function(frame) {
        // Body of callback function
        var hands = frame.hands;
        if (hands.length > 0) {

            var hand = hands[0];

            var extendedFingers = 0;
            for(var f = 0; f < hand.fingers.length; f++){
                var finger = hand.fingers[f];
                if(finger.extended) {
                    extendedFingers++;
                }
            }

            if (extendedFingers > 0 && extendedFingers <= 3) {
                document.getElementById("image").setAttribute("src", "images/" + extendedFingers + ".jpg");
                document.getElementById("image").style.display = "";
            } else {
                document.getElementById("image").style.display = "none";
            }
        }
    });
</script>

<style>
    #image {
        width: 100%;
        height: 100%;
        object-fit: contain;
    }
</style>

Explanation

  1. First we have included Leap JS SDK.
  2. Then we created an empty image tag and hide it.
  3. Leap.loop function will be called on each frame.
  4. On each frame, we are checking if there is any hand on top of Leap.
  5. If there is, then we are counting extended fingers.
  6. If there are more than zero and less than 4 extended fingers, then we are rendering image and displaying it.
  7. Otherwise, we are hiding the image.
  8. CSS styles are applied to fit the image inside the browser window.

Move your hand on top of your Leap Motion Controller and try to extend your fingers one-by-one. You will see the images will be changed as per the number of fingers extended. That’s how you can count extended fingers on your hand in Leap Motion Controller.

Check out our more tutorials on Leap Motion Controller.

[wpdm_package id=’1213′]

Convert date format to another – PHP, HTML

In this tutorial, we are going to teach you how to convert the date format from one to another using Javascript. We will also be adding, subtracting date by days.

Video tutorial

First, we will create a form to get the source and destination format from the user.

<form method="POST" onsubmit="return generateCode(this);">
    
    <div>
        <select name="source_format">
            <option value="">Enter source format</option>
            <option value="timestamp">Timestamp (123456789)</option>
            <option value="Y-m-d">Y-m-d (2020-08-30)</option>
            <option value="Y-m-d H:i:s">Y-m-d H:i:s (2020-08-30 14:30:18)</option>
            <option value="Y-m-d h:i:s A">Y-m-d h:i:s A (2020-08-30 02:30:18 PM)</option>
            <option value="Y-m-d h:i:s a">Y-m-d h:i:s a (2020-08-30 02:30:18 pm)</option>
            <option value="d M, Y">d M, Y (30 August, 2020)</option>
            <option value="D">D (Mon, Tue)</option>
        </select>
    </div>

    <div style="margin-top: 10px;">
        <select name="destination_format">
            <option value="">Enter destination format</option>
            <option value="timestamp">Timestamp (123456789)</option>
            <option value="Y-m-d">Y-m-d (2020-08-30)</option>
            <option value="Y-m-d H:i:s">Y-m-d H:i:s (2020-08-30 14:30:18)</option>
            <option value="Y-m-d h:i:s A">Y-m-d h:i:s A (2020-08-30 02:30:18 PM)</option>
            <option value="Y-m-d h:i:s a">Y-m-d h:i:s a (2020-08-30 02:30:18 pm)</option>
            <option value="d M, Y">d M, Y (30 August, 2020)</option>
            <option value="D">D (Mon, Tue)</option>
        </select>
    </div>

    <input type="submit" value="Generate Code" />

    <p id="output" style="display: none;"></p>
</form>

Then we will create a Javascript function that will write the PHP code to echo the date by converting it from source format to destination format.

<script>
    function generateCode(form) {

        var sourceFormat = form.source_format.value;
        var destinationFormat = form.destination_format.value;

        var html = "";
        var dateHtml = "";
        if (sourceFormat == "timestamp" && destinationFormat == "timestamp") {
            dateHtml = `echo $timestamp_value;`;
        } else if (sourceFormat == "timestamp") {
            dateHtml = `echo date('` + destinationFormat + `', $timestamp_value);`;
        } else if (destinationFormat == "timestamp") {
            dateHtml = `echo strtotime($date_value);`;
        } else {
            dateHtml = `echo date('` + destinationFormat + `', strtotime($date_value));`;
        }
        html += `&lt;?php<br />
            <span style='margin-left: 1em;'>&emsp;` + dateHtml + `</span><br />
        ?>`;
        
        document.getElementById("output").innerHTML = html;
        document.getElementById("output").style.display = '';

        return false;
    }
</script>

The resulting output will be displayed in a paragraph. Right now we are displaying a dropdown to select a date format. But what if the user wants to write a custom format ? So we will create 2 more fields for writing custom format for source and destination.

<input type="text" style="margin-left: 10px;" name="source_format_custom" placeholder="Custom source format" />

<input type="text" style="margin-left: 10px;" name="destination_format_custom" placeholder="Custom destination format" />

Then we need to update our custom date format variables if these fields have some value.

var sourceFormat_custom = form.source_format_custom.value;
if (sourceFormat_custom != "") {
    sourceFormat = sourceFormat_custom;
}

var destinationFormat_custom = form.destination_format_custom.value;
if (destinationFormat_custom != "") {
    destinationFormat = destinationFormat_custom;
}

Add/subtract from the date

Now we need to add or subtract months, years, or days from the new date format. For this, we will create 2 dropdowns to check if the user wants to add or subtract. And second to check if he wants to add/subtract days, months, or years.

<p style="text-align: center;">Add / subtract date (optional)</p>

<div>
    <select name="addsubtract_date">
        <option value="">None</option>
        <option value="add">Add</option>
        <option value="subtract">Subtract</option>
    </select>

    <select name="addsubtract_datetype">
        <option value="years">Years</option>
        <option value="months">Months</option>
        <option value="days">Days</option>
        <option value="hours">Hours</option>
        <option value="minutes">Minutes</option>
        <option value="seconds">Seconds</option>
    </select>
</div>

<input type="number" placeholder="Enter value" name="addsubtract_datevalue" />

Now when the form is submitted, we need to get the values of both these dropdowns.

var addsubtractdate = "";
if (form.addsubtract_date.value == "add") {
    addsubtractdate = "'+ " + form.addsubtract_datevalue.value + " " + form.addsubtract_datetype.value + "'";
} else if (form.addsubtract_date.value == "subtract") {
    addsubtractdate = "'- " + form.addsubtract_datevalue.value + " " + form.addsubtract_datetype.value + "'";
}

After that, we need to make changes in every echo statement in our Javascript code to handle this add/subtract feature.

if (sourceFormat == "timestamp" && destinationFormat == "timestamp") {
    if (addsubtractdate == "") {
        dateHtml = `echo $timestamp_value;`;
    } else {
        dateHtml = `echo strtotime(` + addsubtractdate + `, $timestamp_value);`;
    }
} else if (sourceFormat == "timestamp") {
    if (addsubtractdate == "") {
        dateHtml = `echo date('` + destinationFormat + `', $timestamp_value);`;
    } else {
        dateHtml = `echo date('` + destinationFormat + `', strtotime(` + addsubtractdate + `, $timestamp_value));`;
    }
} else if (destinationFormat == "timestamp") {
    if (addsubtractdate == "") {
        dateHtml = `echo strtotime($date_value);`;
    } else {
        dateHtml = `echo strtotime(` + addsubtractdate + `, strtotime($date_value));`;
    }
} else {
    if (addsubtractdate == "") {
        dateHtml = `echo date('` + destinationFormat + `', strtotime($date_value));`;
    } else {
        dateHtml = `echo date('` + destinationFormat + `', strtotime($date_value . ` + addsubtractdate + `));`;
    }
}

You can run the script now, and you will be able to generate the code for converting the date from one format to another. Moreover, you can also get the code for adding/subtracting days, months, or years from the resultant date. That’s how you can convert date format from one to another.

Learn how to calculate the time passed since the date in PHP and Javascript.

Calculate time passed since date – Javascript, PHP

Feel free to download the source code below.

[wpdm_package id=’1183′]