次勉強したいリポジトリ



https://github.com/ArtsiomHalash/Python-flask-CRUD

https://github.com/JuanFariasGit/flask-crud

https://www.w3schools.com/jquery/jquery_examples.asp

https://jquery-docs-ja.net/ajax/


### 解説

```php:
const sendData = async function(url, data={}) {
    const req = await fetch(url, {
        method:"POST",
        headers:{ 
            "Content-Type":"application/json"
        },
        body:JSON.stringify(data)
    });
    try {
        const res = await req.json();
        return res;
    } catch( err ) {
        console.log("Error "+err);
    }
}

// リスト全体の削除処理
const deleteListHandler = function(e){
    if(confirm('Are You Sure You Want to Delete A full list?')) { 
        const listId = this.parentElement.dataset.id;
        fetch(`/lists/${listId}/delete`, {
            method:'DELETE'
        }).then(data=>data.json()).then( jsonData =>{
            let id = Number(listId)
            id -= 1;
            window.location.replace("http://127.0.0.1:5000/lists/"+ (id > 0 ? id : 1));
        });
    }else{
        return;
    }
}

// タスク単体の削除処理
const deleteHandler = function(eve) {        
    const taskId = this.previousElementSibling.previousElementSibling.dataset.id;
    fetch(`/tasks/${taskId}/delete`,{
        method:"DELETE"
    }).then(data=>data.json()).then( jsonData =>{
        this.parentElement.remove()
        console.log(jsonData.action);
    });
}

// タスク完了チェックボックスの更新処理
const updateHandler =  function(eve) {
    const completed = eve.target.checked;
    const taskId = eve.target.dataset.id;
    if(completed){
       this.parentElement.style.textDecoration='line-through';
    }else{
        this.parentElement.style.textDecoration='none';
    }
    sendData(`/tasks/${taskId}/update`,{'completed':completed}).then(d=>console.log(d.action))
}

// HTML要素の取得
const inpList = document.getElementById('form1');
const formList = document.getElementById('formList');
const ulList = document.getElementById('list');
const allBtns = document.querySelectorAll('.list-item button')
const allLis = document.querySelectorAll('.list-item');

// 新しいリストを画面に追加する関数
function addList(data, ul) {
    const li = document.createElement('li');
    li.classList.add('nav-item' ,'list-item');
    li.setAttribute('data-id',data.id)
    const link = document.createElement('a');
    link.classList.add('nav-link','active');
    link.innerText = data.title;
    link.setAttribute('href', data.id)
    link.addEventListener('click',function(e){       
        activateLi(link)
    })
    const btnList = document.createElement('button');
    btnList.innerText='x';
    btnList.addEventListener('click',deleteListHandler)
    li.appendChild(link);
    li.appendChild(btnList);
    ul.appendChild(li);
    if(ul.childElementCount == 1){
        link.classList.add('activate')   
    }else{
        link.classList.remove('activate')
    }
}

// リスト項目をアクティブにする関数
function activateLi(li) {
    if(window.location.pathname.split('/')[2] == li.dataset.id)
    {
        li.firstElementChild.classList.add("activate")
        li.style.zIndex=1
        
    }
    else
    li.firstElementChild.classList.remove("activate")
}

// 新しいリストの追加処理
formList.addEventListener('submit', function(e){
    e.preventDefault()
    const list = inpList.value;
    const cleanList = list.trim();
    if(cleanList === '') {
        const err = document.querySelector('#error');
        err.style.display='block';
        err.innerHTML = "You Must Enter A valid List Name !";
        window.setTimeout(function(){
            err.style.display='none';
        },2000);
        return;
    }
    sendData('/lists/create', {'title':cleanList})
    .then(data=> {
        if(data.error) {
            const err = document.querySelector('#error');
            err.style.display='block';
            err.innerHTML = data.error;
            return;
        }
        addList(data, ulList) })
});

// 全てのリストをアクティブ状態に反映
allLis.forEach(ele=>{
    activateLi(ele)
})

// 全ての削除ボタンにイベントを付加
allBtns.forEach(ele=>{
    ele.addEventListener('click', deleteListHandler);
})

// 新しいタスクを画面に追加する関数
function addTask(data, ul) {
    const li = document.createElement('li');
    li.classList.add('list-group-item', 'd-flex', 'align-items-center', 'border-0', 'mb-2', 'rounded');
    li.setAttribute('style','background-color: #f4f6f7');
    const checkBox = document.createElement('input');
    checkBox.setAttribute('type','checkbox');
    checkBox.setAttribute('data-id',data.id);
    checkBox.classList.add('form-check-input' ,'me-2');
    checkBox.addEventListener('change', updateHandler);
    const sTag = document.createElement('s');
    sTag.innerHTML = `${data.description}`;
    const newBtn = document.createElement('button');
    newBtn.innerText = "X";
    newBtn.classList.add("btn", "btn-outline-danger", "del-task");
    newBtn.style.position = 'absolute';
    newBtn.style.right = "5px";
    newBtn.addEventListener('click', deleteHandler);
    li.appendChild(checkBox)
    li.appendChild(sTag)
    li.appendChild(newBtn);
    ul.appendChild(li);
}

// タスク追加用の要素取得
const inpTask = document.getElementById('form2');
const formTask = document.getElementById('formTask');
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
const ulTask = document.getElementById('tasks');
const btns = document.querySelectorAll('.del-task');

// 新しいタスクの追加処理
formTask.addEventListener('submit', function(e){
    e.preventDefault()
    const task = inpTask.value;
    const cleanTask = task.trim();
    if(cleanTask === '') {
        const err = document.querySelector('#error');
        err.style.display='block';
        err.innerHTML = "You Must Enter A valid Task !";
        window.setTimeout(function(){
            err.style.display='none';
        },2000);
        return;
    }
    if(ulList.childElementCount == 0) {
        const err = document.querySelector('#error');
        err.style.display='block';
        err.innerHTML = " Enter A list first ";
        window.setTimeout(function(){
            err.style.display='none';
        },2000);
        return;
    }
    sendData('/tasks/create',{'description':cleanTask, 
    'list_id':window.location.pathname.split('/')[2]}).then(data=>{
        if(data.error) {
            const err = document.querySelector('#error');
            err.style.display='block';
            err.innerHTML = data.error;
            return;
        }
        addTask(data, ulTask)
    })
});

// チェックボックスにイベントを追加
checkboxes.forEach(ele=>{
    ele.addEventListener('change',updateHandler);   
});

// タスク削除ボタンにイベントを追加
btns.forEach(btn=>{
    btn.addEventListener('click', deleteHandler);
})
```

### JS

```php:
input.value.trim()：入力された文字（スペースを除く）を取り出す。

document.createElement("li")：新しい「リスト」を作り

li.textContent = text : 文字を入れる

削除ボタンを作る
const delBtn = document.createElement("button");
delBtn.textContent = "削除";
delBtn.addEventListener("click", function() {

li.appendChild(delBtn)：ToDoの横に削除ボタンをくっつける。
list.appendChild(li)：作ったToDoを画面に追加する。
input.value = ""：入力欄を空っぽに戻す。

チェックボックスを作る
const checkbox = document.createElement("input");
checkbox.type = "checkbox";

チェックが「入ったら」取り消し線を表示。
チェックを「外したら」元に戻す。
checkbox.addEventListener("change", function () {
  if (checkbox.checked) {
    li.style.textDecoration = "line-through";  // 打ち消し線を付ける
  } else {
    li.style.textDecoration = "none";          // 線を消す
  }
});

li.prepend(checkbox);  // liの先頭にチェックボックスを追加

```