Categories
React Projects

Create a Flashcard App with React and JavaScript

React is an easy to use JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a flashcard app with React and JavaScript.

Create the Project

We can create the React project with Create React App.

To install it, we run:

npx create-react-app flashcard

with NPM to create our React project.

We need the uuid to let us create unique IDs for our flashcard items easily.

To add it, we run:

npm i uuidv4

Create the Flashcard App

To create the flashcard app, we write:

import { useState } from "react";
import { v4 as uuidv4 } from "uuid";

export default function App() {
  const [item, setItem] = useState({});
  const [items, setItems] = useState([]);

  const add = (e) => {
    e.preventDefault();
    const { question, answer } = item;
    const formValid = question && answer;
    if (!formValid) {
      return;
    }
    setItems((items) => [
      ...items,
      {
        id: uuidv4(),
        ...item
      }
    ]);
  };

  const deleteItem = (index) => {
    setItems((items) => items.filter((_, i) => i !== index));
  };

  return (
    <div className="App">
      <form onSubmit={add}>
        <div>
          <label>question</label>
          <input
            value={item.question}
            onChange={(e) =>
              setItem((item) => ({ ...item, question: e.target.value }))
            }
          />
        </div>
        <div>
          <label>answer</label>
          <input
            value={item.answer}
            onChange={(e) =>
              setItem((item) => ({ ...item, answer: e.target.value }))
            }
          />
        </div>
        <button type="submit">submit</button>
      </form>
      {items.map((item, index) => {
        return (
          <div key={item.id}>
            <b>question</b>
            <p>{item.question}</p>
            <b>answer</b>
            <p>{item.answer}</p>
            <button onClick={() => deleteItem(index)}>delete</button>
          </div>
        );
      })}
    </div>
  );
}

We have the item and items state created with the useState hook.

Then we have the add function to add an item to items .

In the function, we call e.preventDefault() to do client-side form submission.

Then we check if question and answer is set.

If they are, then we call setItems to add an item to the items array with the callback.

The callback gets the existing items value and returns a new array with the new item appended to it.

The deleteItem function calls setItems with a callback that returns the items array without the entry with the given index .

In the form, we have the onSubmit prop set to add so that add runs when we click on the submit button.

The inputs have the value and onChange props so that we bind the inputted value to the properties.

We pass in a callback to setItem to set the properties to e.target.value , which has the inputted value.

Below that, we render the items into elements.

We need to set the key prop to a unique ID so that React can identify each entry.

It also has a button that calls deleteItem with index when we click on it.

Conclusion

We can create a flashcard app with React and JavaScript easily.

Categories
React Projects

Create a Budget Tracker App with React and JavaScript

React is an easy to use JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a budget tracker app with React and JavaScript.

Create the Project

We can create the React project with Create React App.

To install it, we run:

npx create-react-app budget-tracker

with NPM to create our React project.

We need the uuid to let us create unique IDs for our budget items easily.

To add it, we run:

npm i uuidv4

Create the Grocery List App

To create the grocery list app, we write:

import { useMemo, useState } from "react";
import { v4 as uuidv4 } from "uuid";

export default function App() {
  const [budget, setBudget] = useState("");
  const [expense, setExpense] = useState({});
  const [expenses, setExpenses] = useState([]);

  const add = (e) => {
    e.preventDefault();
    const { cost, description } = expense;
    const formValid = +budget > 0 && +cost > 0 && description;
    if (!formValid) {
      return;
    }
    setExpenses((ex) => [
      ...ex,
      {
        id: uuidv4(),
        ...expense
      }
    ]);
  };

  const remove = (index) => {
    setExpenses((expenses) => expenses.filter((_, i) => i !== index));
  };

  const remainingBudget = useMemo(() => {
    const totalExpenses = expenses
      .map(({ cost }) => +cost)
      .reduce((a, b) => +a + +b, 0);
    return budget - totalExpenses;
  }, [budget, expenses]);

  return (
    <div className="App">
      <div>
        <form>
          <fieldset>
            <label>budget</label>
            <input value={budget} onChange={(e) => setBudget(e.target.value)} />
          </fieldset>
        </form>

        <form onSubmit={add}>
          <h1>add expensse</h1>
          <fieldset>
            <label>description</label>
            <input
              value={expense.description}
              onChange={(e) =>
                setExpense((ex) => ({ ...ex, description: e.target.value }))
              }
            />
          </fieldset>

          <fieldset>
            <label>cost</label>
            <input
              value={expense.cost}
              onChange={(e) =>
                setExpense((ex) => ({ ...ex, cost: e.target.value }))
              }
            />
          </fieldset>
          <button type="submit">add expense</button>
        </form>

        <p>remaining budget: ${remainingBudget}</p>

        {expenses.map((ex, index) => {
          return (
            <div key={ex.id}>
              {ex.description} - ${ex.cost}
              <button onClick={() => remove(index)}>remove</button>
            </div>
          );
        })}
      </div>
    </div>
  );
}

We have the budget , expense , and expenses states.

budget has the budget number.

expense has the expense item.

expenses has the expense items.

Then add the add method that lets us add an expense item.

In it, we call e.preventDefault() to let us to client-side submission.

Then we check if the expense properties are valid with the formValid variable.

If it’s true , then we call setExpenses with a callback to return an expenses array with the new item appended to it.

In the remove method, we call setExpenses with a callback that returns the expenses array without the item with the given index .

Next, we add the remainingBudget state that we create with useMemo .

In the callback, we add up all the cost values from the expenses array together to get totalExpenses .

Then we subtract budget by totalExpenses.

We watch budget and expenses for changes as indicated by the array in the 2nd argument.

In the return statement, we have a form to let us enter the budget value.

In the 2nd form, we can enter values for the expense properties.

We set the value and onChange props so that we can set the properties.

To set a property value with the input, we use spread to spread the existing values in the return object, then we add the property we want to change set to e.target.value at the end.

Below that, we display the remainingBudget value.

And below that, we display the expenses items as divs.

The button inside calls remove with the index to remove an item when we click it.

Conclusion

We can create a simple budget app with React and JavaScript.

Categories
React Projects

Create a Budget Tracker App with React and JavaScript

React is an easy to use JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a budget tracker app with React and JavaScript.

Create the Project

We can create the React project with Create React App.

To install it, we run:

npx create-react-app budget-tracker

with NPM to create our React project.

We need the uuid to let us create unique IDs for our to-do items easily.

To add it, we run:

npm i uuidv4

Create the Grocery List App

To create the grocery list app, we write:

import { useMemo, useState } from "react";
import { v4 as uuidv4 } from "uuid";

export default function App() {
  const [budget, setBudget] = useState("");
  const [expense, setExpense] = useState({});
  const [expenses, setExpenses] = useState([]);

  const add = (e) => {
    e.preventDefault();
    const { cost, description } = expense;
    const formValid = +budget > 0 && +cost > 0 && description;
    if (!formValid) {
      return;
    }
    setExpenses((ex) => [
      ...ex,
      {
        id: uuidv4(),
        ...expense
      }
    ]);
  };

  const remove = (index) => {
    setExpenses((expenses) => expenses.filter((_, i) => i !== index));
  };

  const remainingBudget = useMemo(() => {
    const totalExpenses = expenses
      .map(({ cost }) => +cost)
      .reduce((a, b) => +a + +b, 0);
    return budget - totalExpenses;
  }, [budget, expenses]);

  return (
    <div className="App">
      <div>
        <form>
          <fieldset>
            <label>budget</label>
            <input value={budget} onChange={(e) => setBudget(e.target.value)} />
          </fieldset>
        </form>

        <form onSubmit={add}>
          <h1>add expensse</h1>
          <fieldset>
            <label>description</label>
            <input
              value={expense.description}
              onChange={(e) =>
                setExpense((ex) => ({ ...ex, description: e.target.value }))
              }
            />
          </fieldset>

          <fieldset>
            <label>cost</label>
            <input
              value={expense.cost}
              onChange={(e) =>
                setExpense((ex) => ({ ...ex, cost: e.target.value }))
              }
            />
          </fieldset>
          <button type="submit">add expense</button>
        </form>

        <p>remaining budget: ${remainingBudget}</p>

        {expenses.map((ex, index) => {
          return (
            <div key={ex.id}>
              {ex.description} - ${ex.cost}
              <button onClick={() => remove(index)}>remove</button>
            </div>
          );
        })}
      </div>
    </div>
  );
}

We have the budget , expense , and expenses states.

budget has the budget number.

expense has the expense item.

expenses has the expense items.

Then add the add method that lets us add an expense item.

In it, we call e.preventDefault() to let us to client-side submission.

Then we check if the expense properties are valid with the formValid variable.

If it’s true , then we call setExpenses with a callback to return an expenses array with the new item appended to it.

In the remove method, we call setExpenses with a callback that returns the expenses array without the item with the given index .

Next, we add the remainingBudget state that we create with useMemo .

In the callback, we add up all the cost values from the expenses array together to get totalExpenses .

Then we subtract budget by totalExpenses.

We watch budget and expenses for changes as indicated by the array in the 2nd argument.

In the return statement, we have a form to let us enter the budget value.

In the 2nd form, we can enter values for the expense properties.

We set the value and onChange props so that we can set the properties.

To set a property value with the input, we use spread to spread the existing values in the return object, then we add the property we want to change set to e.target.value at the end.

Below that, we display the remainingBudget value.

And below that, we display the expenses items as divs.

The button inside calls remove with the index to remove an item when we click it.

Conclusion

We can create a simple budget app with React and JavaScript.

Categories
React Projects

Create a Grocery List App with React and JavaScript

React is an easy to use JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a grocery list app with React and JavaScript.

Create the Project

We can create the React project with Create React App.

To install it, we run:

npx create-react-app grocery-list

with NPM to create our React project.

We need the uuid to let us create unique IDs for our to-do items easily.

To add it, we run:

npm i uuidv4

Create the Grocery List App

To create the grocery list app, we write:

import { useState } from "react";
import { v4 as uuidv4 } from "uuid";

export default function App() {
  const [item, setItem] = useState("");
  const [items, setItems] = useState([]);
  const add = (e) => {
    e.preventDefault();
    if (!item) {
      return;
    }
    setItems((items) => [
      ...items,
      {
        id: uuidv4(),
        item
      }
    ]);
  };

  const remove = (index) => {
    setItems((items) => items.filter((_, i) => i !== index));
  };

  return (
    <div className="App">
      <form onSubmit={add}>
        <fieldset>
          <label>item</label>
          <input value={item} onChange={(e) => setItem(e.target.value)} />
        </fieldset>
        <button type="submit">add item</button>
      </form>
      {items.map((item, index) => {
        return (
          <div key={item.id}>
            <p>{item.item}</p>
            <button onClick={() => remove(index)}>remove</button>
          </div>
        );
      })}
    </div>
  );
}

We have the item and items state created with the useState hook.

item has the item text.

items has the items array.

Then we add the add method which lets us add an item to the items array.

Inside it, we call e.preventDefault() to do client-side submission.

Then we check if item is set.

If it is, then we call setItems with a callback to return the items array with the new item added to the end.

The remove method calls setItems with a callback to return a items array without the item with the given index .

Then in the return statement, we have a form with the onSubmit prop that calls add .

An input element has the vbalue and onChange props to make it a controlled input.

We set the item value to e.target.value .

Then we render the items array into divs with the item.item text inside.

The button calls remove when we click it.

Conclusion

We can create a grocery list app easily with React and JavaScript.

Categories
Vue

Build a Drag and Drop App with Vue.js

Drag and drop is a feature of many interactive web apps. It provides an intuitive way for users to manipulate their data. Adding drag and drop feature is easy to add to Vue.js apps.

The App We Are Building

We will create a todo app that has 2 columns — a To Do column and a Done column. You can drag and drop between the two to change the status from to do to done and vice versa. To build the app, we use Vue Material library with the Vue Draggable package to make the app look good and provide the drag and drop ability easily. It will also have a navigation menu and a top bar.

Getting Started

To begin building the app, we start by installing Vue CLI. We install it by running npm i -g @vue/cli. After that, we can create the project. To do this, we run vue create todo-app. Instead of choosing the default, we customize the scaffolding of the app by choosing the alternative option and pick Vue Router, Babel, and CSS preprocessor. The scaffolding should be finished after following the instructions and then we are ready to add some libraries.

We need to add Axios for making HTTP requests, and the Vue Material library with the Vue Draggable packages we mentioned before to make our app prettier and to provide the drag and drop capabilities we desire respectively. In addition, we need the Vee Validate package to let us do form validation in our app. To install these packages, we run npm i axios vuedraggable vue-material vee-validate@2.2.14 .

Building the App

Now we can write some code. To start, we add a mixin to let us make our requests. To do this, we create a mixins folder and add a file called todoMixin.js, and we then put the following into our file:

const axios = require('axios');
const apiUrl = 'http://localhost:3000';

export const todoMixin = {
 methods: {
 getTodos() {
 return axios.get(`${apiUrl}/todos`);
 },

 addTodo(data) {
 return axios.post(`${apiUrl}/todos`, data);
 },

 editTodo(data) {
 return axios.put(`${apiUrl}/todos/${data.id}`, data);
 },

 deleteTodo(id) {
 return axios.delete(`${apiUrl}/todos/${id}`);
 }
 }
}

These functions will be used in our home page to make HTTP requests to do CRUD on our todo list. We will create the home page now. In Home.vue, we replace what we have with the following:

<template>
  <div class="home">
    <div class="center">
      <h1>To Do List</h1>
      <md-button class="md-raised" @click="showDialog = true"
        >Add Todo</md-button
      >
    </div>

    <div class="content">
      <md-dialog :md-active.sync="showDialog">
        <md-dialog-title>Add Todo</md-dialog-title>
        <form @submit="addNewTodo" novalidate>
          <md-field :class="{ 'md-invalid': errors.has('description') }">
            <label for="description">Description</label>
            <md-input
              type="text"
              name="description"
              v-model="taskData.description"
              v-validate="'required'"
            ></md-input>
            <span class="md-error" v-if="errors.has('description')">{{
              errors.first("description")
            }}</span>
          </md-field>

          <md-dialog-actions>
            <md-button class="md-primary" @click="showDialog = false"
              >Close</md-button
            >
            <md-button class="md-primary" @click="showDialog = false"
              >Save</md-button
            >
          </md-dialog-actions>
        </form>
      </md-dialog>
      <div class="lists">
        <div class="left">
          <h2>To Do</h2>
          <draggable v-model="todo" group="tasks" @change="updateTodo">
            <div v-for="t in todo" :key="t.id" class="item">
              {{ t.description }}
              <a @click="deleteTask(t.id)">
                <md-icon>close</md-icon>
              </a>
            </div>
          </draggable>
        </div>
        <div class="right">
          <h2>Done</h2>
          <draggable v-model="done" group="tasks" @change="updateTodo">
            <div v-for="d in done" :key="d.id" class="item">
              {{ d.description }}
              <a @click="deleteTask(d.id)">
                <md-icon>close</md-icon>
              </a>
            </div>
          </draggable>
        </div>
      </div>
    </div>
  </div>
</template>


<script>
// @ is an alias to /src
import draggable from "vuedraggable";
import { todoMixin } from "@/mixins/todoMixin";

export default {
  name: "home",
  components: {
    draggable,
  },
  computed: {
    isFormDirty() {
      return Object.keys(this.fields).some((key) => this.fields[key].dirty);
    },
  },
  mixins: [todoMixin],
  data() {
    return {
      todo: [],
      done: [],
      showDialog: false,
      taskData: {},
    };
  },
  beforeMount() {
    this.getNewTodos();
  },
  methods: {
    async addNewTodo(evt) {
      evt.preventDefault();
      if (!this.isFormDirty || this.errors.items.length > 0) {
        return;
      }
      await this.addTodo(this.taskData);
      this.showDialog = false;
      this.getNewTodos();
    },

    async getNewTodos() {
      const response = await this.getTodos();
      this.todo = response.data.filter((t) => !t.done);
      this.done = response.data.filter((t) => t.done);
    },

    async updateTodo(evt) {
      let todo = evt.removed && evt.removed.element;
      if (todo) {
        todo.done = !todo.done;
        await this.editTodo(todo);
      }
    },

    async deleteTask(id) {
      const todo = await this.deleteTodo(id);
      this.getNewTodos();
    },
  },
};
</script>

<style lang="scss" scoped>
.center {
  text-align: center;
}

.md-dialog {
  width: 70vw;
}

form {
  width: 92%;
}

.md-dialog-title.md-title {
  color: black !important;
}

.lists {
  padding-left: 5vw;
  display: flex;
  align-items: flex-start;
  .left,
  .right {
    width: 45vw;
    padding: 20px;
    min-height: 200px;
    .item {
      padding: 10px;
      border: 1px solid black;
      background-color: white;
      display: flex;
      justify-content: space-between;
      a {
        cursor: pointer;
      }
    }
  }
}
</style>

We added a dialog box with a form to enter the description for our task. The field is required but the user can enter anything. The addTodo function takes the data entered and submit it if it’s valid. The this.fields function is provided by the Vee Validate package and has all the fields in the object so we can check if the fields have been changed or not. Anything in the computed property is computer whenever anything returned by the function changes.

Next, we added 2 lists that we drag between to let us change the status of the tasks to done or not done. The lists are the draggable components on the template. We defined the models in the draggable components in the object returned by the data function. It is important that we have the same group prop so that we can drag between them the 2 draggable components. Whenever drag and drop happens, the change event is raised and the updateTodo function is called. The function will toggle the done flag of the task and make a request to save the task.

Each task also has a button to delete it. When the close button is clicked, the deleteTodo function is called. The id of the task is passed into the function, so we can make the request to delete the task.

Next in App.vue, we add the menu and a left-side navigation bar with the following code:

<template>
  <div id="app">
    <md-toolbar>
      <md-button class="md-icon-button" @click="showNavigation = true">
        <md-icon>menu</md-icon>
      </md-button>
      <h3 class="md-title">Todo App</h3>
    </md-toolbar>
    <md-drawer :md-active.sync="showNavigation" md-swipeable>
      <md-toolbar class="md-transparent" md-elevation="0">
        <span class="md-title">Todo App</span>
      </md-toolbar>

      <md-list>
        <md-list-item>
          <router-link to="/">
            <span class="md-list-item-text">Home</span>
          </router-link>
        </md-list-item>
      </md-list>
    </md-drawer>

    <router-view />
  </div>
</template>

<script>
export default {
  name: "app",
  data: () => {
    return {
      showNavigation: false,
    };
  },
};
</script>

<style>
.center {
  text-align: center;
}

form {
  width: 95vw;
  margin: 0 auto;
}

.md-toolbar.md-theme-default {
  background: #009688 !important;
  height: 60px;
}

.md-title,
.md-toolbar.md-theme-default .md-icon {
  color: #fff !important;
}
</style>

The <router-view /> displays the routes that we will define in router.js, which only consists of the home page.

In main.js,we put:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import VueMaterial from 'vue-material';
import VeeValidate from 'vee-validate';
import 'vue-material/dist/vue-material.min.css'
import 'vue-material/dist/theme/default.css'

Vue.config.productionTip = false;

Vue.use(VueMaterial);
Vue.use(VeeValidate);

new Vue({
 router,
 store,
 render: h => h(App)
}).$mount('#app')

to include the Vue.js add-on libraries that we use in this app.

And in router.js, we add:

import Vue from "vue";
import Router from "vue-router";
import Home from "./views/Home.vue";

Vue.use(Router);

export default new Router({
  mode: "history",
  base: process.env.BASE_URL,
  routes: [
    {
      path: "/",
      name: "home",
      component: Home
    }
  ]
});

This adds the home page to our list of routes so that it will be displayed to the user when typing in the URL or clicking a link to the page.

Our JSON API will be added without writing any code by using the JSON Server Node.js package, located at https://github.com/typicode/json-server. Data will be saved to a JSON file, so we don’t have to make our own back end add to save some simple data. We install the server by running npm i -g json-server. Then once that is done, go into our project directory then run json-server --watch db.json. In db.json, we put:

{
 "todos": []
}

so that we can use those endpoints for saving data to db.json, which have the same URLs as in todoMixin.

After all the work is done we have the following: