Nigel  Uys

Nigel Uys

1668750200

How to Automatically Retrying Failed Celery Tasks

In this article, we'll look at how to automatically retry failed Celery tasks.

Objectives

After reading, you should be able to:

  1. Retry a failed Celery task with both the retry method and a decorator argument
  2. Use exponential backoff when retrying a failed task
  3. Use a class-based task to reuse retry arguments

Celery Task

You can find the source code for this article on GitHub.

Let's assume we have a Celery task like this:

@shared_task
def task_process_notification():
    if not random.choice([0, 1]):
        # mimic random error
        raise Exception()

    requests.post('https://httpbin.org/delay/5')

In the real world this may call an internal or external third-party service. Regardless of the service, assume it's very unreliable, especially at peak periods. How can we handle failures?

It's worth noting that many Celery beginners get confused as to why some articles use app.task while others use shared_task. Well, shared_task lets you define Celery tasks without having to import the Celery instance, so it can make your task code more reusable.

Solution 1: Use a Try/Except Block

We can use a try/except block to catch the exception and raise retry:

@shared_task(bind=True)
def task_process_notification(self):
    try:
        if not random.choice([0, 1]):
            # mimic random error
            raise Exception()

        requests.post('https://httpbin.org/delay/5')
    except Exception as e:
        logger.error('exception raised, it would be retry after 5 seconds')
        raise self.retry(exc=e, countdown=5)

Notes:

  1. Since we set bind to True, this is a bound task, so the first argument to the task will always be the current task instance (self). Because of this, we can call self.retry to retry the failed task.
  2. Please remember to raise the exception returned by the self.retry method to make it work.
  3. By setting the countdown argument to 5, the task will retry after a 5 second delay.

Let's run the code below in the Python shell:

>>> from polls.tasks import task_process_notification
>>> task_process_notification.delay()

You should see output like this in your Celery worker terminal output:

Task polls.tasks.task_process_notification[06e1f985-90d4-4453-9870-fab57c5885c4] retry: Retry in 5s: Exception()
Task polls.tasks.task_process_notification[06e1f985-90d4-4453-9870-fab57c5885c4] retry: Retry in 5s: Exception()
Task polls.tasks.task_process_notification[06e1f985-90d4-4453-9870-fab57c5885c4] succeeded in 3.3638455480104312s: None

As you can see, the Celery task failed twice and succeeded the third time.

Solution 2: Task Retry Decorator

Celery 4.0 added built-in support for retrying, so you can let the exception bubble up and specify in the decorator how to handle it:

@shared_task(bind=True, autoretry_for=(Exception,), retry_kwargs={'max_retries': 7, 'countdown': 5})
def task_process_notification(self):
    if not random.choice([0, 1]):
        # mimic random error
        raise Exception()

    requests.post('https://httpbin.org/delay/5')

Notes:

  1. autoretry_for takes a list/tuple of exception types that you'd like to retry for.
  2. retry_kwargs takes a dictionary of additional options for specifying how autoretries are executed. In the above example, the task will retry after a 5 second delay (via countdown) and it allows for a maximum of 7 retry attempts (via max_retries). Celery will stop retrying after 7 failed attempts and raise an exception.

Exponential Backoff

If your Celery task needs to send a request to a third-party service, it's a good idea to use exponential backoff to avoid overwhelming the service.

Celery supports this by default:

@shared_task(bind=True, autoretry_for=(Exception,), retry_backoff=True, retry_kwargs={'max_retries': 5})
def task_process_notification(self):
    if not random.choice([0, 1]):
        # mimic random error
        raise Exception()

    requests.post('https://httpbin.org/delay/5')

In this example, the first retry should run after 1s, the following after 2s, the third one after 4s, the fourth after 8s, and so forth:

[02:09:59,014: INFO/ForkPoolWorker-8] Task polls.tasks.task_process_notification[fbe041b6-e6c1-453d-9cc9-cb99236df6ff] retry: Retry in 1s: Exception()
[02:10:00,210: INFO/ForkPoolWorker-2] Task polls.tasks.task_process_notification[fbe041b6-e6c1-453d-9cc9-cb99236df6ff] retry: Retry in 2s: Exception()
[02:10:02,291: INFO/ForkPoolWorker-4] Task polls.tasks.task_process_notification[fbe041b6-e6c1-453d-9cc9-cb99236df6ff] retry: Retry in 4s: Exception()

You can also set retry_backoff to a number for use as a delay factor:

@shared_task(bind=True, autoretry_for=(Exception,), retry_backoff=5, retry_kwargs={'max_retries': 5})
def task_process_notification(self):
    if not random.choice([0, 1]):
        # mimic random error
        raise Exception()

    requests.post('https://httpbin.org/delay/5')

Example:

[02:21:45,887: INFO/ForkPoolWorker-8] Task polls.tasks.task_process_notification[6a0b2682-74f5-410b-af1e-352069238f3d] retry: Retry in 5s: Exception()
[02:21:55,170: INFO/ForkPoolWorker-2] Task polls.tasks.task_process_notification[6a0b2682-74f5-410b-af1e-352069238f3d] retry: Retry in 10s: Exception()
[02:22:15,706: INFO/ForkPoolWorker-4] Task polls.tasks.task_process_notification[6a0b2682-74f5-410b-af1e-352069238f3d] retry: Retry in 20s: Exception()
[02:22:55,450: INFO/ForkPoolWorker-6] Task polls.tasks.task_process_notification[6a0b2682-74f5-410b-af1e-352069238f3d] retry: Retry in 40s: Exception()

By default, the exponential backoff will also introduce random jitter to avoid having all the tasks run at the same moment.

Randomness

When you build a custom retry strategy for your Celery task (which needs to send a request to another service), you should add some randomness to the delay calculation to prevent all tasks from being executed simultaneously resulting in a thundering herd.

Celery has you covered here as well with retry_jitter:

@shared_task(bind=True, autoretry_for=(Exception,), retry_backoff=5, retry_jitter=True, retry_kwargs={'max_retries': 5})
def task_process_notification(self):
    if not random.choice([0, 1]):
        # mimic random error
        raise Exception()

    requests.post('https://httpbin.org/delay/5')

This option is set to True by default, which helps prevent the thundering herd problem when you use Celery's built-in retry_backoff.

Task Base Class

If you find yourself writing the same retry arguments in your Celery task decorators, you can (as of Celery 4.4) define retry arguments in a base class, which you can then use as a base class in your Celery tasks:

class BaseTaskWithRetry(celery.Task):
    autoretry_for = (Exception, KeyError)
    retry_kwargs = {'max_retries': 5}
    retry_backoff = True


@shared_task(bind=True, base=BaseTaskWithRetry)
def task_process_notification(self):
    raise Exception()

So if you run the task in the Python shell, you would see the following:

[03:12:29,002: INFO/ForkPoolWorker-8] Task polls.tasks.task_process_notification[3231ef9b-00c7-4ab1-bf0b-2fdea6fa8348] retry: Retry in 1s: Exception()
[03:12:30,445: INFO/ForkPoolWorker-8] Task polls.tasks.task_process_notification[3231ef9b-00c7-4ab1-bf0b-2fdea6fa8348] retry: Retry in 2s: Exception()
[03:12:33,080: INFO/ForkPoolWorker-8] Task polls.tasks.task_process_notification[3231ef9b-00c7-4ab1-bf0b-2fdea6fa8348] retry: Retry in 3s: Exception()

Conclusion

In this Celery article, we looked at how to automatically retry failed celery tasks.

Again, the source code for this article can be found on GitHub.

Thanks for your reading. If you have any questions, please feel free to contact me.

Django + Celery Series:

  1. Asynchronous Tasks with Django and Celery
  2. Handling Periodic Tasks in Django with Celery and Docker
  3. Automatically Retrying Failed Celery Tasks (this article!)
  4. Working with Celery and Database Transactions

Original article source at: https://testdriven.io/

#django #celery 

What is GEEK

Buddha Community

How to Automatically Retrying Failed Celery Tasks

Jupyter Notebook Kernel for Running ansible Tasks and Playbooks

Ansible Jupyter Kernel

Example Jupyter Usage

The Ansible Jupyter Kernel adds a kernel backend for Jupyter to interface directly with Ansible and construct plays and tasks and execute them on the fly.

Demo

Demo

Installation:

ansible-kernel is available to be installed from pypi but you can also install it locally. The setup package itself will register the kernel with Jupyter automatically.

From pypi

pip install ansible-kernel
python -m ansible_kernel.install

From a local checkout

pip install -e .
python -m ansible_kernel.install

For Anaconda/Miniconda

pip install ansible-kernel
python -m ansible_kernel.install --sys-prefix

Usage

Local install

    jupyter notebook
    # In the notebook interface, select Ansible from the 'New' menu

Container

docker run -p 8888:8888 benthomasson/ansible-jupyter-kernel

Then copy the URL from the output into your browser:
http://localhost:8888/?token=ABCD1234

Using the Cells

Normally Ansible brings together various components in different files and locations to launch a playbook and performs automation tasks. For this jupyter interface you need to provide this information in cells by denoting what the cell contains and then finally writing your tasks that will make use of them. There are Examples available to help you, in this section we'll go over the currently supported cell types.

In order to denote what the cell contains you should prefix it with a pound/hash symbol (#) and the type as listed here as the first line as shown in the examples below.

#inventory

The inventory that your tasks will use

#inventory
[all]
ahost ansible_connection=local
anotherhost examplevar=val

#play

This represents the opening block of a typical Ansible play

#play
name: Hello World
hosts: all
gather_facts: false

#task

This is the default cell type if no type is given for the first line

#task
debug:
#task
shell: cat /tmp/afile
register: output

#host_vars

This takes an argument that represents the hostname. Variables defined in this file will be available in the tasks for that host.

#host_vars Host1
hostname: host1

#group_vars

This takes an argument that represents the group name. Variables defined in this file will be available in the tasks for hosts in that group.

#group_vars BranchOfficeX
gateway: 192.168.1.254

#vars

This takes an argument that represents the filename for use in later cells

#vars example_vars
message: hello vars
#play
name: hello world
hosts: localhost
gather_facts: false
vars_files:
    - example_vars

#template

This takes an argument in order to create a templated file that can be used in later cells

#template hello.j2
{{ message }}
#task
template:
    src: hello.j2
    dest: /tmp/hello

#ansible.cfg

Provides overrides typically found in ansible.cfg

#ansible.cfg
[defaults]
host_key_checking=False

Examples

You can find various example notebooks in the repository

Using the development environment

It's possible to use whatever python development process you feel comfortable with. The repository itself includes mechanisms for using pipenv

pipenv install
...
pipenv shell

Author: ansible
Source Code:  https://github.com/ansible/ansible-jupyter-kernel
License: Apache-2.0 License

#jupyter #python 

Why is my Cash App Transfer Failed [Solution 2021]?

Why is my Cash App Transfer Failed [Solution 2021]? yes sure you can use this app for online Payment Transfer, Call @+1 (855)698 5775 If you are facing any issues related with cash app transfer then you can contact on this number, If you are having trouble making any transfer on Cash App and your payment fails on Cash App then you need to first check if your Cash App is updated on your mobile or not. If not, then update the app to the latest version to make payments smoothly.Cash App transfers are almost always instantaneous. However, there are occasions when the app throws an exception, asking you to wait a little longer — aka 'Payment Pending. ’ It simply means the transfer has been initiated but cannot be fulfilled instantly

My Cash App Transfer Failed For My Protection

Cash App may fail your transaction to protect you from any fraud. Cash App monitors your account and if any suspicious activity takes place, it fails the transaction for your protection. This happens in order to save you from any scam and lose your money.

### Why would cash APP decline a payment for my protection?

Payments on Cash App with the error “failed for my Protection” may be declined for a few reasons. Some of the most common reasons include: Your bank or card issuer is declining the transaction, Incorrect details and the payment has triggered one of Cash App automated security flags.

How do I enable direct deposit on a cash App?

How do I enable direct deposit on a cash App? After successful activation, the employer will be able to pay your paycheck directly into your Cash App account. Follow these steps. Firstly, open the Cash App and click on the profile icon or Balance tab-present in the updated version of Cash App. After that, now navigate down to get the option “Direct Deposit”.

Relaated articles :- Why is my Cash App direct deposit failed ?

Why Cash App Transfer Failed For My Protection

How to Fix Cash App Payments for my protection? If you’re having trouble sending payment, make sure to check if you have added your correct credit or debit card to the Cash App, the best thing to do is double-check or reach out to your card issuer to confirm that there are no issues. If you’re waiting to receive more than $10,000 via direct deposit, your best bet is to request that the sender split the payment into two parts …

How to Fix Cash App Transfer Failed Earlier?

Cash App transfer failed for your security means that the transaction you are trying to make went unsuccessful. It might be any kind of transfer such as bank transfer, online or offline payment, cash withdrawal at an ATM and sending or receiving money to and from contacts.

### How do I fix my cash APP failed for my protection?

If you have got the Cash app Transfer failed error, then you have the option to raise a dispute for an unapproved transaction since you are a bank account holder. It is your right to dispute the unauthorized deductions made by the App

### How to Fix Cash App Transfer Failed ?

Cash app has witnessed considerable growth, with more than 30 million users. It is widely used in the US in order to make payments or transfer money to family and friends. The platform processes millions and millions of transactions on a daily basis. But this percentage is observed to have a huge drop due to Cash App transfer failed issues. About 10% of the total transactions are failing almost daily due to different reasons.
If you are having a similar sort of problem where the Cash App transaction failed, this article might be a useful one for you. It tells about the causes of the Cash app transfer failed error and mentions a few fixes that work for most of the causes as well. Hence, if you are encountering the same problem, read through this article to find your possible fix.

### Major Causes Behind Cash App Transfer Failed

  1. Improper internet connection
  2. Insufficient account balance
  3. Bank account fraud block
  4. Transaction blocked by Cash App

### How to Fix Cash App Transfer Failed

  1. Check a bank balance
  2. Using other bank accounts or cards
  3. Verifying the bank account details
  4. Contacting Cash app support team
  5. Contacting bank

### Major Causes Behind Cash App Transfer Failed

Although the number of causes behind a Cash app seems to be quite high, some of the key reasons are as mentioned:

Improper internet connection

Since all your transactions take place online, it requires a strong internet connection. Therefore, whenever you encounter a payment failure issue, the first thing is to check for your internet connectivity. For more efficient results, it is always better to connect your device to reliable Wi-Fi, if available.

Insufficient account balance

It happens quite often when users try to make a possible transaction without checking their account balance. If in case you don’t have enough amount in your cash app wallet or bank account, your transaction will fail.

Bank account fraud block

Whether you are having your account with Bank of America, PNC, or wherever, all these banks probably have their own fraud departments. These departments flag certain services as scams/ frauds. And since there are already a lot of scams operated on the Cash app these days, it adds up as a considerable reason for them to block transactions.

Transaction blocked by Cash App

Cash app has now grown into a billion-dollar company with around 30+ million users. Therefore, in order to maintain the security and privacy of its users, the Cash app has strict policies. So, if due to some reason, the application might have flagged the other person’s account as potential scam/ fraud, it might again cause a Cash app transfer failure.
These were some of the possible causes of Cash app transfer failed. However, most times, the following solutions might do a pretty good job of resolving your issues.

How do I fix my cash APP failed for my protection??

Since the whole thing is about transactions, there could be a bunch of other causes behind a failed transfer. These are just some basic fixes that actually work in most of the above-mentioned causes.

Related articles- How To Cash App Direct Deposit Failed ?SOlution | tranter-it

Check a bank balance

If your account balance is low in the case of the Cash app, it will eventually result in a failed transaction. However, to avoid such messages, it is a wise habit to always check your account balance or Cash app wallet balance before making a transfer.

Related article :- What happens when the cash app direct deposit failed? How to fix it?

Using other bank accounts or cards

Another primary reason behind encountering failed transactions is because of using blocked or rejected cards. Cash app often displays this error message basically due to server issues of the bank. To avoid such errors, you can try using a different credit/ debit card or bank account.

Verifying the bank account details

This is a very common mistake done by most users. Entering the wrong bank details will definitely lead to an cash app unsuccessful or failed transfer. Therefore, it is a good practice to be a little extra careful while entering such sensitive data.

Contacting Cash app support team

The Cash app might sometimes block your transactions, or it might flag the other person’s account as possible fraud in rare cases. In such situations, the wisest option is to contact the cash app’s support team and ask for assistance regarding the issue you are facing.

Contacting bank

If the bank itself terminates the transaction, contact your bank and ask for what reason the Cash app transfer failed through their system. They will inform you in case there are any serious issues and also advise the best way to overcome it.

Why is cash App declining my payment for my protection?

Cash App monitors your account for anything that looks out of the ordinary. If a potentially fraudulent payment occurs, we cancel it to prevent you from being charged. When this happens, your funds will instantly be returned to your Cash App balance or linked bank account.

Why does my Cash app keep saying Transfer failed?

Why does my Cash app keep saying Transfer failed?The reason why transfer fail every time can be because of the card which is updated on the account has expired or the details of the card are not correct. So, always you need to make sure that the card which is you are using is not expired and the details are correct.

##What does it mean when a cash app payment failed?

Cash App transfer failed for your security means that the transaction you are trying to make went unsuccessful. It might be any kind of transfer such as bank transfer, online or offline payment, cash withdrawal at ATM and sending or receiving money to and from contacts.

###Conclusion

Cash app has now grown quite popular with millions of users trusting its service. And undoubtedly, the application offers a great platform for easy transfer of money along with its other services. However, a lot of scams have already been reported regarding this application. So, if anyhow you face some sort of trouble and encounter the Cash app transfer failure, these tricks must help you find a way to resolve the problem and make efficient money transfer over the app. Let us know if this article helps you or if we missed out on something.

Bottom Link :-

cash app transfer failed | cash app this transfer failed | how do i fix my cash app failed for my protection why does cash app say transfer failed | trying to add cash to cash app transfer failed | cash app transfer failed add cash | how to fix cash app transfer failed | cash app transfer failed 2020 | how to fix cash app failed for my protection | why is my cash app saying transfer failed | cash app transfer failed for my protection | why is my cash app transfer failing | why is transfer failing on cash app | how to fix transfer failed on cash app | why cash app transfer failed | why does my cash app transfer keep failing | cash app transfer failed fix | what does transfer failed mean on cash app | cash app money transfer failed | what does it mean | when cash app failed for my protection | why is my transfer failed cash app cash app transfer failed 2021 | what does transfer failed on cash app mean | why did cash app transfer fail | why do cash app keep saying transfer failed | when cash app says transfer failed | my cash app keeps saying transfer failed | cash app transfer has failed | transfer failed message on cash app | why is cash app transfer failing
0

#cash app transfer failed #how to fix transfer failed on cash app #cash app transfer failed for my protection #why is my cash app transfer failing #cash app transfer failed 2021 #cash app this transfer failed

Learn CRUD Operations in JavaScript by Building TODO APP

Today we're gonna learn how to do CRUD Operations in JavaScript by making a Todo App. Let's get started 🔥

This is the app we're making today:

App that we're making today

What is CRUD?

Image description

CRUD stands for -

  • C: Create
  • R: Read
  • U: Update
  • D: Delete

CRUD Fullform

CRUD is a type of mechanism that allows you to create data, read data, edit it, and delete those data. In our case, we're gonna make a Todo app, so we will have 4 options to create tasks, read tasks, update tasks, or delete tasks.

Understanding CRUD Principles

Before starting the tutorial, first, let's understand the CRUD principles. For that, let's create a very very simple Social Media Application.

Social Media App Project

Setup

Project Setup

For this project, we will be following these steps below:

  • Create 3 files named index.html, style.css, and main.js
  • Link the JavaScript and CSS file to index.html
  • Start your live server

HTML

Inside the body tag, create a div with a class name .container. There, we will have 2 sections, .left and .right 👇

<body>
  <h1>Social Media App</h1>
  <div class="container">

    <div class="left"></div>
    <div class="right"></div>

  </div>
</body>

On the left side, we will create our posts. On the right side, we can see, update, and delete our posts. Now, create a form inside the .left div tag 👇

<div class="left">
  <form id="form">
    <label for="post"> Write your post here</label>
    <br><br>
    <textarea name="post" id="input" cols="30" rows="10"></textarea>
    <br> <br>
    <div id="msg"></div>
    <button type="submit">Post</button>
  </form>
</div>

Write this code inside the HTML so that we can display our post on the right side 👇

<div class="right">
  <h3>Your posts here</h3>
  <div id="posts"></div>
</div>

Next, we'll insert the font-awesome CDN inside the head tag to use its fonts in our project 👇

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

Now, we're gonna make some sample posts with delete and edit icons. Write this code inside the div with the id #posts: 👇

<div id="posts">
  <div>
    <p>Hello world post 1</p>
    <span class="options">
      <i class="fas fa-edit"></i>
      <i class="fas fa-trash-alt"></i>
    </span>
  </div>

  <div >
    <p>Hello world post 2</p>
    <span class="options">
      <i class="fas fa-edit"></i>
      <i class="fas fa-trash-alt"></i>
    </span>
  </div>
</div>

The result so far looks like this:

HTML Markup result

CSS

Adding CSS for project 1

Let's keep it simple. Write these styles inside your stylesheet: 👇

body {
  font-family: sans-serif;
  margin: 0 50px;
}

.container {
  display: flex;
  gap: 50px;
}

#posts {
  width: 400px;
}

i {
  cursor: pointer;
}

Now, write these styles for the post div and option icons: 👇

#posts div {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.options {
  display: flex;
  gap: 25px;
}

#msg {
  color: red;
}

The results so far look like this:👇

The result after adding the css part project 1

JavaScript Part

Starting the javascript part

According to this flow chart, we will go forward with the project. Don't worry, I'll explain everything along the way. 👇

flow chart

Form Validation

First, let's target all the ID selectors from the HTML in JavaScript. Like this: 👇

let form = document.getElementById("form");
let input = document.getElementById("input");
let msg = document.getElementById("msg");
let posts = document.getElementById("posts");

Then, build a submit event listener for the form so that it can prevent the default behaviour of our App. At the same time, we will create a function named formValidation. 👇

form.addEventListener("submit", (e) => {
  e.preventDefault();
  console.log("button clicked");

  formValidation();
});

let formValidation = () => {};

Now, we're gonna make an if else statement inside our formValidation function. This will help us prevent users from submitting blank input fields. 👇

let formValidation = () => {
  if (input.value === "") {
    msg.innerHTML = "Post cannot be blank";
    console.log("failure");
  } else {
    console.log("successs");
    msg.innerHTML = "";
  }
};

Here's the result so far: 👇

7sb8faq21j5dzy9vlswj

As you can see, a message will also show up if the user tries to submit the form blank.

How to accept data from input fields

Whatever data we get from the input fields, we will store them in an object. Let's create an object named data. And, create a function named acceptData: 👇

let data = {};

let acceptData = () => {};

The main idea is that, using the function, we collect data from the inputs and store them in our object named data. Now let's finish building our acceptData function.

let acceptData = () => {
  data["text"] = input.value;
  console.log(data);
};

Also, we need the acceptData function to work when the user clicks the submit button. For that, we will fire this function in the else statement of our formValidation function. 👇

let formValidation = () => {
  if (input.value === "") {
    // Other codes are here
  } else {
    // Other codes are here
    acceptData();
  }
};

When we input data and submit the form, on the console we can see an object holding our user's input values. Like this: 👇

result so far on the console

How to create posts using JavaScript template literals

In order to post our input data on the right side, we need to create a div element and append it to the posts div. First, let's create a function and write these lines: 👇

let createPost = () => {
  posts.innerHTML += ``;
};

The backticks are template literals. It will work as a template for us. Here, we need 3 things: a parent div, the input itself, and the options div which carries the edit and delete icons. Let's finish our function 👇

let createPost = () => {
  posts.innerHTML += `
  <div>
    <p>${data.text}</p>
    <span class="options">
      <i onClick="editPost(this)" class="fas fa-edit"></i>
      <i onClick="deletePost(this)" class="fas fa-trash-alt"></i>
    </span>
  </div>
  `;
  input.value = "";
};

In our acceptdata function, we will fire our createPost function. Like this: 👇

let acceptData = () => {
  // Other codes are here

  createPost();
};

The result so far: 👇

Result so far

So far so good guys, we're almost done with project 1.

so far so good

How to delete a post

In order to delete a post, first of all, let's create a function inside our javascript file:

let deletePost = (e) => {};

Next up, we fire this deletePost function inside all of our delete icons using an onClick attribute. You'll write these lines in HTML and on the template literal. 👇

<i onClick="deletePost(this)" class="fas fa-trash-alt"></i>

The this keyword will refer to the element that fired the event. in our case, the this refers to the delete button.

Look carefully, the parent of the delete button is the span with class name options. The parent of the span is the div. So, we write parentElement twice so that we can jump from the delete icon to the div and target it directly to remove it.

Let's finish our function. 👇

let deletePost = (e) => {
  e.parentElement.parentElement.remove();
};

The result so far: 👇

deleting a post result

How to edit a post

In order to edit a post, first of all, let's create a function inside our JavaScript file:

let editPost = (e) => {};

Next up, we fire this editPost function inside all of our edit icons using an onClick attribute. You'll write these lines in HTML and on the template literal. 👇

<i onClick="editPost(this)" class="fas fa-edit"></i>

The this keyword will refer to the element that fired the event. In our case, the this refers to the edit button.

Look carefully, the parent of the edit button is the span with class name options. The parent of the span is the div. So, we write parentElement twice so that we can jump from the edit icon to the div and target it directly to remove it.

Then, whatever data is inside the post, we bring it back on the input field to edit it.

Let's finish our function. 👇

let editPost = (e) => {
  input.value = e.parentElement.previousElementSibling.innerHTML;
  e.parentElement.parentElement.remove();
};

The result so far: 👇

Editing a post result

Take a Break!

Take a Break

Congratulations everyone for completing project 1. Now, take a small break!

How to Make a To-Do App using CRUD Operations

Let's make a todo app

Let's start making project 2, which is a To-Do App.

Project Setup

Project setup

For this project, we will be following these steps below:

  • Create 3 files named index.html, style.css, and main.js
  • Link the JavaScript and CSS files to index.html
  • Start our live server

HTML

Write this starter code inside the HTML file: 👇

<div class="app">
  <h4 class="mb-3">TODO App</h4>

  <div id="addNew" data-bs-toggle="modal" data-bs-target="#form">
    <span>Add New Task</span>
    <i class="fas fa-plus"></i>
  </div>
</div>

The div with an id addNew is the button that will open the modal. The span will be displayed on the button. The i is the icon from font-awesome.

We're going to use bootstrap to make our modal. We'll use the modal to add new tasks. For that, add the bootstrap CDN link inside the head tag. 👇

<link
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
  rel="stylesheet"
  integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
  crossorigin="anonymous"
/>

<script
  src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
  integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
  crossorigin="anonymous"
></script>

To see the created tasks, we'll use a div with an id tasks, inside the div with the classname app. 👇

<h5 class="text-center my-3">Tasks</h5>

<div id="tasks"></div>

Insert the font-awesome CDN inside the head tag to use fonts in our project 👇

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

Copy and paste the code below which are from the bootstrap modal. It carries a form with 3 input fields and a submit button. If you want then you can search Bootstrap's website by writing 'modal' in the search bar.

<!-- Modal -->
<form
  class="modal fade"
  id="form"
  tabindex="-1"
  aria-labelledby="exampleModalLabel"
  aria-hidden="true"
>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Add New Task</h5>
        <button
          type="button"
          class="btn-close"
          data-bs-dismiss="modal"
          aria-label="Close"
        ></button>
      </div>
      <div class="modal-body">
        <p>Task Title</p>
        <input type="text" class="form-control" name="" id="textInput" />
        <div id="msg"></div>
        <br />
        <p>Due Date</p>
        <input type="date" class="form-control" name="" id="dateInput" />
        <br />
        <p>Description</p>
        <textarea
          name=""
          class="form-control"
          id="textarea"
          cols="30"
          rows="5"
        ></textarea>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
          Close
        </button>
        <button type="submit" id="add" class="btn btn-primary">Add</button>
      </div>
    </div>
  </div>
</form>

The result so far: 👇

Html file setup

We're done with the HTML file setup. Let's start the CSS.

CSS

Adding the css part

Add these styles in the body so that we can keep our app at the exact center of the screen.

body {
  font-family: sans-serif;
  margin: 0 50px;
  background-color: #e5e5e5;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

Let's style the div with the classname app. 👇

.app {
  background-color: #fff;
  width: 300px;
  height: 500px;
  border: 5px solid #abcea1;
  border-radius: 8px;
  padding: 15px;
}

The result so far: 👇

App styles

Now, let's style the button with the id addNew. 👇

#addNew {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: rgba(171, 206, 161, 0.35);
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
}
.fa-plus {
  background-color: #abcea1;
  padding: 3px;
  border-radius: 3px;
}

The result so far: 👇

Add new task Button

If you click on the button, the modal pops up like this: 👇

Modal poping

Add the JS

Adding the JavaScript

In the JavaScript file, first of all, select all the selectors from the HTML that we need to use. 👇

let form = document.getElementById("form");
let textInput = document.getElementById("textInput");
let dateInput = document.getElementById("dateInput");
let textarea = document.getElementById("textarea");
let msg = document.getElementById("msg");
let tasks = document.getElementById("tasks");
let add = document.getElementById("add");

Form Validations

We cannot let a user submit blank input fields. So, we need to validate the input fields. 👇

form.addEventListener("submit", (e) => {
  e.preventDefault();
  formValidation();
});

let formValidation = () => {
  if (textInput.value === "") {
    console.log("failure");
    msg.innerHTML = "Task cannot be blank";
  } else {
    console.log("success");
    msg.innerHTML = "";
  }
};

Also, add this line inside the CSS:

#msg {
  color: red;
}

The result so far: 👇

Image description

As you can see, the validation is working. The JavaScript code doesn't let the user submit blank input fields, otherwise you're gonna see an error message.

How to collect data and use local storage

Whatever inputs the user writes, we need to collect them and store them in local storage.

First, we collect the data from the input fields, using the function named acceptData and an array named data. Then we push them inside the local storage like this: 👇

let data = [];

let acceptData = () => {
  data.push({
    text: textInput.value,
    date: dateInput.value,
    description: textarea.value,
  });

  localStorage.setItem("data", JSON.stringify(data));

  console.log(data);
};

Also note that this will never work unless you invoke the function acceptData inside the else statement of the form validation. Follow along here: 👇

let formValidation = () => {

  // Other codes are here
   else {

    // Other codes are here

    acceptData();
  }
};

You may have noticed that the modal doesn't close automatically. To solve this, write this small function inside the else statement of the form validation: 👇

let formValidation = () => {

  // Other codes are here
   else {

    // Other codes are here

    acceptData();
    add.setAttribute("data-bs-dismiss", "modal");
    add.click();

    (() => {
      add.setAttribute("data-bs-dismiss", "");
    })();
  }
};

If you open Chrome dev tools, go to the application and open the local storage. You can see this result: 👇

Local Storage Result

How to create new tasks

In order to create a new task, we need to create a function, use template literals to create the HTML elements, and use a map to push the data collected from the user inside the template. Follow along here: 👇

let createTasks = () => {
  tasks.innerHTML = "";
  data.map((x, y) => {
    return (tasks.innerHTML += `
    <div id=${y}>
          <span class="fw-bold">${x.text}</span>
          <span class="small text-secondary">${x.date}</span>
          <p>${x.description}</p>
  
          <span class="options">
            <i onClick= "editTask(this)" data-bs-toggle="modal" data-bs-target="#form" class="fas fa-edit"></i>
            <i onClick ="deleteTask(this);createTasks()" class="fas fa-trash-alt"></i>
          </span>
        </div>
    `);
  });

  resetForm();
};

Also note that the function will never run unless you invoke it inside the acceptData function, like this: 👇

let acceptData = () => {
  // Other codes are here

  createTasks();
};

Once we're done collecting and accepting data from the user, we need to clear the input fields. For that we create a function called resetForm. Follow along: 👇

let resetForm = () => {
  textInput.value = "";
  dateInput.value = "";
  textarea.value = "";
};

The result so far: 👇

Adding task cards

As you can see, there's no styles with the card. Let's add some styles: 👇

#tasks {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}

#tasks div {
  border: 3px solid #abcea1;
  background-color: #e2eede;
  border-radius: 6px;
  padding: 5px;
  display: grid;
  gap: 4px;
}

Style the edit and delete buttons with this code: 👇

#tasks div .options {
  justify-self: center;
  display: flex;
  gap: 20px;
}

#tasks div .options i {
  cursor: pointer;
}

The result so far: 👇

Styles card templates

Function to delete a task

Look here carefully, I added 3 lines of code inside the function.

  • The first line will delete the HTML element from the screen,
  • the second line will remove the targetted Task from the data array,
  • and the third line will update the local storage with the new data.
let deleteTask = (e) => {
  e.parentElement.parentElement.remove();

  data.splice(e.parentElement.parentElement.id, 1);

  localStorage.setItem("data", JSON.stringify(data));

  console.log(data);
};

Now create a dummy task and try to delete it. The result so far looks like this: 👇

Image description

Function to edit tasks

Look here carefully, I added 5 lines of code inside the function.

  • Line 1 is targetting the task that we selected to edit
  • Lines 2, 3, and 4, are targetting the values [task, date, description] of the task that we selected to edit
  • line 5 is running the delete function to remove the selected data both from the local storage, HTML element, and data array.
let editTask = (e) => {
  let selectedTask = e.parentElement.parentElement;

  textInput.value = selectedTask.children[0].innerHTML;
  dateInput.value = selectedTask.children[1].innerHTML;
  textarea.value = selectedTask.children[2].innerHTML;

  deleteTask(e);
};

Now, try to create a dummy task and edit it. The result so far: 👇

Editing a Task

How to get data from local storage

If you refresh the page, you'll note that all of your data is gone. In order to solve that issue, we run a IIFE (Immediately invoked function expression) to retrieve the data from local storage. Follow along: 👇

(() => {
  data = JSON.parse(localStorage.getItem("data")) || [];
  console.log(data);
  createTasks();
})();

Now the data will show up even if you refresh the page.

Conclusion

Congratulations

Congratulations for successfully completing this tutorial. You've learned how to create a todo list application using CRUD operations. Now, you can create your own CRUD application using this tutorial.

Here's your medal for reading until the end. ❤️

Source: https://www.freecodecamp.org/news/learn-crud-operations-in-javascript-by-building-todo-app/

#javascript #crud #operator #todoapp 

Cómo Hacer Operaciones CRUD En JavaScript Creando Una Aplicación Todo

Hoy vamos a aprender cómo hacer operaciones CRUD en JavaScript creando una aplicación Todo. Empecemos 🔥

Esta es la aplicación que estamos haciendo hoy:

Aplicación que estamos haciendo hoy

¿Qué es CRUD?

descripción de la imagen

CRUD significa -

  • c: crear
  • R: Leer
  • U: Actualizar
  • D: Eliminar

CRUD de forma completa

CRUD es un tipo de mecanismo que le permite crear datos, leer datos, editarlos y eliminar esos datos. En nuestro caso, vamos a crear una aplicación Todo, por lo que tendremos 4 opciones para crear tareas, leer tareas, actualizar tareas o eliminar tareas.

Comprender los principios CRUD

Antes de comenzar el tutorial, primero, comprendamos los principios CRUD. Para eso, creemos una aplicación de redes sociales muy, muy simple.

Proyecto de aplicación de redes sociales

Configuración

Configuración del proyecto

Para este proyecto, seguiremos los siguientes pasos:

  • Cree 3 archivos llamados index.html, style.css y main.js
  • Vincule el archivo JavaScript y CSS a index.html
  • Inicie su servidor en vivo

HTML

Dentro de la etiqueta del cuerpo, crea un div con un nombre de clase .container. Ahí tendremos 2 secciones, .lefty .right👇

<body>
  <h1>Social Media App</h1>
  <div class="container">

    <div class="left"></div>
    <div class="right"></div>

  </div>
</body>

En el lado izquierdo, crearemos nuestras publicaciones. En el lado derecho, podemos ver, actualizar y eliminar nuestras publicaciones. Ahora, crea un formulario dentro de la etiqueta div .left 👇

<div class="left">
  <form id="form">
    <label for="post"> Write your post here</label>
    <br><br>
    <textarea name="post" id="input" cols="30" rows="10"></textarea>
    <br> <br>
    <div id="msg"></div>
    <button type="submit">Post</button>
  </form>
</div>

Escribe este código dentro del HTML para que podamos mostrar nuestra publicación en el lado derecho 👇

<div class="right">
  <h3>Your posts here</h3>
  <div id="posts"></div>
</div>

A continuación, insertaremos el CDN font-awesome dentro de la etiqueta de encabezado para usar sus fuentes en nuestro proyecto 👇

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

Ahora, vamos a hacer algunas publicaciones de muestra con íconos de eliminar y editar. Escribe este código dentro del div con el id #posts: 👇

<div id="posts">
  <div>
    <p>Hello world post 1</p>
    <span class="options">
      <i class="fas fa-edit"></i>
      <i class="fas fa-trash-alt"></i>
    </span>
  </div>

  <div >
    <p>Hello world post 2</p>
    <span class="options">
      <i class="fas fa-edit"></i>
      <i class="fas fa-trash-alt"></i>
    </span>
  </div>
</div>

El resultado hasta ahora se ve así:

Resultado de marcado HTML

CSS

Agregar CSS para el proyecto 1

Mantengámoslo simple. Escribe estos estilos dentro de tu hoja de estilo: 👇

body {
  font-family: sans-serif;
  margin: 0 50px;
}

.container {
  display: flex;
  gap: 50px;
}

#posts {
  width: 400px;
}

i {
  cursor: pointer;
}

Ahora, escribe estos estilos para los íconos de opción y div posteriores: 👇

#posts div {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.options {
  display: flex;
  gap: 25px;
}

#msg {
  color: red;
}

Los resultados hasta ahora se ven así: 👇

El resultado después de agregar el proyecto de parte css 1

Parte de JavaScript

Comenzando la parte de javascript

De acuerdo con este diagrama de flujo, seguiremos adelante con el proyecto. No te preocupes, te explicaré todo en el camino. 👇

diagrama de flujo

Validación de formulario

Primero, apuntemos a todos los selectores de ID del HTML en JavaScript. Así: 👇

let form = document.getElementById("form");
let input = document.getElementById("input");
let msg = document.getElementById("msg");
let posts = document.getElementById("posts");

Luego, cree un detector de eventos de envío para el formulario para que pueda evitar el comportamiento predeterminado de nuestra aplicación. Al mismo tiempo, crearemos una función llamada formValidation. 👇

form.addEventListener("submit", (e) => {
  e.preventDefault();
  console.log("button clicked");

  formValidation();
});

let formValidation = () => {};

Ahora, vamos a hacer una declaración if else dentro de nuestra formValidationfunción. Esto nos ayudará a evitar que los usuarios envíen campos de entrada en blanco. 👇

let formValidation = () => {
  if (input.value === "") {
    msg.innerHTML = "Post cannot be blank";
    console.log("failure");
  } else {
    console.log("successs");
    msg.innerHTML = "";
  }
};

Aquí está el resultado hasta ahora: 👇

7sb8faq21j5dzy9vlswj

Como puede ver, también aparecerá un mensaje si el usuario intenta enviar el formulario en blanco.

Cómo aceptar datos de campos de entrada

Cualesquiera que sean los datos que obtengamos de los campos de entrada, los almacenaremos en un objeto. Vamos a crear un objeto llamado data. Y crea una función llamada acceptData: 👇

let data = {};

let acceptData = () => {};

La idea principal es que, usando la función, recopilamos datos de las entradas y los almacenamos en nuestro objeto llamado data. Ahora terminemos de construir nuestra acceptDatafunción.

let acceptData = () => {
  data["text"] = input.value;
  console.log(data);
};

Además, necesitamos que la acceptDatafunción funcione cuando el usuario haga clic en el botón Enviar. Para eso, activaremos esta función en la instrucción else de nuestra formValidationfunción. 👇

let formValidation = () => {
  if (input.value === "") {
    // Other codes are here
  } else {
    // Other codes are here
    acceptData();
  }
};

Cuando ingresamos datos y enviamos el formulario, en la consola podemos ver un objeto que contiene los valores de entrada de nuestro usuario. Así: 👇

resultado hasta ahora en la consola

Cómo crear publicaciones usando literales de plantilla de JavaScript

Para publicar nuestros datos de entrada en el lado derecho, necesitamos crear un elemento div y agregarlo al div de publicaciones. Primero, creemos una función y escribamos estas líneas: 👇

let createPost = () => {
  posts.innerHTML += ``;
};

Los acentos graves son literales de plantilla. Funcionará como una plantilla para nosotros. Aquí, necesitamos 3 cosas: un div principal, la entrada en sí y el div de opciones que lleva los íconos de edición y eliminación. Terminemos nuestra función 👇

let createPost = () => {
  posts.innerHTML += `
  <div>
    <p>${data.text}</p>
    <span class="options">
      <i onClick="editPost(this)" class="fas fa-edit"></i>
      <i onClick="deletePost(this)" class="fas fa-trash-alt"></i>
    </span>
  </div>
  `;
  input.value = "";
};

En nuestra acceptdatafunción, activaremos nuestra createPostfunción. Así: 👇

let acceptData = () => {
  // Other codes are here

  createPost();
};

El resultado hasta ahora: 👇

resultado hasta ahora

Hasta ahora todo bien chicos, casi hemos terminado con el proyecto 1.

Hasta ahora, todo bien

Cómo eliminar una publicación

Para eliminar una publicación, en primer lugar, creemos una función dentro de nuestro archivo javascript:

let deletePost = (e) => {};

A continuación, activamos esta deletePostfunción dentro de todos nuestros íconos de eliminación usando un atributo onClick. Escribirá estas líneas en HTML y en el literal de la plantilla. 👇

<i onClick="deletePost(this)" class="fas fa-trash-alt"></i>

La thispalabra clave se referirá al elemento que disparó el evento. en nuestro caso, el thisse refiere al botón eliminar.

Mire con cuidado, el padre del botón Eliminar es el tramo con opciones de nombre de clase. El padre del lapso es el div. Entonces, escribimos parentElementdos veces para que podamos saltar del ícono de eliminar al div y apuntarlo directamente para eliminarlo.

Terminemos nuestra función. 👇

let deletePost = (e) => {
  e.parentElement.parentElement.remove();
};

El resultado hasta ahora: 👇

eliminar el resultado de una publicación

Cómo editar una publicación

Para editar una publicación, en primer lugar, creemos una función dentro de nuestro archivo JavaScript:

let editPost = (e) => {};

A continuación, activamos esta editPostfunción dentro de todos nuestros íconos de edición usando un atributo onClick. Escribirá estas líneas en HTML y en el literal de la plantilla. 👇

<i onClick="editPost(this)" class="fas fa-edit"></i>

La thispalabra clave se referirá al elemento que disparó el evento. En nuestro caso, el thisse refiere al botón editar.

Mire con cuidado, el padre del botón de edición es el tramo con opciones de nombre de clase. El padre del lapso es el div. Entonces, escribimos parentElementdos veces para que podamos saltar del ícono de edición al div y apuntarlo directamente para eliminarlo.

Luego, cualquier dato que esté dentro de la publicación, lo traemos de vuelta al campo de entrada para editarlo.

Terminemos nuestra función. 👇

let editPost = (e) => {
  input.value = e.parentElement.previousElementSibling.innerHTML;
  e.parentElement.parentElement.remove();
};

El resultado hasta ahora: 👇

Editar el resultado de una publicación

¡Tomar un descanso!

Tomar un descanso

Felicitaciones a todos por completar el proyecto 1. Ahora, ¡tómense un pequeño descanso!

Cómo hacer una aplicación de tareas pendientes usando operaciones CRUD

Hagamos una aplicación de tareas

Comencemos a hacer el proyecto 2, que es una aplicación To-Do.

Configuración del proyecto

configuración del proyecto

Para este proyecto, seguiremos los siguientes pasos:

  • Cree 3 archivos llamados index.html, style.css y main.js
  • Vincule los archivos JavaScript y CSS a index.html
  • Inicie nuestro servidor en vivo

HTML

Escribe este código de inicio dentro del archivo HTML: 👇

<div class="app">
  <h4 class="mb-3">TODO App</h4>

  <div id="addNew" data-bs-toggle="modal" data-bs-target="#form">
    <span>Add New Task</span>
    <i class="fas fa-plus"></i>
  </div>
</div>

El div con una identificación addNewes el botón que abrirá el modal. El intervalo se mostrará en el botón. El ies el ícono de font-awesome.

Vamos a usar bootstrap para hacer nuestro modal. Usaremos el modal para agregar nuevas tareas. Para eso, agregue el enlace CDN de arranque dentro de la etiqueta principal. 👇

<link
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
  rel="stylesheet"
  integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
  crossorigin="anonymous"
/>

<script
  src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
  integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
  crossorigin="anonymous"
></script>

Para ver las tareas creadas, usaremos un div con una tarea de identificación, dentro del div con la aplicación de nombre de clase. 👇

<h5 class="text-center my-3">Tasks</h5>

<div id="tasks"></div>

Inserte el CDN font-awesome dentro de la etiqueta principal para usar fuentes en nuestro proyecto 👇

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

Copie y pegue el código a continuación que proviene del modal de arranque. Lleva un formulario con 3 campos de entrada y un botón de envío. Si lo desea, puede buscar en el sitio web de Bootstrap escribiendo 'modal' en la barra de búsqueda.

<!-- Modal -->
<form
  class="modal fade"
  id="form"
  tabindex="-1"
  aria-labelledby="exampleModalLabel"
  aria-hidden="true"
>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Add New Task</h5>
        <button
          type="button"
          class="btn-close"
          data-bs-dismiss="modal"
          aria-label="Close"
        ></button>
      </div>
      <div class="modal-body">
        <p>Task Title</p>
        <input type="text" class="form-control" name="" id="textInput" />
        <div id="msg"></div>
        <br />
        <p>Due Date</p>
        <input type="date" class="form-control" name="" id="dateInput" />
        <br />
        <p>Description</p>
        <textarea
          name=""
          class="form-control"
          id="textarea"
          cols="30"
          rows="5"
        ></textarea>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
          Close
        </button>
        <button type="submit" id="add" class="btn btn-primary">Add</button>
      </div>
    </div>
  </div>
</form>

El resultado hasta ahora: 👇

Configuración del archivo HTML

Hemos terminado con la configuración del archivo HTML. Comencemos el CSS.

CSS

Agregar la parte css

Agregue estos estilos en el cuerpo para que podamos mantener nuestra aplicación en el centro exacto de la pantalla.

body {
  font-family: sans-serif;
  margin: 0 50px;
  background-color: #e5e5e5;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

Apliquemos estilo al div con la aplicación classname. 👇

.app {
  background-color: #fff;
  width: 300px;
  height: 500px;
  border: 5px solid #abcea1;
  border-radius: 8px;
  padding: 15px;
}

El resultado hasta ahora: 👇

Estilos de aplicaciones

Ahora, diseñemos el botón con el id addNew. 👇

#addNew {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: rgba(171, 206, 161, 0.35);
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
}
.fa-plus {
  background-color: #abcea1;
  padding: 3px;
  border-radius: 3px;
}

El resultado hasta ahora: 👇

Agregar nueva tarea Botón

Si hace clic en el botón, el modal aparece así: 👇

Estallidos modales

Agregar el JS

Agregar el JavaScript

En el archivo JavaScript, en primer lugar, seleccione todos los selectores del HTML que necesitamos usar. 👇

let form = document.getElementById("form");
let textInput = document.getElementById("textInput");
let dateInput = document.getElementById("dateInput");
let textarea = document.getElementById("textarea");
let msg = document.getElementById("msg");
let tasks = document.getElementById("tasks");
let add = document.getElementById("add");

Validaciones de formulario

No podemos permitir que un usuario envíe campos de entrada en blanco. Entonces, necesitamos validar los campos de entrada. 👇

form.addEventListener("submit", (e) => {
  e.preventDefault();
  formValidation();
});

let formValidation = () => {
  if (textInput.value === "") {
    console.log("failure");
    msg.innerHTML = "Task cannot be blank";
  } else {
    console.log("success");
    msg.innerHTML = "";
  }
};

Además, agregue esta línea dentro del CSS:

#msg {
  color: red;
}

El resultado hasta ahora: 👇

descripción de la imagen

Como puede ver, la validación está funcionando. El código JavaScript no permite que el usuario envíe campos de entrada en blanco; de lo contrario, verá un mensaje de error.

Cómo recopilar datos y utilizar el almacenamiento local

Independientemente de las entradas que escriba el usuario, debemos recopilarlas y almacenarlas en el almacenamiento local.

Primero, recopilamos los datos de los campos de entrada, usando la función named acceptDatay una matriz llamada data. Luego los empujamos dentro del almacenamiento local así: 👇

let data = [];

let acceptData = () => {
  data.push({
    text: textInput.value,
    date: dateInput.value,
    description: textarea.value,
  });

  localStorage.setItem("data", JSON.stringify(data));

  console.log(data);
};

También tenga en cuenta que esto nunca funcionará a menos que invoque la función acceptDatadentro de la declaración else de la validación del formulario. Síguenos aquí: 👇

let formValidation = () => {

  // Other codes are here
   else {

    // Other codes are here

    acceptData();
  }
};

Es posible que haya notado que el modal no se cierra automáticamente. Para resolver esto, escribe esta pequeña función dentro de la instrucción else de la validación del formulario: 👇

let formValidation = () => {

  // Other codes are here
   else {

    // Other codes are here

    acceptData();
    add.setAttribute("data-bs-dismiss", "modal");
    add.click();

    (() => {
      add.setAttribute("data-bs-dismiss", "");
    })();
  }
};

Si abre las herramientas de desarrollo de Chrome, vaya a la aplicación y abra el almacenamiento local. Puedes ver este resultado: 👇

Resultado de almacenamiento local

Cómo crear nuevas tareas

Para crear una nueva tarea, necesitamos crear una función, usar literales de plantilla para crear los elementos HTML y usar un mapa para insertar los datos recopilados del usuario dentro de la plantilla. Síguenos aquí: 👇

let createTasks = () => {
  tasks.innerHTML = "";
  data.map((x, y) => {
    return (tasks.innerHTML += `
    <div id=${y}>
          <span class="fw-bold">${x.text}</span>
          <span class="small text-secondary">${x.date}</span>
          <p>${x.description}</p>
  
          <span class="options">
            <i onClick= "editTask(this)" data-bs-toggle="modal" data-bs-target="#form" class="fas fa-edit"></i>
            <i onClick ="deleteTask(this);createTasks()" class="fas fa-trash-alt"></i>
          </span>
        </div>
    `);
  });

  resetForm();
};

También tenga en cuenta que la función nunca se ejecutará a menos que la invoque dentro de la acceptDatafunción, así: 👇

let acceptData = () => {
  // Other codes are here

  createTasks();
};

Una vez que hayamos terminado de recopilar y aceptar datos del usuario, debemos borrar los campos de entrada. Para eso creamos una función llamada resetForm. Síguenos: 👇

let resetForm = () => {
  textInput.value = "";
  dateInput.value = "";
  textarea.value = "";
};

El resultado hasta ahora: 👇

Adición de tarjetas de tareas

Como puede ver, no hay estilos con la tarjeta. Agreguemos algunos estilos: 👇

#tasks {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}

#tasks div {
  border: 3px solid #abcea1;
  background-color: #e2eede;
  border-radius: 6px;
  padding: 5px;
  display: grid;
  gap: 4px;
}

Dale estilo a los botones de editar y eliminar con este código: 👇

#tasks div .options {
  justify-self: center;
  display: flex;
  gap: 20px;
}

#tasks div .options i {
  cursor: pointer;
}

El resultado hasta ahora: 👇

Plantillas de tarjetas de estilos

Función para eliminar una tarea

Mire aquí cuidadosamente, agregué 3 líneas de código dentro de la función.

  • La primera línea eliminará el elemento HTML de la pantalla,
  • la segunda línea eliminará la tarea objetivo de la matriz de datos,
  • y la tercera línea actualizará el almacenamiento local con los nuevos datos.
let deleteTask = (e) => {
  e.parentElement.parentElement.remove();

  data.splice(e.parentElement.parentElement.id, 1);

  localStorage.setItem("data", JSON.stringify(data));

  console.log(data);
};

Ahora cree una tarea ficticia e intente eliminarla. El resultado hasta ahora se ve así: 👇

descripción de la imagen

Función para editar tareas

Mire aquí cuidadosamente, agregué 5 líneas de código dentro de la función.

  • La línea 1 apunta a la tarea que seleccionamos para editar
  • Las líneas 2, 3 y 4 apuntan a los valores [tarea, fecha, descripción] de la tarea que seleccionamos para editar
  • la línea 5 está ejecutando la función de eliminación para eliminar los datos seleccionados tanto del almacenamiento local, el elemento HTML y la matriz de datos.
let editTask = (e) => {
  let selectedTask = e.parentElement.parentElement;

  textInput.value = selectedTask.children[0].innerHTML;
  dateInput.value = selectedTask.children[1].innerHTML;
  textarea.value = selectedTask.children[2].innerHTML;

  deleteTask(e);
};

Ahora, intente crear una tarea ficticia y edítela. El resultado hasta ahora: 👇

Edición de una tarea

Cómo obtener datos del almacenamiento local

Si actualiza la página, notará que todos sus datos han desaparecido. Para resolver ese problema, ejecutamos un IIFE (expresión de función invocada inmediatamente) para recuperar los datos del almacenamiento local. Síguenos: 👇

(() => {
  data = JSON.parse(localStorage.getItem("data")) || [];
  console.log(data);
  createTasks();
})();

Ahora los datos aparecerán incluso si actualiza la página.

Conclusión

Felicidades

Felicitaciones por completar con éxito este tutorial. Ha aprendido a crear una aplicación de lista de tareas mediante operaciones CRUD. Ahora, puede crear su propia aplicación CRUD usando este tutorial.

Aquí está tu medalla por leer hasta el final. ❤️

Fuente: https://www.freecodecamp.org/news/learn-crud-operations-in-javascript-by-building-todo-app/ 

#javascript #crud #operator #todoapp

Thai  Son

Thai Son

1650865080

CRUD Trong JavaScript Bằng Cách Xây Dựng Ứng Dụng TODO

Hôm nay chúng ta sẽ học cách thực hiện các Thao tác CRUD trong JavaScript bằng cách tạo Ứng dụng Todo. Bắt đầu thôi 🔥

Đây là ứng dụng chúng tôi tạo ra hôm nay:

Ứng dụng mà chúng tôi đang làm hôm nay

CRUD là gì?

Mô tả hình ảnh

CRUD là viết tắt của -

  • C: Create
  • R: Read
  • U: Update
  • D: Delete

CRUD đầy đủ

CRUD là một loại cơ chế cho phép bạn tạo dữ liệu, đọc dữ liệu, chỉnh sửa và xóa các dữ liệu đó. Trong trường hợp của chúng tôi, chúng tôi sẽ tạo một ứng dụng Todo, vì vậy chúng tôi sẽ có 4 tùy chọn để tạo tác vụ, đọc tác vụ, cập nhật tác vụ hoặc xóa tác vụ.

Hiểu các nguyên tắc CRUD

Trước khi bắt đầu hướng dẫn, trước tiên, chúng ta hãy hiểu các nguyên tắc CRUD. Để làm được điều đó, hãy tạo một Ứng dụng Truyền thông Xã hội rất đơn giản.

Dự án ứng dụng truyền thông xã hội

Cài đặt

Thiết lập dự án

Đối với dự án này, chúng tôi sẽ thực hiện theo các bước sau:

  • Tạo 3 tệp có tên index.html, style.css và main.js
  • Liên kết tệp JavaScript và CSS với index.html
  • Khởi động máy chủ trực tiếp của bạn

HTML

Bên trong thẻ body, hãy tạo một div có tên lớp .container. Ở đó, chúng ta sẽ có 2 phần, .left.right👇

<body>
  <h1>Social Media App</h1>
  <div class="container">

    <div class="left"></div>
    <div class="right"></div>

  </div>
</body>

Ở phía bên trái, chúng tôi sẽ tạo các bài đăng của chúng tôi. Ở phía bên phải, chúng ta có thể xem, cập nhật và xóa các bài đăng của mình. Bây giờ, hãy tạo một biểu mẫu bên trong thẻ div .left 👇

<div class="left">
  <form id="form">
    <label for="post"> Write your post here</label>
    <br><br>
    <textarea name="post" id="input" cols="30" rows="10"></textarea>
    <br> <br>
    <div id="msg"></div>
    <button type="submit">Post</button>
  </form>
</div>

Viết mã này bên trong HTML để chúng tôi có thể hiển thị bài đăng của mình ở phía bên phải 👇

<div class="right">
  <h3>Your posts here</h3>
  <div id="posts"></div>
</div>

Tiếp theo, chúng tôi sẽ chèn CDN phông chữ tuyệt vời bên trong thẻ head để sử dụng phông chữ của nó trong dự án của chúng tôi 👇

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

Bây giờ, chúng tôi sẽ tạo một số bài đăng mẫu với các biểu tượng xóa và chỉnh sửa. Viết mã này bên trong div với id #posts: 👇

<div id="posts">
  <div>
    <p>Hello world post 1</p>
    <span class="options">
      <i class="fas fa-edit"></i>
      <i class="fas fa-trash-alt"></i>
    </span>
  </div>

  <div >
    <p>Hello world post 2</p>
    <span class="options">
      <i class="fas fa-edit"></i>
      <i class="fas fa-trash-alt"></i>
    </span>
  </div>
</div>

Kết quả cho đến nay trông như thế này:

Kết quả đánh dấu HTML

CSS

Thêm CSS cho dự án 1

Hãy giữ nó đơn giản. Viết các kiểu này bên trong bảng định kiểu của bạn: 👇

body {
  font-family: sans-serif;
  margin: 0 50px;
}

.container {
  display: flex;
  gap: 50px;
}

#posts {
  width: 400px;
}

i {
  cursor: pointer;
}

Bây giờ, hãy viết các kiểu này cho các biểu tượng div và tùy chọn của bài đăng: 👇

#posts div {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.options {
  display: flex;
  gap: 25px;
}

#msg {
  color: red;
}

Kết quả cho đến nay trông như thế này: 👇

Kết quả sau khi thêm dự án phần css 1

Phần JavaScript

Bắt đầu phần javascript

Theo biểu đồ này, chúng tôi sẽ tiếp tục với dự án. Đừng lo lắng, tôi sẽ giải thích mọi thứ trên đường đi. 👇

sơ đồ

Xác thực biểu mẫu

Đầu tiên, hãy nhắm mục tiêu tất cả các bộ chọn ID từ HTML trong JavaScript. Như thế này: 👇

let form = document.getElementById("form");
let input = document.getElementById("input");
let msg = document.getElementById("msg");
let posts = document.getElementById("posts");

Sau đó, xây dựng trình xử lý sự kiện gửi cho biểu mẫu để biểu mẫu có thể ngăn chặn hành vi mặc định của Ứng dụng của chúng tôi. Đồng thời, chúng ta sẽ tạo một hàm có tên formValidation. 👇

form.addEventListener("submit", (e) => {
  e.preventDefault();
  console.log("button clicked");

  formValidation();
});

let formValidation = () => {};

Bây giờ, chúng ta sẽ tạo một câu lệnh if else bên trong formValidationhàm của chúng ta. Điều này sẽ giúp chúng tôi ngăn người dùng gửi các trường nhập trống. 👇

let formValidation = () => {
  if (input.value === "") {
    msg.innerHTML = "Post cannot be blank";
    console.log("failure");
  } else {
    console.log("successs");
    msg.innerHTML = "";
  }
};

Đây là kết quả cho đến nay: 👇

7sb8faq21j5dzy9vlswj

Như bạn có thể thấy, một thông báo cũng sẽ hiển thị nếu người dùng cố gắng gửi biểu mẫu trống.

Cách chấp nhận dữ liệu từ các trường đầu vào

Bất kỳ dữ liệu nào chúng tôi nhận được từ các trường đầu vào, chúng tôi sẽ lưu trữ chúng trong một đối tượng. Hãy tạo một đối tượng có tên data. Và, tạo một hàm có tên acceptData: 👇

let data = {};

let acceptData = () => {};

Ý tưởng chính là, bằng cách sử dụng hàm, chúng tôi thu thập dữ liệu từ các đầu vào và lưu trữ chúng trong đối tượng được đặt tên của chúng tôi data. Bây giờ chúng ta hãy hoàn thành việc xây dựng acceptDatachức năng của chúng ta.

let acceptData = () => {
  data["text"] = input.value;
  console.log(data);
};

Ngoài ra, chúng ta cần acceptDatachức năng hoạt động khi người dùng nhấp vào nút gửi. Vì vậy, chúng ta sẽ kích hoạt hàm này trong câu lệnh else của formValidationhàm của chúng ta. 👇

let formValidation = () => {
  if (input.value === "") {
    // Other codes are here
  } else {
    // Other codes are here
    acceptData();
  }
};

Khi chúng tôi nhập dữ liệu và gửi biểu mẫu, trên bảng điều khiển, chúng tôi có thể thấy một đối tượng chứa các giá trị đầu vào của người dùng của chúng tôi. Như thế này: 👇

kết quả cho đến nay trên bảng điều khiển

Cách tạo bài đăng bằng cách sử dụng các ký tự mẫu JavaScript

Để đăng dữ liệu đầu vào của chúng tôi ở phía bên phải, chúng tôi cần tạo một phần tử div và nối nó vào div bài viết. Đầu tiên, hãy tạo một hàm và viết những dòng sau: 👇

let createPost = () => {
  posts.innerHTML += ``;
};

Các dấu gạch ngược là các ký tự mẫu. Nó sẽ hoạt động như một mẫu cho chúng tôi. Ở đây, chúng ta cần 3 thứ: div cha, chính đầu vào và div tùy chọn mang các biểu tượng chỉnh sửa và xóa. Hãy hoàn thành chức năng của chúng ta 👇

let createPost = () => {
  posts.innerHTML += `
  <div>
    <p>${data.text}</p>
    <span class="options">
      <i onClick="editPost(this)" class="fas fa-edit"></i>
      <i onClick="deletePost(this)" class="fas fa-trash-alt"></i>
    </span>
  </div>
  `;
  input.value = "";
};

Trong acceptdatachức năng của chúng tôi, chúng tôi sẽ kích createPosthoạt chức năng của mình. Như thế này: 👇

let acceptData = () => {
  // Other codes are here

  createPost();
};

Kết quả cho đến nay: 👇

Kết quả cho đến nay

Cho đến nay, các bạn tốt, chúng ta gần như đã hoàn thành xong dự án 1.

càng xa càng tốt

Cách xóa một bài đăng

Để xóa một bài đăng, trước hết, hãy tạo một hàm bên trong tệp javascript của chúng tôi:

let deletePost = (e) => {};

Tiếp theo, chúng tôi kích deletePosthoạt chức năng này bên trong tất cả các biểu tượng xóa của chúng tôi bằng cách sử dụng thuộc tính onClick. Bạn sẽ viết những dòng này bằng HTML và trên mẫu. 👇

<i onClick="deletePost(this)" class="fas fa-trash-alt"></i>

Từ thiskhóa sẽ tham chiếu đến phần tử đã kích hoạt sự kiện. trong trường hợp của chúng tôi, thisđề cập đến nút xóa.

Hãy xem xét kỹ, cha của nút xóa là khoảng cách với các tùy chọn tên lớp. Cha của span là div. Vì vậy, chúng tôi viết parentElementhai lần để chúng tôi có thể chuyển từ biểu tượng xóa sang div và nhắm mục tiêu trực tiếp để xóa nó.

Hãy hoàn thành chức năng của chúng ta. 👇

let deletePost = (e) => {
  e.parentElement.parentElement.remove();
};

Kết quả cho đến nay: 👇

xóa kết quả bài đăng

Cách chỉnh sửa một bài đăng

Để chỉnh sửa một bài đăng, trước hết, hãy tạo một hàm bên trong tệp JavaScript của chúng tôi:

let editPost = (e) => {};

Tiếp theo, chúng tôi kích editPosthoạt chức năng này bên trong tất cả các biểu tượng chỉnh sửa của chúng tôi bằng cách sử dụng thuộc tính onClick. Bạn sẽ viết những dòng này bằng HTML và trên mẫu. 👇

<i onClick="editPost(this)" class="fas fa-edit"></i>

Từ thiskhóa sẽ tham chiếu đến phần tử đã kích hoạt sự kiện. Trong trường hợp của chúng tôi, tham chiếu thisđến nút chỉnh sửa.

Xem kỹ, cha của nút chỉnh sửa là khoảng cách với các tùy chọn tên lớp. Cha của span là div. Vì vậy, chúng tôi viết parentElementhai lần để chúng tôi có thể chuyển từ biểu tượng chỉnh sửa sang div và nhắm mục tiêu trực tiếp để xóa nó.

Sau đó, bất kỳ dữ liệu nào có trong bài đăng, chúng tôi đưa dữ liệu đó trở lại trường đầu vào để chỉnh sửa.

Hãy hoàn thành chức năng của chúng ta. 👇

let editPost = (e) => {
  input.value = e.parentElement.previousElementSibling.innerHTML;
  e.parentElement.parentElement.remove();
};

Kết quả cho đến nay: 👇

Chỉnh sửa kết quả bài đăng

Nghỉ ngơi một lát!

Nghỉ ngơi một lát

Xin chúc mừng mọi người đã hoàn thành dự án 1. Bây giờ, hãy nghỉ ngơi một chút!

Cách tạo ứng dụng việc cần làm bằng Thao tác CRUD

Hãy tạo một ứng dụng todo

Hãy bắt đầu làm dự án 2, đó là Ứng dụng việc cần làm.

Thiết lập dự án

Thiết lập dự án

Đối với dự án này, chúng tôi sẽ thực hiện theo các bước sau:

  • Tạo 3 tệp có tên index.html, style.css và main.js
  • Liên kết các tệp JavaScript và CSS với index.html
  • Khởi động máy chủ trực tiếp của chúng tôi

HTML

Viết mã khởi động này bên trong tệp HTML: 👇

<div class="app">
  <h4 class="mb-3">TODO App</h4>

  <div id="addNew" data-bs-toggle="modal" data-bs-target="#form">
    <span>Add New Task</span>
    <i class="fas fa-plus"></i>
  </div>
</div>

Div có id addNewlà nút sẽ mở phương thức. Khoảng cách sẽ được hiển thị trên nút. Đây ilà biểu tượng từ phông chữ tuyệt vời.

Chúng tôi sẽ sử dụng bootstrap để làm phương thức của chúng tôi. Chúng tôi sẽ sử dụng phương thức để thêm các nhiệm vụ mới. Đối với điều đó, hãy thêm liên kết bootstrap CDN bên trong thẻ head. 👇

<link
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
  rel="stylesheet"
  integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
  crossorigin="anonymous"
/>

<script
  src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
  integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
  crossorigin="anonymous"
></script>

Để xem các tác vụ đã tạo, chúng tôi sẽ sử dụng một div với một nhiệm vụ id, bên trong div có ứng dụng tên lớp. 👇

<h5 class="text-center my-3">Tasks</h5>

<div id="tasks"></div>

Chèn CDN phông chữ tuyệt vời bên trong thẻ head để sử dụng phông chữ trong dự án của chúng tôi 👇

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" />

Sao chép và dán mã bên dưới từ phương thức bootstrap. Nó mang một biểu mẫu với 3 trường đầu vào và một nút gửi. Nếu muốn, bạn có thể tìm kiếm trang web của Bootstrap bằng cách viết 'modal' vào thanh tìm kiếm.

<!-- Modal -->
<form
  class="modal fade"
  id="form"
  tabindex="-1"
  aria-labelledby="exampleModalLabel"
  aria-hidden="true"
>
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Add New Task</h5>
        <button
          type="button"
          class="btn-close"
          data-bs-dismiss="modal"
          aria-label="Close"
        ></button>
      </div>
      <div class="modal-body">
        <p>Task Title</p>
        <input type="text" class="form-control" name="" id="textInput" />
        <div id="msg"></div>
        <br />
        <p>Due Date</p>
        <input type="date" class="form-control" name="" id="dateInput" />
        <br />
        <p>Description</p>
        <textarea
          name=""
          class="form-control"
          id="textarea"
          cols="30"
          rows="5"
        ></textarea>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
          Close
        </button>
        <button type="submit" id="add" class="btn btn-primary">Add</button>
      </div>
    </div>
  </div>
</form>

Kết quả cho đến nay: 👇

Thiết lập tệp html

Chúng tôi đã hoàn tất việc thiết lập tệp HTML. Hãy bắt đầu CSS.

CSS

Thêm phần css

Thêm các kiểu này vào phần nội dung để chúng tôi có thể giữ ứng dụng của mình ở chính giữa màn hình.

body {
  font-family: sans-serif;
  margin: 0 50px;
  background-color: #e5e5e5;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}

Hãy tạo kiểu div với ứng dụng classname. 👇

.app {
  background-color: #fff;
  width: 300px;
  height: 500px;
  border: 5px solid #abcea1;
  border-radius: 8px;
  padding: 15px;
}

Kết quả cho đến nay: 👇

Kiểu ứng dụng

Bây giờ, hãy tạo kiểu cho nút với id addNew. 👇

#addNew {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: rgba(171, 206, 161, 0.35);
  padding: 5px 10px;
  border-radius: 5px;
  cursor: pointer;
}
.fa-plus {
  background-color: #abcea1;
  padding: 3px;
  border-radius: 3px;
}

Kết quả cho đến nay: 👇

Thêm nút tác vụ mới

Nếu bạn nhấp vào nút, phương thức sẽ bật lên như thế này: 👇

Bật lên phương thức

Thêm JS

Thêm JavaScript

Trong tệp JavaScript, trước hết, hãy chọn tất cả các bộ chọn từ HTML mà chúng ta cần sử dụng. 👇

let form = document.getElementById("form");
let textInput = document.getElementById("textInput");
let dateInput = document.getElementById("dateInput");
let textarea = document.getElementById("textarea");
let msg = document.getElementById("msg");
let tasks = document.getElementById("tasks");
let add = document.getElementById("add");

Xác thực biểu mẫu

Chúng tôi không thể để người dùng gửi các trường đầu vào trống. Vì vậy, chúng ta cần xác thực các trường đầu vào. 👇

form.addEventListener("submit", (e) => {
  e.preventDefault();
  formValidation();
});

let formValidation = () => {
  if (textInput.value === "") {
    console.log("failure");
    msg.innerHTML = "Task cannot be blank";
  } else {
    console.log("success");
    msg.innerHTML = "";
  }
};

Ngoài ra, hãy thêm dòng này vào bên trong CSS:

#msg {
  color: red;
}

Kết quả cho đến nay: 👇

Mô tả hình ảnh

Như bạn có thể thấy, xác thực đang hoạt động. Mã JavaScript không cho phép người dùng gửi các trường nhập trống, nếu không bạn sẽ thấy thông báo lỗi.

Cách thu thập dữ liệu và sử dụng bộ nhớ cục bộ

Bất kỳ đầu vào nào mà người dùng viết, chúng tôi cần thu thập chúng và lưu trữ chúng trong bộ nhớ cục bộ.

Đầu tiên, chúng tôi thu thập dữ liệu từ các trường đầu vào, sử dụng hàm được đặt tên acceptDatavà một mảng được đặt tên data. Sau đó, chúng tôi đẩy chúng vào bên trong bộ nhớ cục bộ như thế này: 👇

let data = [];

let acceptData = () => {
  data.push({
    text: textInput.value,
    date: dateInput.value,
    description: textarea.value,
  });

  localStorage.setItem("data", JSON.stringify(data));

  console.log(data);
};

Cũng lưu ý rằng điều này sẽ không bao giờ hoạt động trừ khi bạn gọi hàm acceptDatabên trong câu lệnh else của xác thực biểu mẫu. Cùng theo dõi tại đây: 👇

let formValidation = () => {

  // Other codes are here
   else {

    // Other codes are here

    acceptData();
  }
};

Bạn có thể nhận thấy rằng phương thức không tự động đóng. Để giải quyết vấn đề này, hãy viết hàm nhỏ này bên trong câu lệnh else của xác thực biểu mẫu: 👇

let formValidation = () => {

  // Other codes are here
   else {

    // Other codes are here

    acceptData();
    add.setAttribute("data-bs-dismiss", "modal");
    add.click();

    (() => {
      add.setAttribute("data-bs-dismiss", "");
    })();
  }
};

Nếu bạn mở các công cụ dành cho nhà phát triển Chrome, hãy chuyển đến ứng dụng và mở bộ nhớ cục bộ. Bạn có thể xem kết quả này: 👇

Kết quả lưu trữ cục bộ

Cách tạo nhiệm vụ mới

Để tạo một tác vụ mới, chúng ta cần tạo một hàm, sử dụng các ký tự mẫu để tạo các phần tử HTML và sử dụng bản đồ để đẩy dữ liệu được thu thập từ người dùng vào bên trong mẫu. Cùng theo dõi tại đây: 👇

let createTasks = () => {
  tasks.innerHTML = "";
  data.map((x, y) => {
    return (tasks.innerHTML += `
    <div id=${y}>
          <span class="fw-bold">${x.text}</span>
          <span class="small text-secondary">${x.date}</span>
          <p>${x.description}</p>
  
          <span class="options">
            <i onClick= "editTask(this)" data-bs-toggle="modal" data-bs-target="#form" class="fas fa-edit"></i>
            <i onClick ="deleteTask(this);createTasks()" class="fas fa-trash-alt"></i>
          </span>
        </div>
    `);
  });

  resetForm();
};

Cũng lưu ý rằng hàm sẽ không bao giờ chạy trừ khi bạn gọi nó bên trong acceptDatahàm, như thế này: 👇

let acceptData = () => {
  // Other codes are here

  createTasks();
};

Khi chúng tôi đã hoàn tất việc thu thập và chấp nhận dữ liệu từ người dùng, chúng tôi cần xóa các trường đầu vào. Đối với điều đó, chúng tôi tạo ra một hàm được gọi là resetForm. Cùng theo dõi: 👇

let resetForm = () => {
  textInput.value = "";
  dateInput.value = "";
  textarea.value = "";
};

Kết quả cho đến nay: 👇

Thêm thẻ nhiệm vụ

Như bạn có thể thấy, không có phong cách nào với thẻ. Hãy thêm một số phong cách: 👇

#tasks {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}

#tasks div {
  border: 3px solid #abcea1;
  background-color: #e2eede;
  border-radius: 6px;
  padding: 5px;
  display: grid;
  gap: 4px;
}

Tạo kiểu cho các nút chỉnh sửa và xóa bằng mã này: 👇

#tasks div .options {
  justify-self: center;
  display: flex;
  gap: 20px;
}

#tasks div .options i {
  cursor: pointer;
}

Kết quả cho đến nay: 👇

Các mẫu thẻ kiểu

Chức năng xóa một nhiệm vụ

Xem kỹ ở đây, tôi đã thêm 3 dòng mã bên trong hàm.

  • Dòng đầu tiên sẽ xóa phần tử HTML khỏi màn hình,
  • dòng thứ hai sẽ xóa Nhiệm vụ được nhắm mục tiêu khỏi mảng dữ liệu,
  • và dòng thứ ba sẽ cập nhật bộ nhớ cục bộ với dữ liệu mới.
let deleteTask = (e) => {
  e.parentElement.parentElement.remove();

  data.splice(e.parentElement.parentElement.id, 1);

  localStorage.setItem("data", JSON.stringify(data));

  console.log(data);
};

Bây giờ, hãy tạo một tác vụ giả và cố gắng xóa nó. Kết quả cho đến nay trông như thế này: 👇

Mô tả hình ảnh

Chức năng chỉnh sửa nhiệm vụ

Hãy xem kỹ ở đây, tôi đã thêm 5 dòng mã bên trong hàm.

  • Dòng 1 đang nhắm mục tiêu nhiệm vụ mà chúng tôi đã chọn để chỉnh sửa
  • Các dòng 2, 3 và 4, đang nhắm mục tiêu các giá trị [nhiệm vụ, ngày tháng, mô tả] của nhiệm vụ mà chúng tôi đã chọn để chỉnh sửa
  • dòng 5 đang chạy chức năng xóa để xóa cả dữ liệu đã chọn khỏi bộ nhớ cục bộ, phần tử HTML và mảng dữ liệu.
let editTask = (e) => {
  let selectedTask = e.parentElement.parentElement;

  textInput.value = selectedTask.children[0].innerHTML;
  dateInput.value = selectedTask.children[1].innerHTML;
  textarea.value = selectedTask.children[2].innerHTML;

  deleteTask(e);
};

Bây giờ, hãy thử tạo một tác vụ giả và chỉnh sửa nó. Kết quả cho đến nay: 👇

Chỉnh sửa công việc

Cách lấy dữ liệu từ bộ nhớ cục bộ

Nếu bạn làm mới trang, bạn sẽ lưu ý rằng tất cả dữ liệu của bạn đã biến mất. Để giải quyết vấn đề đó, chúng tôi chạy IIFE (Biểu thức hàm được gọi ngay lập tức) để truy xuất dữ liệu từ bộ nhớ cục bộ. Cùng theo dõi: 👇

(() => {
  data = JSON.parse(localStorage.getItem("data")) || [];
  console.log(data);
  createTasks();
})();

Bây giờ dữ liệu sẽ hiển thị ngay cả khi bạn làm mới trang.

Sự kết luận

Xin chúc mừng

Xin chúc mừng vì đã hoàn thành thành công hướng dẫn này. Bạn đã học cách tạo một ứng dụng danh sách việc cần làm bằng các phép toán CRUD. Bây giờ, bạn có thể tạo ứng dụng CRUD của riêng mình bằng cách sử dụng hướng dẫn này.

Nguồn: https://www.freecodecamp.org/news/learn-crud-operations-in-javascript-by-building-todo-app/

#javascript #crud #todo