I'm creating a filtered table in JavaScript. Everything is okay. However, the only line that doesn't seem to work is inputValue = ''. Not sure why it doesn't want to clear the field after filtering is done.
If you replace that with document.querySelector('.form__input').value things seem to work, but I don't want to repeat the same code. I already declared it above as inputValue.
const initValues = [
'Walmart',
'State Grid',
'Sinopec Group',
'China National Petrolium',
'Royal Dutch Shell',
'Toyota Motor',
'Volkswagen',
'BP',
'Exxon Mobil',
'Berkshire Hathaway'
];
const tableCreation = array => {
const tableBody = document.querySelector('.table__body');
document.querySelectorAll('tr').forEach(el => el.parentNode.removeChild(el));
array.forEach(el => {
const row = document.createElement('tr');
const cell = document.createElement('td');
const cellText = document.createTextNode(el);
cell.appendChild(cellText);
row.appendChild(cell);
tableBody.appendChild(row);
});
};
tableCreation(initValues);
const filterTable = event => {
event.preventDefault();
let inputValue = document.querySelector('.form__input').value;
const filtered = initValues.filter(el => el.toLowerCase().includes(inputValue.toLowerCase()));
if (filtered) {
inputValue ? tableCreation(filtered) : tableCreation(initValues);
}
inputValue = '';
};
document.querySelector('.form__button').addEventListener('click', filterTable);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="./css/3.css">
<title>Filtered list</title>
</head>
<body>
<form class="form" id="form">
<label for="filter">Filtered: </label>
<input class="form__input" type="text" id="filter" name="input" placeholder="Insert phrase...">
<button class="form__button" form="form" type="submit">Filter</button>
</form>
<table class="table">
<tbody class="table__body"></tbody>
</table>
<script src="./js/3.js"></script>
</body>
</html>
The variable inputValue is holding only the actual value of the field, it's detached from it.
You can save a reference to the field as a variable and clean the value as follows:
const inp = document.querySelector('.form__input');
inp.value = '';
let inputValue = document.querySelector('.form__input').value;
this line return the string value of the input.
When you are trying inputValue = ''; you are only changing the value of the variable 'inputValue' but not of the input field.
to do this juste save you field as a variable instead of it's value and then change it's value :
let inputField = document.querySelector('.form__input');
const filtered = initValues.filter(el => el.toLowerCase().includes(inputValue.toLowerCase()));
if (filtered) {
inputValue ? tableCreation(filtered) : tableCreation(initValues);
}
inputField.value = '';
You already get value only from inputvalue., but u can't change that value so
get dom instance also
kindly change this code to
const filterTable = event => {
event.preventDefault();
let inputElement = document.querySelector('.form__input'),
inputValue = inputElement.value;
const filtered = initValues.filter(el => el.toLowerCase().includes(inputValue.toLowerCase()));
if (filtered) {
inputValue ? tableCreation(filtered) : tableCreation(initValues);
}
inputElement.value = '';
};
Related
I, not so long ago, went ahead and built an html dependent dropdown which pulls it's data from an array in the js. The dependencies worked perfectly fine until I realized that I needed to add a search function to the dropdown.
I went through different alternatives and to me the simplest option was to use select2 plugin. The problem I am having is that when using select2, it doesn't seem to be triggering the EventListener (Line 43 in JS) I had previously setup for the regular select.
Find below what I have attempted:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/select2#4.0.13/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://cdn.jsdelivr.net/npm/select2#4.0.13/dist/js/select2.min.js"></script>
<title>Document</title>
</head>
<body>
<select id ="level1" style='width: 300px;'></select>
<select id ="level2" style='width: 300px;'></select>
<select id ="level3" style='width: 300px;'></select>
<hr>
<select id ="level4" disabled></select>
<select id ="level5" disabled></select>
<select id ="level6" disabled></select>
<select id ="level7" disabled></select>
<hr>
<h1 id ="level8"></h1>
<script src="betterdd.js"></script>
</body>
</html>
JS: (Select options are found in var myData = [...])
class DropDown {
constructor(data){
this.data = data;
this.targets = [];
}
filterData(filtersAsArray){
return this.data.filter(r => filtersAsArray.every((item,i) => item === r[i]));
}
getUniqueValues(dataAsArray,index){
const uniqueOptions = new Set();
dataAsArray.forEach(r => uniqueOptions.add(r[index]));
return [...uniqueOptions];
}
populateDropDown(el,listAsArray){
el.innerHTML = "";
listAsArray.forEach(item => {
const option = document.createElement("option");
option.textContent = item;
el.appendChild(option);
});
}
createPopulateDropDownFunction(el,elsDependsOn){
return () => {
const elsDependsOnValues = elsDependsOn.length === 0 ? null : elsDependsOn.map(depEl => depEl.value);
const dataToUse = elsDependsOn.length === 0 ? this.data : this.filterData (elsDependsOnValues);
const listToUse = this.getUniqueValues(dataToUse, elsDependsOn.length);
this.populateDropDown(el,listToUse);
}
}
add(options){
//{target: "level2", dependsOn: ["level1"] }
const el = document.getElementById(options.target);
const elsDependsOn = options.dependsOn.length === 0 ? [] : options.dependsOn.map(id => document.getElementById(id));
const eventFunction = this.createPopulateDropDownFunction (el, elsDependsOn);
const targetObject = { el: el, elsDependsOn: elsDependsOn,func: eventFunction};
targetObject.elsDependsOn.forEach(depEl => depEl.addEventListener("change",eventFunction));
this.targets.push(targetObject);
return this;
}
initialize(){
this.targets.forEach(t => t.func());
return this;
}
eazyDropDown(arrayOfIds){
arrayOfIds.forEach((item,i) =>{
const option = {target: item, dependsOn: arrayOfIds.slice(0,i) }
this.add(option);
});
this.initialize();
return this;
}
}
var dd = new DropDown(myData).eazyDropDown(["level1","level2","level3","level4","level5","level6","level7","level8"])
add the following line inside add method :
const eventFunction = this.createPopulateDropDownFunction (el, elsDependsOn);
el.addEventListener("change", (e) => {
eventFunction();
console.log(e.target.value)
})
and remove the following line:
targetObject.elsDependsOn.forEach(depEl => depEl.addEventListener("change",eventFunction));
I have a todo html element whose inner html i want to save in localstorage through use of html but i am unable to figure out how i would do it.
My javascript code
// Load everything
// get DOM Elements
let to_do_input = document.getElementById("todo-input");
let addBtn = document.getElementById("addBtn");
let display = document.getElementsByClassName("display")[0];
// Event Listeners
addBtn.addEventListener("click", () => {
// Add DOM ELements
let list = document.createElement("ul");
let todos = document.createElement("li");
let deleteBtn = document.createElement("button");
deleteBtn.innerText = "Delete";
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list);
list.appendChild(todos);
list.appendChild(deleteBtn);
// list.append(saveBtn);
// Class names
list.classList.add("list");
todos.classList.add("todos");
deleteBtn.classList.add("deleteBtn");
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value;
to_do_input.value = null;
// delete todo
deleteBtn.addEventListener("click", () => {
list.innerHTML = null;
});
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
});
and my html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="This web app provides you with accessibility of todo list" />
<title>Simple To-Do-List</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h2>A Reliable To-Do-App</h2>
<div class="text-input center">
<input type="text" id="todo-input" placeholder="Write you task here.." />
<button type="button" id="addBtn" )>Add</button>
</div>
<div class="display"></div>
</div>
<script src="app.js"></script>
</body>
</html>
I have reviewed from other sites on how to do it but when i tried the array method , it returned numbers or when i tried to push todos into empty array , it didnt do anything. Also i dont know how i will convert the html element into an object to use it while making todo. Rest all the things work fine.
You need to set a array to save list,
So just edit your JS code to :
// Load everything
// get DOM Elements
let to_do_input = document.getElementById('todo-input')
let addBtn = document.getElementById('addBtn')
let display = document.getElementsByClassName('display')[0]
let todoArray = []
// Event Listeners
addBtn.addEventListener('click', () => {
// Add DOM ELements
let list = document.createElement('ul')
let todos = document.createElement('li')
let deleteBtn = document.createElement('button')
deleteBtn.innerText = 'Delete'
// let saveBtn = document.createElement("button");
// saveBtn.innerText = "Save";
display.appendChild(list)
list.appendChild(todos)
list.appendChild(deleteBtn)
// list.append(saveBtn);
// Class names
list.classList.add('list')
todos.classList.add('todos')
deleteBtn.classList.add('deleteBtn')
// saveBtn.classList.add("saveBtn");
// Set values
todos.innerHTML = to_do_input.value
todoArray.push(to_do_input.value)
to_do_input.value = null
// delete todo
deleteBtn.addEventListener('click', () => {
list.innerHTML = null
})
// SAVE todo
// saveBtn.addEventListener("click", () => {
// // let arr = [];
// let savedTodo = arr.push(todos.innerHTML);
// localStorage.setItem("todo", JSON.stringify(savedTodo));
// });
// Set saved todo
localStorage.setItem('todo', JSON.stringify(todoArray))
})
I am writing code that uses data binding to change the innerHTML of an span to the input of the user, but I can't get it to work. What it should do is show the input on the right side of the input field on both the input fields, but it doesn't. Can someone please help me out.
HTML:
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My Frontend Framework</title>
</style>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" bit-data="name"/>
<span bit-data-binding="name" style="margin-left: 1rem;"></span>
</div>
<div>
<label>Lastname:</label>
<input type="text" bit-data="LastName"/>
<span bit-data-binding="LastName" style="margin-left: 1rem;"></span>
</div>
<script src="frontend-framework.js"></script>
</body>
</html>
Javascript:
const createState = (stateObj) => {
return new Proxy(stateObj, {
set(target, property, value) {
target[property] = value;
render();
return true;
}
});
};
const state = createState({
name: '',
lastName: ''
});
const listeners = document.querySelectorAll('[bit-data]');
listeners.forEach((element) => {
const name = element.dataset.model;
element.addEventListener('keyup', (event) => {
state[name] = element.value;
console.log(state);
});
});
const render = () => {
const bindings = Array.from(document.querySelectorAll('[bit-data-binding]')).map(
e => e.dataset.binding
);
bindings.forEach((binding) => {
document.querySelector(`[bit-data-binding=${binding}]`).innerHTML = state[binding];
document.querySelector(`[bit-data=${binding}]`).value = state[binding];
});
}
https://jsfiddle.net/Mauro0294/g3170whc/4/
I made some changes to the fiddle to get the desired result. The problem was with your logic to refer the elements using the dataset attributes, so I tried to simplify it.
Some notable changes :
Updated the data-bit to use lastName instead of LastName. Made it same as your state.
Used getAttribute to get the value of the data-* properties to correctly get the reference.
I think this is what you're looking for:
const createState = (stateObj) => {
return new Proxy(stateObj, {
set(target, property, value) {
target[property] = value;
render();
return true;
}
});
};
const state = createState({
name: '',
lastName: ''
});
const listeners = document.querySelectorAll('[bit-data]');
listeners.forEach((element) => {
const name = element.getAttribute('bit-data');
console.log('here', element.getAttribute('bit-data'), JSON.stringify(element.dataset))
element.addEventListener('keyup', (event) => {
state[name] = element.value;
console.log(state);
});
});
const render = () => {
const bindings = Array.from(document.querySelectorAll('[bit-data-binding]')).map((e) => {
return e.getAttribute('bit-data-binding');
});
//console.log('bindings:', bindings, document.querySelectorAll('[bit-data-binding]'));
(bindings ?? []).forEach((binding) => {
document.querySelector(`[bit-data-binding=${binding}]`).innerHTML = state[binding];
document.querySelector(`[bit-data=${binding}]`).value = state[binding];
});
}
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>My Frontend Framework</title>
</head>
<body>
<div>
<label>Name:</label>
<input type="text" bit-data="name"/>
<span bit-data-binding="name" style="margin-left: 1rem;"></span>
</div>
<div>
<label>Lastname:</label>
<input type="text" bit-data="lastName"/>
<span bit-data-binding="lastName" style="margin-left: 1rem;"></span>
</div>
</body>
</html>
Your main issue is this part:
const bindings = Array.from(document.querySelectorAll('[bit-data-binding]')).map(
e => e.dataset.binding
);
or more specifically e.dataset.binding. Your elements do not a have data-binding attribute, which would be the prerequisite for using dataset.binding. You can use e.getAttribute('bit-data-binding') instead.
But your logic is also flawed: As it currently stands, entering text into an input is pointless, as the state is never updated.
Finally, note that you spell LastName with a capital L in your DOM but lowercased in your state object.
Super new to all of this so this might be some beginner troubleshooting. The list seems to be working where I'm adding a list element to the UL with a checkbox and delete button. When checkbox is checked it puts a line through the text and when the delete button is clicked it deletes the list element. The assignment asks to save to localStorage so that when refreshed, the list items still remain, and I'm getting super confused by this. What I have now seems to be saving my list elements to an array but I don't understand how to get them to save and stay on the page.
const form = document.querySelector('form');
const input = document.querySelector('#todoInput');
const newElement = document.querySelector('ul');
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
newElement.addEventListener('click', function(e) {
if(e.target.tagName === 'BUTTON') {
e.target.parentElement.remove()
}
})
function addToList(text) {
const li = document.createElement('li');
const checkbox = document.createElement('input');
const button = document.createElement('button');
button.innerText = "Delete";
checkbox.type = 'checkbox';
checkbox.addEventListener('change', function() {
li.style.textDecoration = checkbox.checked ? 'line-through' : 'none';
})
li.innerText = text;
li.insertBefore(checkbox, li.firstChild);
li.appendChild(button);
return li;
};
form.addEventListener('submit', function(e) {
e.preventDefault();
const newListItem = addToList(input.value);
input.value = '';
newElement.append(newListItem);
savedToDos.push(newListItem.innerText);
localStorage.setItem('todos', JSON.stringify(savedToDos));
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ToDo App</title>
<link rel="stylesheet" href="app.css">
</head>
<body>
<div>
<h1>Todo List</h1>
<form action="">
<input type="text" id="todoInput" placeholder="Add To Todo List">
<button class="add-button">Add</button>
</form>
<ul id="todoList">
</ul>
</div>
<script src="app.js"></script>
</body>
</html>
It looks like you're failing to populate the DOM when the page loads.
After you retrieve the items from local storage (which you're already doing), loop through the list and add each of them to the DOM:
// After this line, which you've already written:
const savedToDos = JSON.parse(localStorage.getItem('todos')) || [];
// Loop through savedToDos, and for each one, insert a new list:
savedToDos.forEach(function(value) {
const newListItem = addToList(value);
newElement.append(newListItem);
});
Every browser has local storage where we can store data and cookies. just go to the developer tools by pressing F12, then go to the Application tab. In the Storage section expand Local Storage.
this piece of code might help you
// Store Task
function storeTaskInLocalStorage(task) {
let tasks;
if(localStorage.getItem('tasks') === null){
tasks = [];
} else {
tasks = JSON.parse(localStorage.getItem('tasks'));
}
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
I received answers regarding the following contents.
Create Todo list with Javascript
If you enter too many characters, the "state" part will be misaligned. Like in the video, I want to expand the width of the "comment" according to the input value. What should I do?
See also the image.
Have already updated my answer to acomodate this additional bit on the same question :). See this and read the comments on the snippets:
https://stackoverflow.com/a/62356950/4650975
document.addEventListener('DOMContentLoaded', function() {
// 必要なDOM要素を取得。
const addTaskTrigger = document.getElementsByClassName('addTask-trigger')[0];
const addTaskTarget = document.getElementsByClassName('addTask-target')[0];
const addTaskValue = document.getElementsByClassName('addTask-value')[0];
//ID用のインデックスを定義
let nextId = 0;
const addTask = (task,id) => {
// 表のタグを生成する
const tableItem=document.createElement('thead');
const addButton = document.createElement('button');
const removeButton = document.createElement('button');
addButton.style.margin = "5px"; //<------- Added a style here
removeButton.style.margin ="5px"; //<------- Added a style here
// それぞれ作業中、削除という言葉をボタンに入れる
addButton.innerText = '作業中';
removeButton.innerText = '削除';
//ボタンを押したら以下の作業をする
removeButton.addEventListener('click', () => removeTask(removeButton));
// IDを表示するspan要素を作成して tableItem に追加
const idSpan = document.createElement('span');
idSpan.innerText = id;
idSpan.style.marginRight = "20px"; //<------- Added a style here
tableItem.append(idSpan);
const taskSpan = document.createElement('span');
taskSpan.style.width = "60px"; //<------- Added a style here
taskSpan.style.display = "inline-block"; //<------- Added a style here
taskSpan.style.overflow = "hidden"; // <----- This styling for trimming the text if it exceeds certain width
taskSpan.style.textOverflow = "ellipsis"; // <------- This will append a (...) to the exceeding text
taskSpan.innerText = task;
taskSpan.title = task; //If you hover on the text full text will be displayed. In production code, you might like to use fancy tooltips, say, from bootstrap, for this
tableItem.append(taskSpan); //<------- changed this
//入力タスクを表示
addTaskTarget.appendChild(tableItem);
// 作業中ボタンを追加
tableItem.appendChild(addButton);
// 削除ボタンを追加
tableItem.appendChild(removeButton);
};
// 追加ボタンに対して、タスク登録イベントを設定
addTaskTrigger.addEventListener('click', event => {
const task = addTaskValue.value;
addTask(task,nextId ++);
addTaskValue.value = '';
});
});
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel ="stylesheet" href="css/style.css">
<title>Todoリスト</title>
</head>
<body>
<h1>Todoリスト</h1>
<p>
<input type="radio" name="status" value="1" checked="checked">全て
<input type="radio" name="status" value="2">作業中
<input type="radio" name="status" value="3">完了
</p>
<p></p>
<table>
<thead>
<tr>ID コメント 状態</tr>
</thead>
<tbody class ="addTask-target">
<tr>
</tr>
</tbody>
</table>
<h2>新規タスクの追加</h2>
<input class="addTask-value" type="text" />
<button class="addTask-trigger" type="button">追加</button>
<script src="js/main.js"></script>
</body>
</html>