Фильтр задач не работает - список задач с шаблоном MVC с использованием классов es6 - PullRequest
1 голос
/ 26 января 2020

Я пытаюсь написать проект списка задач с чистым JS с использованием шаблона MVC. Это мой первый проект с MVC, и у меня есть реальная проблема, которую я не могу решить. У меня есть три кнопки, каждая кнопка получает значение в качестве значения фильтра (в классе Model) для complete , active и all задачи. значение по умолчанию для фильтра 0 , что относится к кнопке all . когда кнопка завершения активна, новая задача добавляется на страницу, но эта страница предназначена только для полной задачи, и новая задача должна добавляться на все страницы, пока полная страница еще активна. Я пишу несколько методов, чтобы справиться с этим, но они не работают, и я не могу понять, в чем проблема. как я могу решить это?

это мой код:

class Model {
    constructor() {
        this.todoS = [];
        this.filter = 0;
    }

    bindTodoListChanged(callback) {
        this.onTodoListChanged = callback;
    }

    _commit(todoS) {
        this.onTodoListChanged(todoS);
    }

    addTodo(todoText) {
        var todo = {
            id:
                this.todoS.length > 0
                    ? this.todoS[this.todoS.length - 1].id + 1
                    : 0,
            text: todoText,
            complete: false
        };

        this.todoS.push(todo);

        this._commit(this.todoS);
    }

    toggleTodo(id) {
        this.todoS = this.todoS.map(todo =>
            todo.id === id
                ? {
                      id: todo.id,
                      text: todo.text,
                      complete: !todo.complete
                  }
                : todo
        );

        this._commit(this.todoS);
    }

    filterTodo(filter) {
        this.todoS.filter(todo => {
            if (filter === 0) return true;
            return filter === 1 ? !todo.complete : todo.complete;
        });
    }
}

class View {
    constructor() {
        this.form = document.querySelector("#taskForm");
        this.input = document.getElementById("taskInput");
        this.list = document.querySelector("#taskList");
        this.filterBtnS = document.getElementById("filterButtons");
        this.allBtn = document.querySelector(".all");
        this.activeBtn = document.querySelector(".active");
        this.completeBtn = document.querySelector(".complete");
    }

    createElement(tag, className) {
        var element = document.createElement(tag);
        if (className) element.classList.add(className);

        return element;
    }

    getElement(selector) {
        var element = document.querySelector(selector);

        return element;
    }

    get _todoText() {
        return this.input.value;
    }

    _resetInput() {
        this.input.value = "";
    }

    displayTodoS(todoS) {
        // Faster way for clear tasks
        while (this.list.firstChild) {
            this.list.removeChild(this.list.firstChild);
        }

        if (todoS.length !== 0) {
            todoS.forEach(todo => {
                var li = this.createElement("li", "task"),
                    span = this.createElement("span");

                li.id = todo.id;            

                var checkbox = this.createElement("input");
                checkbox.type = "checkbox";
                checkbox.checked = todo.complete;

                if (todo.complete) {
                    var strike = this.createElement("s");
                    strike.textContent = todo.text;
                    span.innerHTML = "";    
                    span.append(strike);
                } else {
                    span.textContent = todo.text;
                }

                li.append(checkbox, span);

                this.list.append(li);
            });
        }
    }

    bindAddTodo(handler) {
        this.form.addEventListener("submit", e => {
            e.preventDefault();

            if (this._todoText) {
                handler(this._todoText);
                this._resetInput();
            } 
        });
    }
    
    bindToggleTodo(handler) {
        this.list.addEventListener("change", event => {
            if (event.target.type === "checkbox") {
                var id = +event.target.parentElement.id;

                handler(id);
            }
        });
    }

    bindFilterTodo(handler) {
        this.filterBtnS.addEventListener("click", e => {
            var filter = +e.target.getAttribute("value");

            handler(filter);
        });
    }

}

class Controller {
    constructor(model, view) {
        this.model = model;
        this.view = view;

        this.model.bindTodoListChanged(this.onTodoListChanged);
        this.view.bindAddTodo(this.handleAddTodo);
        this.view.bindToggleTodo(this.handleToggleTodo);
        this.view.bindFilterTodo(this.handleFilterTodo);

        this.onTodoListChanged(this.model.todoS);
    }

    onTodoListChanged = todoS => {
        this.view.displayTodoS(todoS);
    };

    handleAddTodo = todoText => {
        this.model.addTodo(todoText);
    };

    handleToggleTodo = id => {
        this.model.toggleTodo(id);
    };

    handleFilterTodo = filter => {
        this.model.filterTodo(filter);
    };
}

var app = new Controller(new Model(), new View());
<div id="main">
            <h2>Task List</h2>
            <form id="taskForm">
                <input
                    id="taskInput"
                    placeholder="New task..."
                    autocomplete="off"
                />
                <input class="submit" type="submit" value="Add Task" />
            </form>
            <div id="filterButtons" class="buttons">
                <div class="all" value="0">All</div>
                <div class="active" value="1">Active</div>
                <div class="complete" value="2">Completed</div>
            </div>
            <ul id="taskList"></ul>
        </div>

Ответы [ 2 ]

1 голос
/ 26 января 2020

Проблема в том, что в filterTodo вы просто фильтруете задачи, но не _commit изменение.

Итак

  1. Сохраните фильтр в модели
  2. Переместите фильтр на _commit (чтобы он оставался фильтром для любых других действий, таких как добавление)

class Model {
    constructor() {
        this.todoS = [];
        this.filter = 0;
    }

    bindTodoListChanged(callback) {
        this.onTodoListChanged = callback;
    }

    _commit(todoS = this.todoS) {
        this.onTodoListChanged(todoS.filter(todo => {
            if (this.filter === 0) return true;
            return this.filter === 1 ? !todo.complete : todo.complete;
        }));
    }

    addTodo(todoText) {
        var todo = {
            id:
                this.todoS.length > 0
                    ? this.todoS[this.todoS.length - 1].id + 1
                    : 0,
            text: todoText,
            complete: false
        };

        this.todoS.push(todo);

        this._commit(this.todoS);
    }

    toggleTodo(id) {
        this.todoS = this.todoS.map(todo =>
            todo.id === id
                ? {
                      id: todo.id,
                      text: todo.text,
                      complete: !todo.complete
                  }
                : todo
        );

        this._commit(this.todoS);
    }

    filterTodo(filter) {
        this.filter = filter;
        this._commit();
    }
}

class View {
    constructor() {
        this.form = document.querySelector("#taskForm");
        this.input = document.getElementById("taskInput");
        this.list = document.querySelector("#taskList");
        this.filterBtnS = document.getElementById("filterButtons");
        this.allBtn = document.querySelector(".all");
        this.activeBtn = document.querySelector(".active");
        this.completeBtn = document.querySelector(".complete");
    }

    createElement(tag, className) {
        var element = document.createElement(tag);
        if (className) element.classList.add(className);

        return element;
    }

    getElement(selector) {
        var element = document.querySelector(selector);

        return element;
    }

    get _todoText() {
        return this.input.value;
    }

    _resetInput() {
        this.input.value = "";
    }

    displayTodoS(todoS) {
        // Faster way for clear tasks
        while (this.list.firstChild) {
            this.list.removeChild(this.list.firstChild);
        }

        if (todoS.length !== 0) {
            todoS.forEach(todo => {
                var li = this.createElement("li", "task"),
                    span = this.createElement("span");

                li.id = todo.id;            

                var checkbox = this.createElement("input");
                checkbox.type = "checkbox";
                checkbox.checked = todo.complete;

                if (todo.complete) {
                    var strike = this.createElement("s");
                    strike.textContent = todo.text;
                    span.innerHTML = "";    
                    span.append(strike);
                } else {
                    span.textContent = todo.text;
                }

                li.append(checkbox, span);

                this.list.append(li);
            });
        }
    }

    bindAddTodo(handler) {
        this.form.addEventListener("submit", e => {
            e.preventDefault();

            if (this._todoText) {
                handler(this._todoText);
                this._resetInput();
            } 
        });
    }
    
    bindToggleTodo(handler) {
        this.list.addEventListener("change", event => {
            if (event.target.type === "checkbox") {
                var id = +event.target.parentElement.id;

                handler(id);
            }
        });
    }

    bindFilterTodo(handler) {
        this.filterBtnS.addEventListener("click", e => {
            var filter = +e.target.getAttribute("value");

            handler(filter);
        });
    }

}

class Controller {
    constructor(model, view) {
        this.model = model;
        this.view = view;

        this.model.bindTodoListChanged(this.onTodoListChanged);
        this.view.bindAddTodo(this.handleAddTodo);
        this.view.bindToggleTodo(this.handleToggleTodo);
        this.view.bindFilterTodo(this.handleFilterTodo);

        this.onTodoListChanged(this.model.todoS);
    }

    onTodoListChanged = todoS => {
        console.log(todoS);
        this.view.displayTodoS(todoS);
    };

    handleAddTodo = todoText => {
        this.model.addTodo(todoText);
    };

    handleToggleTodo = id => {
        this.model.toggleTodo(id);
    };

    handleFilterTodo = filter => {
        this.model.filterTodo(filter);
    };
}

var app = new Controller(new Model(), new View());
<div id="main">
  <h2>Task List</h2>
  <form id="taskForm">
    <input id="taskInput" placeholder="New task..." autocomplete="off" />
    <input class="submit" type="submit" value="Add Task" />
  </form>
  <div id="filterButtons" class="buttons">
    <div class="all" value="0">All</div>
    <div class="active" value="1">Active</div>
    <div class="complete" value="2">Completed</div>
  </div>
  <ul id="taskList"></ul>
</div>

https://stackblitz.com/edit/js-1u6dxi

0 голосов
/ 26 января 2020

Я подозреваю, что самые большие проблемы с возвратом значений. Например, это:

handleFilterTodo = filter => {
    this.model.filterTodo(filter);
};

Этот код ничего не возвращает, он только вызывает this.model.filterTodo. В соответствующем методе filterTodo вы создаете новый массив с помощью this.todoS.filter, но нигде не возвращаете его:

filterTodo(filter) {
    this.todoS.filter(todo => {
        if (filter === 0) return true;
        return filter === 1 ? !todo.complete : todo.complete;
    });
}

Вы можете сделать что-то похожее на то, что вы сделали с toggleTodo и map функция здесь:

filterTodo(filter) {
    this.todoS = this.todoS.filter(todo => {
        if (filter === 0) return true;
        return filter === 1 ? !todo.complete : todo.complete;
    });
}

... но это сработает только один раз, так как установка фильтра удалит другие задачи из вашей базы данных.

Из моего понимания кода (не пытаясь это сделать), я бы, вероятно, установил только фильтр, и всякий раз, когда вызывается _commit, передайте отфильтрованную версию задач на основе выбранного фильтра

constructor() {
    ...
    this.possibleFilters = {
        0: () => true,
        1: todo => !todo.completed,
        2: todo => todo.completed
    };
}

filterTodo(filter) {
    this.filter = filter;
}

_commit(todoS) {
    const selectedFilter = this.possibleFilters[this.filter];
    this.onTodoListChanged(todoS.filter(selectedFilter));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...