DNT Typescript Deno task executor

Dnit - A typescript (deno) based task runner

Dnit is a task runner based on typescript and Deno. It uses typescript variables for tasks and dependencies and is aimed at larger projects with tasks split across many files or shared between projects.

Sample Usage

import {task, exec, file} from  "https://deno.land/x/dnit@dnit-v1.5.0/dnit.ts";

/// A file to be tracked as a target and dependency:
export const msg = file({
  path: './msg.txt'
});

/// A task definition.  No side effect is incurred by creating a task.
export const helloWorld = task({
  name: 'helloWorld',
  description: "foo",
  action: async () => {         /// Actions are typescript async ()=> Promise<void> functions.
    await Deno.run({
      cmd: ["./writeMsg.sh"],
    }).status();
  },
  deps: [
    file({
      path: "./writeMsg.sh"
    })
  ],
  targets: [
    msg
  ]
});

export const goodbye = task({
  name: 'goodbye',
  action: async () => {
    // use ordinary typescript idiomatically if several actions are required
    const actions = [
      async () => {
        const txt = await Deno.readTextFile(msg.path);
        console.log(txt);
      },
      async () => {
        console.log("...");
      },
    ];
    for (const action of actions) {
      await action();
    }
  },
  deps: [msg]       /// Dependency added as a typescript variable
  ///   Dependencies can be file dependency or task dependencies.
});

/// Register cmdline args & tasks with the tool.
exec(Deno.args, [helloWorld, goodbye]);

Sample Usage - CLI

  • List tasks available:
dnit list

  • Execute a task by name:
dnit helloWorld

  • Verbose logging:
dnit list --verbose

In verbose mode the tool logs to stderr (fd #2)

Installation:

Pre-Requisites

  • Requires deno v1.2.0 or greater

Install

It is recommended to use deno install to install the tool, which provides a convenient entrypoint script and aliases the permission flags.

deno install --allow-read --allow-write --allow-run --unstable -f --name dnit https://deno.land/x/dnit@dnit-v1.5.0/main.ts

Install from source checkout:

deno install --allow-read --allow-write --allow-run --unstable -f --name dnit ./main.ts

  • Read, Write and Run permissions are required in order to operate on files and execute tasks.
  • Unstable flag is currently required in order to support import maps.

Tasks and Files in Detail

Files are tracked by the exported export function file(fileParams: FileParams) : TrackedFile

/** User params for a tracked file */
export type FileParams = {

  /// File path
  path: string;

  /// Optional function for how to hash the file.   Defaults to the sha1 hash of the file contents.
  /// A file is out of date if the file timestamp and the hash are different than that in the task manifest
  gethash?: GetFileHash;
};

TrackedFile objects are used in tasks, either as targets or dependencies.

Tasks are created by the exported function task(taskParams: TaskParams): Task

/** User definition of a task */
export type TaskParams = {

  /// Name: (string) - The key used to initiate a task
  name: A.TaskName;

  /// Description (string) - Freeform text description shown on help
  description?: string;

  /// Action executed on execution of the task (async or sync)
  action: Action;

  /// Optional list of explicit task dependencies
  task_deps?: Task[];

  /// Optional list of explicit file dependencies
  file_deps?: TrackedFile[];

  /// Optional list of task or file dependencies
  deps?: (Task|TrackedFile)[];

  /// Targets (files which will be produced by execution of this task)
  targets?: TrackedFile[];

  /// Custom up-to-date definition - Can be used to make a task *less* up to date.  Eg; use uptodate: runAlways  to run always on request regardless of dependencies being up to date.
  uptodate?: IsUpToDate;
};

Tasks are passed to the exported export async function exec(cliArgs: string[], tasks: Task[]) : Promise<void> This exposes the tasks for execution by the CLI and executes them according to the cliArgs passed in.

exec(Deno.args, tasks);

Larger Scale use of tasks

This tool aims to support “large” projects with many tasks and even sharing task definitions across projects.

  • Tasks and dependencies are typescript variables, can be imported/exported and used. This makes a large project of tasks and dependencies easy to navigate in a typescript IDE.
  • User scripts are required to reside in a dnit directory. This provides a place to have a (deno) typescript tree for the task scripting, which encourages tasks to be separated into modules and generally organised as a typescript project tree.
  • User scripts can have an import_map.json file in order to import tasks and utils more flexibly.
  • The main dnit tool can be executed on its own (see section on Installation above)

Launching the tool

The dnit tool searches for a user script to execute, in order to support the abovementioned directory of sources.

  • When dnit is the main it runs the launch function to run the user’s scripts.
  • It starts from the current working directory and runs findUserSource
  • findUserSource looks for subdirectory dnit and looks for sources main.ts or dnit.ts
    • It optionally looks for import_map.json or .import_map.json to use as the import map.
    • If found then it changes working directory and executes the user script.
    • If not found then it recurses into findUserSource in the parent directory.

Eg: with a file layout:

repo
  dnit
    main.ts
    import_map.json
  src
    project.ts
  package.json
  tsconfig.json

Executing dnit anywhere in a subdirectory of repo will execute the main.ts. Any relative paths used for dependencies and targets will resolve relative to the repo root, since it is where the subdirectory and file dnit/main.ts was found.

Note that the other directories can contain (non-deno) typescript project(s) and having the (deno) typescript sources in a nominal dnit tree helps prevent confusion between the two.

References:

Download Details:

Author: PaulThompson

Source Code: https://github.com/PaulThompson/dnit

#deno #node #nodejs #typescript

What is GEEK

Buddha Community

DNT Typescript Deno task executor

DNT Typescript Deno task executor

Dnit - A typescript (deno) based task runner

Dnit is a task runner based on typescript and Deno. It uses typescript variables for tasks and dependencies and is aimed at larger projects with tasks split across many files or shared between projects.

Sample Usage

import {task, exec, file} from  "https://deno.land/x/dnit@dnit-v1.5.0/dnit.ts";

/// A file to be tracked as a target and dependency:
export const msg = file({
  path: './msg.txt'
});

/// A task definition.  No side effect is incurred by creating a task.
export const helloWorld = task({
  name: 'helloWorld',
  description: "foo",
  action: async () => {         /// Actions are typescript async ()=> Promise<void> functions.
    await Deno.run({
      cmd: ["./writeMsg.sh"],
    }).status();
  },
  deps: [
    file({
      path: "./writeMsg.sh"
    })
  ],
  targets: [
    msg
  ]
});

export const goodbye = task({
  name: 'goodbye',
  action: async () => {
    // use ordinary typescript idiomatically if several actions are required
    const actions = [
      async () => {
        const txt = await Deno.readTextFile(msg.path);
        console.log(txt);
      },
      async () => {
        console.log("...");
      },
    ];
    for (const action of actions) {
      await action();
    }
  },
  deps: [msg]       /// Dependency added as a typescript variable
  ///   Dependencies can be file dependency or task dependencies.
});

/// Register cmdline args & tasks with the tool.
exec(Deno.args, [helloWorld, goodbye]);

Sample Usage - CLI

  • List tasks available:
dnit list

  • Execute a task by name:
dnit helloWorld

  • Verbose logging:
dnit list --verbose

In verbose mode the tool logs to stderr (fd #2)

Installation:

Pre-Requisites

  • Requires deno v1.2.0 or greater

Install

It is recommended to use deno install to install the tool, which provides a convenient entrypoint script and aliases the permission flags.

deno install --allow-read --allow-write --allow-run --unstable -f --name dnit https://deno.land/x/dnit@dnit-v1.5.0/main.ts

Install from source checkout:

deno install --allow-read --allow-write --allow-run --unstable -f --name dnit ./main.ts

  • Read, Write and Run permissions are required in order to operate on files and execute tasks.
  • Unstable flag is currently required in order to support import maps.

Tasks and Files in Detail

Files are tracked by the exported export function file(fileParams: FileParams) : TrackedFile

/** User params for a tracked file */
export type FileParams = {

  /// File path
  path: string;

  /// Optional function for how to hash the file.   Defaults to the sha1 hash of the file contents.
  /// A file is out of date if the file timestamp and the hash are different than that in the task manifest
  gethash?: GetFileHash;
};

TrackedFile objects are used in tasks, either as targets or dependencies.

Tasks are created by the exported function task(taskParams: TaskParams): Task

/** User definition of a task */
export type TaskParams = {

  /// Name: (string) - The key used to initiate a task
  name: A.TaskName;

  /// Description (string) - Freeform text description shown on help
  description?: string;

  /// Action executed on execution of the task (async or sync)
  action: Action;

  /// Optional list of explicit task dependencies
  task_deps?: Task[];

  /// Optional list of explicit file dependencies
  file_deps?: TrackedFile[];

  /// Optional list of task or file dependencies
  deps?: (Task|TrackedFile)[];

  /// Targets (files which will be produced by execution of this task)
  targets?: TrackedFile[];

  /// Custom up-to-date definition - Can be used to make a task *less* up to date.  Eg; use uptodate: runAlways  to run always on request regardless of dependencies being up to date.
  uptodate?: IsUpToDate;
};

Tasks are passed to the exported export async function exec(cliArgs: string[], tasks: Task[]) : Promise<void> This exposes the tasks for execution by the CLI and executes them according to the cliArgs passed in.

exec(Deno.args, tasks);

Larger Scale use of tasks

This tool aims to support “large” projects with many tasks and even sharing task definitions across projects.

  • Tasks and dependencies are typescript variables, can be imported/exported and used. This makes a large project of tasks and dependencies easy to navigate in a typescript IDE.
  • User scripts are required to reside in a dnit directory. This provides a place to have a (deno) typescript tree for the task scripting, which encourages tasks to be separated into modules and generally organised as a typescript project tree.
  • User scripts can have an import_map.json file in order to import tasks and utils more flexibly.
  • The main dnit tool can be executed on its own (see section on Installation above)

Launching the tool

The dnit tool searches for a user script to execute, in order to support the abovementioned directory of sources.

  • When dnit is the main it runs the launch function to run the user’s scripts.
  • It starts from the current working directory and runs findUserSource
  • findUserSource looks for subdirectory dnit and looks for sources main.ts or dnit.ts
    • It optionally looks for import_map.json or .import_map.json to use as the import map.
    • If found then it changes working directory and executes the user script.
    • If not found then it recurses into findUserSource in the parent directory.

Eg: with a file layout:

repo
  dnit
    main.ts
    import_map.json
  src
    project.ts
  package.json
  tsconfig.json

Executing dnit anywhere in a subdirectory of repo will execute the main.ts. Any relative paths used for dependencies and targets will resolve relative to the repo root, since it is where the subdirectory and file dnit/main.ts was found.

Note that the other directories can contain (non-deno) typescript project(s) and having the (deno) typescript sources in a nominal dnit tree helps prevent confusion between the two.

References:

Download Details:

Author: PaulThompson

Source Code: https://github.com/PaulThompson/dnit

#deno #node #nodejs #typescript

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 

Rusty  Shanahan

Rusty Shanahan

1596666360

TypeScript — Compilation & the TypeScript Compiler

TypeScript provides a command-line utility tsc that compiles (transpiles) TypeScript files (_.ts_) into JavaScript. However, the tsc compiler (short for TypeScript compiler) needs a JSON configuration file to look for TypeScript files in the project and generate valid output files at a correct location.

When you run tsc command in a directory, TypeScript compiler looks for the tsconfig.json file in the current directory and if it doesn’t find one, then it keeps looking up the directory tree until it finds one. The directory where the tsconfig.json is located is considered as the root of the project.

You can manually provide a path to the tsconfig.json file using --project or -p command-line flag. This file doesn’t need to have the tsconfig.json filename if you are using this flag with the exact file path. However, you can also provide the directory path that contains the tsconfig.json file.

$ tsc -p /proj/x/tsconfig.dev.json

If the TypeScript compiler fails to locate this configuration file, you would get an error. But you can provide settings enlisted in this file through the equivalent command-line options which we will cover in the next lesson.

Structure of tsconfig.json

So what does this file contain and what exactly it controls?

{
  "files": [
    "src/lib/person.ts",
    "src/lib/student.ts",
    "src/main.ts"
  ],
  "compilerOptions": {
    "target": "ES6",
    "module": "CommonJS",
    "outDir": "./dist/development"
  }
}

The tsconfig.json file is a standard JSON file, however, it supports JSON5 specifications, so you can use comments, single quotes, and more. It contains some root-level options and some compiler options. The root-level options are options that are outside of the compilerOptions object, so in the above example, files is a root-level option.

The root-level options control how the project is presented to the TypeScript compiler, such as which TypeScript files to consider for the compilation. The compiler options contain settings for the TypeScript compiler such as where to output the compiled JavaScript files in the project directory.


ROOT-LEVEL OPTIONS

These options control how the project is presented to the TypeScript compiler for the compilation and static type analysis. These options must be kept outside compilerOptions object of the tsconfig.json file.

● files

The files array contains the location of the TypeScript files to consider for the compilation. These can be either relative paths or absolute paths on the disk. A relative path is located relative to the location of the tsconfig.json file (AKA root of the project).

/projects/sample/
├── a.ts
├── src/
|  ├── b.ts
|  ├── c.ts
|  ├── ignore.ts
|  └── lib/
|     ├── d.ts
|     └── e.ts
└── tsconfig.json

Let’s consider that we have the above directory structure in our project. As you can see, the TypeScript files (.ts) are located in multiple directories. We want to compile all the .ts files except the ignore.ts file. Hence we would provide relative paths of these files in the files options of tsconfig.json.

// tsconfig.json

{
    "files": [
        "a.ts",
        "src/b.ts",
        "./src/c.ts",
        "src/lib/d.ts",
        "./src/lib/e.ts"
    ]
}

You can also provide absolute paths of these files but relative paths are most recommended since they would be consistent on all the systems. All the relative paths are resolved against the path of tsconfig.json file in the project. You can optionally provide ./ or ../ prefix to locate the file.

Since we haven’t provided any compilerOptions values, all the default values for the compiler options are used which we will talk about in a bit. The TypeScript compiler compiles these files and outputs the JavaScript with .js extension by keeping the same file name as the individual input file.

The TypeScript compiler also preserves the original file path, hence the .js output file will be generated where the input file was in the directory structure. When you run the tsc command from the directory where your tsconfig.json file is located, you are going to see the result below.

/projects/sample/
├── a.js
├── a.ts
├── src/
|  ├── b.js
|  ├── b.ts
|  ├── c.js
|  ├── c.ts
|  ├── ignore.ts
|  └── lib/
|     ├── d.js
|     ├── d.ts
|     ├── e.js
|     └── e.ts
└── tsconfig.json

As you can see, the TypeScript compiler compiled all the input TypeScript files listed inside files array of tsconfig.json. You can’t see the ignore.js file since ignore.ts file was not included in the files array.

The directory where the tsconfig.json file is located is considered as the root of the project, AKA the root directory. You can also include a file from outside this root directory, such by including "../x.ts" in the files array where x would be in the parent directory of the root directory. Since the TypeScript compiler preserves the input file path, it will generate x.js in the parent directory of the root directory.

● include & exclude

The files option is great when you have relatively few files to work with. But when your project is big and contains hundreds of source files located in a nested directory structure, then handpicking file paths is not practical.

To solve this issue, we can use include option. This option is just like files, however, we can optionally provide glob patterns to locate input files. The exclude options behave the same, except it removes the files from the compilation that may have been included by the include option.

// tsconfig.json

{
    "include": [
        "a.ts",
        "src/**/*.ts"
    ],
    "exclude": [
        "./**/*/ignore.ts"
    ]
}

In the above tsconfig.json, we have removed the files option and added include which adds a.ts file from the root directory and all the .ts file from the src directory. Since this would also include any ignore.ts from the src directory, we have provided the exclude option that excludes any ignore.ts file from the compilation if located inside the src directory.

When we run the tsc command now, results won’t be any different since the files considered for the compilation both in the previous example and this example are the same.

/projects/sample/
├── a.js
├── a.ts
├── src/
|  ├── b.js
|  ├── b.ts
|  ├── c.js
|  ├── c.ts
|  ├── ignore.ts
|  └── lib/
|     ├── d.js
|     ├── d.ts
|     ├── e.js
|     └── e.ts
└── tsconfig.json

The TypeScript compiler automatically excludes files from the "node_modules""bower_components""jspm_packages" and "<outDir>" directories, where <outDir> is the value of outDir compiler-option provided by you. This prevents any .ts file from these directories getting included in the compilation process by accident.

#nodejs #typescript #deno #programming #javascript #deno

伊藤  直子

伊藤 直子

1650021960

TODO APPを構築して、JavaScriptでのCRUD操作を学ぶ

今日は、Todoアプリを作成してJavaScriptでCRUD操作を行う方法を学びます。始めましょう🔥

これは私たちが今日作っているアプリです:

今日作っているアプリ

CRUDとは何ですか?

画像の説明

CRUDは-の略です

  • C:作成
  • R:読む
  • U:更新
  • D:削除

CRUDフルフォーム

CRUDは、データの作成、データの読み取り、編集、およびそれらのデータの削除を可能にするメカニズムの一種です。この例では、Todoアプリを作成するので、タスクの作成、タスクの読み取り、タスクの更新、またはタスクの削除を行うための4つのオプションがあります。

CRUDの原則を理解する

チュートリアルを開始する前に、まず、CRUDの原則を理解しましょう。そのために、非常に単純なソーシャルメディアアプリケーションを作成しましょう。

ソーシャルメディアアプリプロジェクト

設定

プロジェクトの設定

このプロジェクトでは、以下の手順に従います。

  • index.html、style.css、main.jsという名前の3つのファイルを作成します
  • JavaScriptおよびCSSファイルをindex.htmlにリンクします
  • ライブサーバーを起動します

HTML

bodyタグ内に、クラス名を使用してdivを作成します.container。そこには2つのセクションがあり.left.right👇

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

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

  </div>
</body>

左側に投稿を作成します。右側では、投稿を表示、更新、削除できます。次に、.leftdivタグ内にフォームを作成します👇

<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>

このコードをHTML内に記述して、投稿を右側に表示できるようにします👇

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

次に、プロジェクトでそのフォントを使用するために、headタグ内にfont-awesomeCDNを挿入します👇

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

次に、削除アイコンと編集アイコンを使用してサンプル投稿を作成します。このコードをdiv内に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>

これまでの結果は次のようになります。

HTMLマークアップの結果

CSS

プロジェクト1のCSSの追加

シンプルにしましょう。スタイルシート内にこれらのスタイルを記述します:👇

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

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

#posts {
  width: 400px;
}

i {
  cursor: pointer;
}

次に、投稿divとオプションアイコンに次のスタイルを記述します。👇

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

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

#msg {
  color: red;
}

これまでの結果は次のようになります:👇

cssパーツプロジェクト1を追加した後の結果

JavaScriptパート

javascript部分を開始します

このフローチャートに従って、プロジェクトを進めていきます。心配しないでください、私は途中ですべてを説明します。👇

フローチャート

フォームの検証

まず、JavaScriptのHTMLからすべてのIDセレクターをターゲットにしましょう。このように:👇

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

次に、フォームの送信イベントリスナーを作成して、アプリのデフォルトの動作を防ぐことができるようにします。同時に、という名前の関数を作成しますformValidation。👇

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

  formValidation();
});

let formValidation = () => {};

次に、関数内でifelseステートメントを作成しformValidationます。これにより、ユーザーが空白の入力フィールドを送信するのを防ぐことができます。👇

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

これまでの結果は次のとおりです:👇

7sb8faq21j5dzy9vlswj

ご覧のとおり、ユーザーがフォームを空白で送信しようとすると、メッセージも表示されます。

入力フィールドからデータを受け入れる方法

入力フィールドから取得するデータが何であれ、それらをオブジェクトに格納します。。という名前のオブジェクトを作成しましょうdata。そして、次の名前の関数を作成しますacceptData:👇

let data = {};

let acceptData = () => {};

主なアイデアは、関数を使用して、入力からデータを収集し、という名前のオブジェクトに格納することdataです。acceptDataそれでは、関数の作成を完了しましょう。

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

また、acceptDataユーザーが送信ボタンをクリックしたときに機能する機能が必要です。そのために、関数のelseステートメントでこの関数を起動しformValidationます。👇

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

データを入力してフォームを送信すると、コンソールにユーザーの入力値を保持しているオブジェクトが表示されます。このように:👇

これまでのコンソールでの結果

JavaScriptテンプレートリテラルを使用して投稿を作成する方法

入力データを右側に投稿するには、div要素を作成し、それを投稿divに追加する必要があります。まず、関数を作成して次の行を記述しましょう:👇

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

バックティックはテンプレートリテラルです。それは私たちのテンプレートとして機能します。ここでは、親div、入力自体、および編集アイコンと削除アイコンを保持するオプションdivの3つが必要です。機能を終了しましょう👇

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 = "";
};

acceptdata関数では、関数を起動しますcreatePost。このように:👇

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

  createPost();
};

これまでの結果:👇

これまでの結果

これまでのところ、プロジェクト1はほぼ完了しています。

ここまでは順調ですね

投稿を削除する方法

投稿を削除するために、まず、javascriptファイル内に関数を作成しましょう。

let deletePost = (e) => {};

deletePost次に、onClick属性を使用して、すべての削除アイコン内でこの関数を起動します。これらの行は、HTMLとテンプレートリテラルで記述します。👇

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

thisキーワードは、イベントを発生させた要素を参照します。この場合、thisは削除ボタンを指します。

注意深く見てください。削除ボタンの親は、クラス名オプションのあるスパンです。スパンの親はdivです。parentElementしたがって、削除アイコンからdivにジャンプし、直接ターゲットにして削除できるように、2回書き込みます。

関数を終了しましょう。👇

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

これまでの結果:👇

投稿結果の削除

投稿を編集する方法

投稿を編集するために、まず、JavaScriptファイル内に関数を作成しましょう。

let editPost = (e) => {};

editPost次に、onClick属性を使用して、すべての編集アイコン内でこの関数を起動します。これらの行は、HTMLとテンプレートリテラルで記述します。👇

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

thisキーワードは、イベントを発生させた要素を参照します。この場合、thisは編集ボタンを指します。

注意深く見てください。編集ボタンの親は、クラス名オプションのあるスパンです。スパンの親はdivです。parentElementしたがって、編集アイコンからdivにジャンプし、直接ターゲットにして削除できるように、2回書き込みます。

次に、投稿内のデータが何であれ、入力フィールドに戻して編集します。

関数を終了しましょう。👇

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

これまでの結果:👇

投稿結果の編集

休憩する!

休憩する

プロジェクト1を完了してくださった皆さん、おめでとうございます。さあ、ちょっと休憩してください。

CRUD操作を使用してToDoアプリを作成する方法

ToDoアプリを作ろう

To-Doアプリであるプロジェクト2の作成を始めましょう。

プロジェクトの設定

プロジェクトの設定

このプロジェクトでは、以下の手順に従います。

  • index.html、style.css、main.jsという名前の3つのファイルを作成します
  • JavaScriptファイルとCSSファイルをindex.htmlにリンクします
  • ライブサーバーを起動します

HTML

このスターターコードを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>

IDを持つdivaddNewは、モーダルを開くボタンです。ボタンにスパンが表示されます。これiはfont-awesomeのアイコンです。

ブートストラップを使用してモーダルを作成します。モーダルを使用して新しいタスクを追加します。そのために、headタグ内にブートストラップCDNリンクを追加します。👇

<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>

作成されたタスクを確認するには、クラス名アプリを使用したdiv内で、idタスクを使用したdivを使用します。👇

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

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

プロジェクトでフォントを使用するには、headタグ内にfont-awesomeCDNを挿入します👇

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

ブートストラップモーダルからの以下のコードをコピーして貼り付けます。3つの入力フィールドと送信ボタンを備えたフォームがあります。必要に応じて、検索バーに「モーダル」と入力して、BootstrapのWebサイトを検索できます。

<!-- 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>

これまでの結果:👇

HTMLファイルの設定

HTMLファイルの設定は完了です。CSSを始めましょう。

CSS

css部分を追加する

これらのスタイルを本文に追加して、アプリを画面の正確な中央に配置できるようにします。

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

classnameアプリでdivのスタイルを設定しましょう。👇

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

これまでの結果:👇

アプリのスタイル

それでは、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;
}

これまでの結果:👇

新しいタスクボタンを追加

ボタンをクリックすると、モーダルが次のようにポップアップ表示されます:👇

モーダルポップ

JSを追加する

JavaScriptを追加する

JavaScriptファイルで、まず、使用する必要のあるHTMLからすべてのセレクターを選択します。👇

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.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 = "";
  }
};

また、CSS内に次の行を追加します。

#msg {
  color: red;
}

これまでの結果:👇

画像の説明

ご覧のとおり、検証は機能しています。JavaScriptコードでは、ユーザーが空白の入力フィールドを送信することはできません。そうしないと、エラーメッセージが表示されます。

データを収集してローカルストレージを使用する方法

ユーザーが書き込んだ入力が何であれ、それらを収集してローカルストレージに保存する必要があります。

まず、という名前の関数とという名前acceptDataの配列を使用して、入力フィールドからデータを収集しますdata。次に、次のようにローカルストレージ内にプッシュします:👇

let data = [];

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

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

  console.log(data);
};

acceptDataまた、フォーム検証のelseステートメント内で関数を呼び出さない限り、これは機能しないことに注意してください。ここに従ってください:👇

let formValidation = () => {

  // Other codes are here
   else {

    // Other codes are here

    acceptData();
  }
};

モーダルが自動的に閉じないことに気付いたかもしれません。これを解決するには、フォーム検証のelseステートメント内にこの小さな関数を記述します。👇

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", "");
    })();
  }
};

Chrome開発ツールを開く場合は、アプリケーションに移動してローカルストレージを開きます。あなたはこの結果を見ることができます:👇

ローカルストレージの結果

新しいタスクを作成する方法

新しいタスクを作成するには、関数を作成し、テンプレートリテラルを使用してHTML要素を作成し、マップを使用してユーザーから収集したデータをテンプレート内にプッシュする必要があります。ここに従ってください:👇

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();
};

また、次のacceptDataように、関数内で呼び出さない限り、関数は実行されないことに注意してください。👇

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

  createTasks();
};

ユーザーからのデータの収集と受け入れが完了したら、入力フィールドをクリアする必要があります。そのために、と呼ばれる関数を作成しますresetForm。フォローする:👇

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

これまでの結果:👇

タスクカードの追加

ご覧のとおり、このカードにはスタイルはありません。いくつかのスタイルを追加しましょう:👇

#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;
}

次のコードで編集ボタンと削除ボタンのスタイルを設定します:👇

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

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

これまでの結果:👇

スタイルカードテンプレート

タスクを削除する機能

ここを注意深く見てください。関数内に3行のコードを追加しました。

  • 最初の行は、画面からHTML要素を削除します。
  • 2行目は、ターゲットのタスクをデータ配列から削除します。
  • 3行目は、ローカルストレージを新しいデータで更新します。
let deleteTask = (e) => {
  e.parentElement.parentElement.remove();

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

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

  console.log(data);
};

次に、ダミータスクを作成し、それを削除してみます。これまでの結果は次のようになります:👇

画像の説明

タスクを編集する機能

ここを注意深く見てください。関数内に5行のコードを追加しました。

  • 1行目は、編集するために選択したタスクを対象としています
  • 2行目、3行目、および4行目は、編集するために選択したタスクの値[タスク、日付、説明]を対象としています。
  • 5行目では、削除機能を実行して、選択したデータをローカルストレージ、HTML要素、およびデータ配列の両方から削除しています。
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);
};

次に、ダミータスクを作成して編集してみます。これまでの結果:👇

タスクの編集

ローカルストレージからデータを取得する方法

ページを更新すると、すべてのデータが失われていることに気付くでしょう。この問題を解決するために、IIFE(即時呼び出し関数式)を実行して、ローカルストレージからデータを取得します。フォローする:👇

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

これで、ページを更新してもデータが表示されます。

結論

おめでとう

このチュートリアルを正常に完了しました。おめでとうございます。CRUD操作を使用してToDoリストアプリケーションを作成する方法を学習しました。これで、このチュートリアルを使用して独自のCRUDアプリケーションを作成できます。

これが最後まで読むためのあなたのメダルです。❤️

ソース: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