Here is the code
<template>
<div id="left_container" ref="usersContainer">
<button v-for="user in users" :key="user.userID" >{{ user.username }}</button>
</div>
<div id="right_container">
<ul id="messages"></ul>
<div id="bottom_container">
<label id="lt"></label>
<form id="form" #submit.prevent="onSubmit" action="">
<input id="input" v-model="in_msg" autocomplete="off" v-on:input="vChanged"/><button>Send</button>
</form>
</div>
</div>
</template>
<script>
import socket from "../socket"
export default {
name: "MyChat",
components: {
},
data() {
return {
in_msg:'',
users: [],
selectedUser: null,
};
},
methods: {
onSubmit()
{
console.log(this.users);
if(this.selectedUser)
{
var content = this.in_msg;
socket.emit("private message", {
content,
to: this.selectedUser.userID,
});
}
else{
if (this.in_msg) {
socket.emit('chat message', this.in_msg);
this.in_msg = '';
}
}
},
vChanged()
{
socket.emit('on_c');
},
},
created()
{
var messages = document.getElementById('messages');
var lbl_writing = document.getElementById('lt');
socket.on('chat mess', function(msg) {
var item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
socket.on("private message", ({ content, from }) => {
var msg = from + " : " + content;
var item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
socket.on('chat message not', function(msg) {
lbl_writing.textContent = msg;
});
socket.on('users',function(users)
{
this.users = [...users];
console.log(this.users);
//const dlv = document.getElementById('left_container');
//dlv.innerHTML = '';
// this.users.forEach(user => {
// const button = document.createElement('button');
// button.innerHTML = user.username;
// //button.addEventListener('click',this.onClick(user));
// //dlv.appendChild(button);
// });
});
socket.on('user connected',function(user)
{
this.users.push(user);
// const dlv = document.getElementById('left_container');
// //dlv.innerHTML = '';
// const button = document.createElement('button');
// button.innerHTML = user.username;
// //button.addEventListener('click',this.onClick(user));
// dlv.appendChild(button);
})
}
};
</script>
<style scoped>
#left_container {width: 19vw;position: absolute;top: 0;bottom:0; background-color: white;border: dashed black;display: flex;flex-direction: column;}
#right_container {width: 80vw;display: flex; background-color:white;flex-direction: column;position: absolute;margin-left: 19.5vw;top:0;bottom: 0;}
#bottom_container { display: flex; position: absolute; bottom: 0;left: 0;right: 0; flex-direction: column;}
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#pv { background-color: red;color: #fff;}
#lt { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#lo { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
.user-button {
background-color: blue;
color: white;
}
</style>
In the template part the v-for on buttons isn't displaying anything because I'm unable to update data() -> users array.
We can see in the socket.on('users') function the array is supposed to be updated but the users array isn't updated after the function is finished. It comes back to empty array after the ending bracket of socket.on('users'...)
Vue allows for the page elements to react to variable changes rather than explicitly modifying the DOM with getElementById / createElement / appendChild.
Similar to how you are managing the display of users, use Vue data for an array of messages and a string for the label text.
<template>
<div id="left_container" ref="usersContainer">
<button v-for="user in users" :key="user.userID" >{{ user.username }}</button>
</div>
<div id="right_container">
<ul id="messages">
<!-- using the array index as a key is not recommended, but
will work for simple array appending -->
<li v-for="(message, index) of messages" :key="index">
{{ message.msg }}
</li>
</ul>
<div id="bottom_container">
<label id="lt">
{{ lbl_writing }}
</label>
<form id="form" #submit.prevent="onSubmit" action="">
<input id="input" v-model="in_msg" autocomplete="off" v-on:input="vChanged"/><button>Send</button>
</form>
</div>
</div>
</template>
Then the script just needs to modify the messages and lbl_writing variables, rather than modifying the elements directly
<script>
import socket from "../socket"
export default {
name: "MyChat",
data() {
return {
in_msg:'',
users: [],
selectedUser: null,
messages: [],
lbl_writing: null,
};
},
mounted()
{
socket.on('chat mess', function(msg) {
this.messages.push({ msg })
});
socket.on("private message", ({ content, from }) => {
var msg = from + " : " + content;
this.messages.push({ content, from, msg })
});
socket.on('chat message not', function(msg) {
this.lbl_writing = msg
});
socket.on('users',function(users){
this.users = [...users];
console.log(this.users);
});
socket.on('user connected',function(user)
{
this.users.push(user);
})
}
};
</script>
Related
I am doing a to-do list web page using HTML/CSS/JavaScript. I did only up to display the content entered by users with priority bases (high/low/medium). I am not able to do the last section (select to get specific task).
The main concept is, If the user clicks on the high/medium/low buttons, It should display the corresponding priority list only. If the user clicks the high priority button then display only high priority list data.
High priority (background -red), medium priority (background -yellow), low priority (background -green). You can display that last section anywhere, further, we can do modifications.
Below you can see my code. Please, can you help me?
const lists = document.getElementsByClassName('task-list')[0];
const radios = document.getElementsByName('rgPrior');
function onClick()
{
for (let i = 0, length = radios.length; i < length; i++)
{
if (radios[i].checked)
{
btn_selected_color = radios[i].value + 'P';
break;
}
}
const task = document.getElementById('item').value;
// Add it to the HTML
addTodo(task, btn_selected_color);
// Save it to localStorage
let data = JSON.parse(localStorage.getItem('todo')) || [];
data.push([
task,
btn_selected_color
]);
localStorage.setItem('todo', JSON.stringify(data));
}
function addTodo(todo, priority)
{
let entry = document.createElement('li');
let close = document.createElement('button');
entry.className = priority;
close.className = 'close-btn';
close.innerText = 'X';
close.addEventListener('click', function(e)
{
// Delete from localstorage
let data = JSON.parse(localStorage.getItem('todo'));
let index = data.indexOf([
todo,
priority
]);
data.splice(index, 1);
localStorage.setItem('todo', JSON.stringify(data));
// Delete HTML
this.parentElement.remove();
});
entry.appendChild(close);
entry.appendChild(document.createTextNode(todo));
lists.appendChild(entry);
}
// When the page is loaded, get from localStorage
window.addEventListener('load', function()
{
const data = JSON.parse(localStorage.getItem('todo'));
data.forEach(function(task)
{
addTodo(...task);
});
});
.hiP {background-color : red;}
.medP {background-color: #ffbf00;}
.lowP {background-color: green;}
.ch5 {padding-left: 30px;}
#box{
width: 500px;
padding: 20px;
margin: 20px;
margin-left: auto;
margin-right: auto;
background-color: white;
border-radius: 40px;
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, .5);
}
#box1{
text-align: center;
width: 400px;
padding: 30px;
margin: 30px;
margin-left: auto;
margin-right: auto;
/* background-color: #140101; */
/* background-color: #37283b; */
background-image: linear-gradient(rgb(218, 76, 76),#d1b562, rgb(122, 233, 122));
border-radius: 20px;
}
#box2{
width: 400px;
padding: 30px;
margin: 30px;
margin-top: auto;
margin-left: auto;
margin-right: auto;
/* background-image: linear-gradient(red,#ffbf00, green); */
/* background-color: rgb(160, 10, 122); */
background-color: #c1d7f5;
border-radius: 20px;
}
#box3{
text-align: center;
width: 400px;
padding: 30px;
margin: 30px;
margin-top: auto;
margin-left: auto;
margin-right: auto;
/* background-color: rgb(22, 240, 22); */
background-color: #93f6c6;
border-radius: 20px;
}
.header{
/* background-color: #5a9cda; */
background-color: #38045a;
color: white ;
padding: 20px ;
margin-top: -10px;
margin: -10px;
font-size: large;
}
.footer{
position: fixed;
padding: 10px 10px 0px 10px;
margin: -10px;
font-size: large;
color: white;
bottom: 0;
width: 100%;
height: 40px;
/* background: #5a9cda; */
background-color: #04267c;
}
.button1 {
background-color: white;
color: black;
border: 2px solid #f44336;
border-radius: 10px;
}
.button1:hover {
background-color: #f44336;
color: white;
}
.button2 {
background-color: white;
color: black;
border: 2px solid #ffbf00;
border-radius: 10px;
}
.button2:hover {
background-color: #ffbf00;
color: white;
}
.button3 {
background-color: white;
color: black;
border: 2px solid green;
border-radius: 10px;
}
.button3:hover {
background-color: green;
color: white;
}
.button4 {
background-color: white;
color: black;
border: 2px solid green;
border-radius: 10px;
}
.button4:hover {
background-color: green;
color: white;
}
<div class="header" align="center">
<header>MY TO_DO LIST</header>
</div>
<div id="box">
<div id="box1" >
<form >
<label for="txtAdd" style="font-size: 20px;color: white;"><b> Enter New thing to do: </b></label>
<input name="txtAdd" type="text" id="item" />
</form>
<p style="font-size: 20px; color: white;"><b> Set Priority </b></p>
<p>
<label style="color: #ce1126; font-size: 20px;"><input type="radio" name="rgPrior" value="hi" id="rgPrior_0"/>HIGH</label>
<label style="color: #ce1126; font-size: 20px;"><input type="radio" name="rgPrior" value="med" id="rgPrior_1"/>MEDIUM</label>
<label style="color: #ce1126; font-size: 20px;"><input type="radio" name="rgPrior" value="low" id="rgPrior_2"/>LOW</label>
</p>
<input type="button" name="btnAdd" class="button4" id="btnAdd" value="Save The Task" onClick="onClick()" />
</div>
<p style="text-align: center; color: rgba(3, 95, 30, 0.767); font-size: 20px;"><b> WORK TO-DO </b></p>
<div id="box2">
<ul class="task-list"> </ul>
</div>
<div id="box3">
<p style" -20px;color: rgb(56, 4, 155); font-size: 20px;">Select to get Specific tasks</p>
<button class="button1">HIGH</button>
<button class="button2">MEDIUM</button>
<button class="button3">LOW</button>
</div>
</div>
<div class="footer" align="center" >
<marquee direction="right" >ThankYou, Visit again</marquee>
</div>
Array.prototype.filter()
Here's a working example of how to filter a list:
const items = [{
value: 'Item 1',
className: 'low',
}, {
value: 'Item 2',
className: 'high',
}, {
value: 'Item 3',
className: 'low',
}, {
value: 'Item 4',
className: 'medium',
}, {
value: 'Item 5',
className: 'medium',
}];
const ul = document.getElementById('filtered-list');
const button1 = document.getElementById('high-priority');
const button2 = document.getElementById('medium-priority');
const button3 = document.getElementById('low-priority');
const createListItems = function createListItems(filteredList) {
ul.innerHTML = '';
filteredList.map((item) => {
const li = document.createElement('li');
li.append(item.value);
li.className = item.className;
ul.append(li);
});
};
const click = function click(event) {
event.preventDefault();
const t = this;
const filtered = items.filter(item => item.className === t.priority);
createListItems(filtered);
}
button1.addEventListener('click', click.bind({ priority: 'high' }));
button2.addEventListener('click', click.bind({ priority: 'medium' }));
button3.addEventListener('click', click.bind({ priority: 'low' }));
createListItems(items);
.high { background-color: red; }
.medium { background-color: yellow; }
.low { background-color: green; }
<ul id="filtered-list"></ul>
<button id="high-priority" type="button">High Priority</button>
<button id="medium-priority" type="button">Medium Priority</button>
<button id="low-priority" type="button">Low Priority</button>
Below is how it could look in your code. Just remove onClick from your HTML otherwise it will add the item twice.
const lists = document.getElementsByClassName('task-list')[0];
const radios = [...document.getElementsByName('rgPrior')];
const btnAdd = document.getElementById('btnAdd');
const button1 = document.getElementsByClassName('button1')[0];
const button2 = document.getElementsByClassName('button2')[0];
const button3 = document.getElementsByClassName('button3')[0];
const items = [];
const addTodo = function addTodo(todo, priority) {
const entry = document.createElement('li');
const close = document.createElement('button');
items.push({
value: todo,
className: priority,
});
entry.className = priority;
close.className = 'close-btn';
close.innerText = 'X';
close.addEventListener('click', function click(event) {
event.preventDefault();
// Delete from localstorage
const data = JSON.parse(localStorage.getItem('todo'));
const index = data.indexOf([
todo,
priority,
]);
data.splice(index, 1);
localStorage.setItem('todo', JSON.stringify(data));
// Delete HTML
this.parentElement.remove();
});
entry.appendChild(close);
entry.appendChild(document.createTextNode(todo));
lists.appendChild(entry);
};
const onClick = function onClick() {
let btnSelectedColor;
radios.map((radio) => {
if (radio.checked) {
btnSelectedColor = `${radio.value}P`;
}
return false;
});
const task = document.getElementById('item').value;
// Add it to the HTML
addTodo(task, btnSelectedColor);
// Save it to localStorage
const data = JSON.parse(localStorage.getItem('todo')) || [];
data.push([task, btnSelectedColor]);
localStorage.setItem('todo', JSON.stringify(data));
};
btnAdd.addEventListener('click', onClick);
const createListItems = function createListItems(filteredList) {
lists.innerHTML = '';
filteredList.map((item) => {
const li = document.createElement('li');
li.append(item.value);
li.className = item.className;
lists.append(li);
return false;
});
};
const filterItems = function filterItems(event) {
event.preventDefault();
const t = this;
const filtered = items.filter((item) => item.className === t.priority);
createListItems(filtered);
};
button1.addEventListener('click', filterItems.bind({ priority: 'hiP' }));
button2.addEventListener('click', filterItems.bind({ priority: 'medP' }));
button3.addEventListener('click', filterItems.bind({ priority: 'lowP' }));
// When the page is loaded, get from localStorage
window.addEventListener('load', () => {
const data = JSON.parse(localStorage.getItem('todo'));
data.forEach((task) => {
addTodo(...task);
});
});
const addBtn = document.querySelector(".add");
const modal = document.querySelector(".modal__container");
const library = document.querySelector(".library__container");
const submitBook = document.querySelector(".add__book");
const deleteBtn = document.querySelector(".fas fa-trash-alt");
//Modal inputs
const modalTitle = document.querySelector("#title");
const modalAuthor = document.querySelector("#author");
const modalPages = document.querySelector("#pages");
const isRead = document.querySelector("#read-status");
//Toggle Modal
const hideModal = () => {
modal.style.display = "none";
};
const showModal = () => {
modal.style.display = "block";
const cancel = document.querySelector(".cancel");
cancel.addEventListener("click", (e) => {
e.preventDefault();
hideModal();
});
};
addBtn.addEventListener("click", showModal);
let myLibrary = [];
let index = 0;
function Book(title, author, pages, read) {
this.title = title,
this.author = author,
this.pages = pages,
this.read = read
}
submitBook.addEventListener("click", addBookToLibrary);
function addBookToLibrary(e) {
e.preventDefault();
let bookTitle = modalTitle.value;
let bookAuthor = modalAuthor.value;
let bookPages = modalPages.value;
let bookStatus = isRead.checked;
//Display error message if inputs are empty
if (bookTitle === "" || bookAuthor === "" || bookPages === "") {
const errorMessage = document.querySelector(".error__message--container");
hideModal();
errorMessage.style.display = "block";
const errorBtn = document.querySelector(".error-btn");
errorBtn.addEventListener("click", () => {
errorMessage.style.display = "none";
showModal();
})
} else {
let book = new Book(bookTitle, bookAuthor, bookPages, bookStatus);
myLibrary.push(book);
hideModal();
render();
}
}
function render() {
library.innerHTML = "";
for (let i = 0; i < myLibrary.length; i++) {
library.innerHTML +=
'<div class="book__container">' +
'<div class="book">' +
'<div class="title__content">' +
'<span class="main">Title : </span><span class="book__title">' +` ${myLibrary[i].title}`+'</span>' +
'</div>' +
'<div class="author__content">' +
'<span class="main">Author : </span><span class="book__author">'+` ${myLibrary[i].author}`+'</span>' +
'</div>' +
'<div class="pages__content">' +
'<span class="main">Pages : </span><span class="book__pages">'+` ${myLibrary[i].pages}`+'</span>' +
'</div>' +
'<div class="book__read-elements">' +
'<span class="book__read">I read it</span>' +
'<i class="fas fa-check"></i>' +
'<a href="#"><i class="fas fa-times"></i>' +
'<i class="fas fa-trash-alt"></i>' +
'</div>' +
'</div>' +
'</div>'
readStatus(myLibrary[i].checked)
}
modalTitle.value = "";
modalAuthor.value = "";
modalPages.value = "";
isRead.checked = false;
}
function readStatus(bookStatus) {
const bookStatusContainer = document.querySelector(".book__read");
if (bookStatus) {
bookStatusContainer.classList.add("yes");
bookStatusContainer.textContent = "I read it";
bookStatusContainer.style.color = "rgb(110, 176, 120)";
} else {
bookStatusContainer.classList.add("no");
bookStatusContainer.textContent = "I have not read it";
bookStatusContainer.style.color = "rgb(194, 89, 89)";
}
}
#import url('https://fonts.googleapis.com/css2?family=Poppins:wght#300;400;600&display=swap');
:root {
--light-gray: #dededef3;
--title-color: #333756;
--main-color: #c6c6c6f3;
}
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
font-family: 'Poppins', sans-serif;
background-color: var(--light-gray);
}
header {
text-align: center;
padding-top: 4rem;
color: var(--title-color);
text-transform: uppercase;
letter-spacing: 4px;
}
button {
margin: 1rem;
padding: 0.8rem 2rem;
font-size: 14px;
border-radius: 25px;
background: white;
color: #333756;
font-weight: 600;
border: none;
cursor: pointer;
transition: 0.6s all ease;
}
:focus {
/*outline: 1px solid white;*/
}
button:hover {
background: var(--title-color);
color: white;
}
.add__book:hover,
.cancel:hover {
background: var(--main-color);
color: var(--title-color)
}
.all,
.books__read,
.books__not-read {
border-radius: 0;
text-transform: uppercase;
letter-spacing: 0.1rem;
background: var(--light-gray);
border-bottom: 4px solid var(--title-color)
}
.library__container {
display: flex;
justify-content: center;
flex-wrap: wrap;
}
.book__container {
display: flex;
margin: 2rem 2rem;
}
.modal__container {
display: none;
position: fixed;
z-index: 4;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
padding-top: 0px;
}
.book,
.modal {
padding: 2rem 2rem;
border-radius: 15px;
background: #333756;
line-height: 3rem;
}
.modal {
position: relative;
width: 50%;
margin: 0 auto;
margin-top: 8rem;
}
.modal__content {
display: flex;
flex-direction: column;
}
label {
color: white;
margin-right: 1rem;
}
input {
padding: 0.5rem;
font-size: 14px;
}
.book__read-elements {
display: flex;
justify-content: space-between;
}
.main,
i {
color: white;
pointer-events: none;
margin: 0.5rem;
}
.book__title,
.book__author,
.book__pages,
.book__read {
color: var(--main-color)
}
.error__message--container {
display: none;
position: fixed;
z-index: 4;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
}
.error__message--modal {
position: relative;
margin: 0 auto;
margin-top: 10rem;
width:40%;
}
.error {
display: flex;
flex-direction: column;
align-items: center;
color: rgb(101, 3, 3);
font-size: 20px;
font-weight: bold;
background: rgb(189, 96, 96);
padding: 3rem 5rem;
border-radius: 10px;
}
.error-btn {
color: rgb(101, 3, 3);
font-weight: bold;
}
.error-btn:hover {
color: white;
background: rgb(101, 3, 3);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.1/css/all.min.css" integrity="sha256-2XFplPlrFClt0bIdPgpz8H7ojnk10H69xRqd9+uTShA=" crossorigin="anonymous" />
<link rel="stylesheet" href="styles.css">
<title>Library</title>
</head>
<body>
<header>
<h1>My Library</h1>
<button class="add">Add New Book</button>
<div class="buttons">
<button class="all">View All</button>
<button class="books__read">Read</button>
<button class="books__not-read">Not Read</button>
</div>
</header>
<div class="error__message--container">
<div class="error__message--modal">
<div class="error">
<p>Complete the form!</p>
<button class ="error-btn">Ok</button>
</div>
</div>
</div>
<!--Modal-->
<form class="modal__container">
<div class="modal">
<div class="modal__content">
<label for="">Title:</label>
<input type="text" id="title">
</div>
<div class="modal__content">
<label for="">Author:</label>
<input type="text" id="author">
</div>
<div class="modal__content">
<label for="">Pages:</label>
<input type="number" id="pages">
</div>
<div>
<label for="read-status">Check the box if you've read this book</label>
<input type="checkbox" id="read-status" value ="check">
</div>
<button class="add__book">Add</button>
<button class="cancel">Cancel</button>
</div>
</form>
<!--End of Modal-->
<div class="library__container"></div>
<script src="script.js"></script>
</body>
</html>
I'm new to OOP and I'm struggling.
I'm building a library where you can add a book with the title, author nr of pages and if you've read it or not. When I add the first book if I check the box it displays that to book is not read(which is false). When I add a new book the read functionality is not applied to that book at all. I have no idea how to fix it
In this function you are checking the status if isRead which is incorrect.
Do this
Call the readStatus function inside the for loop
Pass the current parameter readStatus(myLibrary[i].checked)
Modify readStatus as shown below
function readStatus(status) {
const bookReadStatus = document.querySelector(".book__read");
if (status) {
bookReadStatus.classList.add("yes");
bookReadStatus.textContent = "I read it";
bookReadStatus.style.color = "rgb(110, 176, 120)";
} else {
bookReadStatus.classList.add("no");
bookReadStatus.textContent = "I have not read it";
bookReadStatus.style.color = "rgb(194, 89, 89)";
}
}
I have got a problem at the coding project I am doing, as I formatted the numbers to be shown nicer, I ran into a problem. The webpage when it loads shows NaN. undefined in the total income/expenses at the top. I can't figure out what is the problem.
//Budget controller
var budgetController = (function() {
var Expense = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
this.percentage = -1;
};
Expense.prototype.calcPercentage = function(totalIncome) {
if (totalIncome > 0) {
this.percentage = Math.round((this.value / totalIncome) * 100);
} else {
this.percentage = -1;
}
};
Expense.prototype.getPercentage = function() {
return this.percentage;
};
var Income = function(id, description, value) {
this.id = id;
this.description = description;
this.value = value;
};
var calculateTotal = function(type) {
var sum = 0;
data.allItems[type].forEach(function(cur) {
sum = sum + cur.value;
});
data.totals[type] = sum;
};
var data = {
allItems: {
exp: [],
inc: []
},
totals: {
exp: 0,
inc: 0
},
budget: 0,
percentage: -1
};
return {
addItem: function(type, des, val) {
var newItem, ID;
//create new iD
if (data.allItems[type].length > 0) {
ID = data.allItems[type][data.allItems[type].length - 1].id + 1;
} else {
ID = 0;
}
//CREATe new item, if it is inc or exp
if (type === 'exp') {
newItem = new Expense(ID, des, val);
} else if (type === 'inc') {
newItem = new Income(ID, des, val);
}
// Push all items into data structure and return the new element
data.allItems[type].push(newItem);
return newItem;
},
deleteItem: function(type, id) {
var ids, index;
ids = data.allItems[type].map(function(current) {
return current.id;
});
index = ids.indexOf(id);
if (index !== -1) {
data.allItems[type].splice(index, 1);
}
},
calculateBudget: function() {
// calculate the total income and expenses
calculateTotal('exp');
calculateTotal('inc');
// calculate the budget: income - expenses
data.budget = data.totals.inc - data.totals.exp;
if (data.totals.inc > 0) {
data.percentage = Math.round((data.totals.exp / data.totals.inc) * 100);
} else {
data.percentage = -1;
}
},
calculatePercentages: function() {
data.allItems.exp.forEach(function(cur) {
cur.calcPercentage(data.totals.inc);
});
},
getPercentages: function() {
var allPerc = data.allItems.exp.map(function(cur) {
return cur.getPercentage();
});
return allPerc;
},
getBudget: function() {
return {
budget: data.budget,
totalInc: data.totals.inc,
totalExp: data.totals.exp,
percentage: data.percentage
};
}
};
})();
// UI Controller
var UIController = (function() {
var DOMstrings = {
inputType: '.add__type',
inputDescription: '.add__description',
inputValue: '.add__value',
inputBtn: '.add__btn',
incomeContainer: '.income__list',
expensesContainer: '.expenses__list',
budgetLabel: '.budget__value',
incomeLabel: '.budget__income--value',
expensesLabel: '.budget__expenses--value',
percentageLabel: '.budget__expenses--percentage',
container: '.container',
expensesPercLabel: '.item__percentage',
dateLabel: '.budget__title--month'
};
var formatNumber = function(num, type) {
var numSplit, int, dec, type;
/* + or - befofe a number
on 2 decimals
comma seperating thousands
*/
num = Math.abs(num);
num = num.toFixed(2);
numSplit = num.split('.');
int = numSplit[0];
if (int.length > 3) {
int = int.substr(0, int.length - 3) + ',' + int.substr(int.length - 3, 3); //input 23510, output 23,510
}
dec = numSplit[1];
return (type === 'exp' ? '-' : '+') + ' ' + int + '.' + dec;
};
var nodeListForEach = function(list, callback) {
for (var i = 0; i < list.length; i++) {
callback(list[i], i);
}
};
return {
getInput: function() {
return {
type: document.querySelector(DOMstrings.inputType).value, //will be either inc or exp
description: document.querySelector(DOMstrings.inputDescription).value,
value: parseFloat(document.querySelector(DOMstrings.inputValue).value)
};
},
addListItem: function(obj, type) {
var html, newHtml, element;
// Create HTML string with placeholder text
if (type === 'inc') {
element = DOMstrings.incomeContainer;
html = '<div class="item clearfix" id="inc-%id%"> <div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
} else if (type === 'exp') {
element = DOMstrings.expensesContainer;
html = '<div class="item clearfix" id="exp-%id%"><div class="item__description">%description%</div><div class="right clearfix"><div class="item__value">%value%</div><div class="item__percentage">21%</div><div class="item__delete"><button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button></div></div></div>';
}
// Replace the placeholder text with some actual data
newHtml = html.replace('%id%', obj.id);
newHtml = newHtml.replace('%description%', obj.description);
newHtml = newHtml.replace('%value%', formatNumber(obj.value, type));
// Insert the HTML into the DOM
document.querySelector(element).insertAdjacentHTML('beforeend', newHtml);
},
deleteListItem: function(selectorID) {
var el = document.getElementById(selectorID);
el.parentNode.removeChild(el);
},
clearFields: function() {
var fields, fieldsArr;
fields = document.querySelectorAll(
DOMstrings.inputDescription + ',' + DOMstrings.inputValue
);
fieldsArr = Array.prototype.slice.call(fields);
fieldsArr.forEach(function(current, index, array) {
current.value = "";
});
fieldsArr[0].focus();
},
displayBudget: function(obj) {
var type;
obj.budget > 0 ? type = 'inc' : type = 'exp';
document.querySelector(DOMstrings.budgetLabel).textContent = formatNumber(obj.budget, type);
document.querySelector(DOMstrings.incomeLabel).textContent = formatNumber(obj.totalInc, 'inc');
document.querySelector(DOMstrings.expensesLabel).textContent = formatNumber(obj.totalExp, 'exp');
if (obj.percentage > 0) {
document.querySelector(DOMstrings.percentageLabel).textContent = obj.percentage + '%';
} else {
document.querySelector(DOMstrings.percentageLabel).textContent = '---';
}
},
displayPercentages: function(percentages) {
var fields = document.querySelectorAll(DOMstrings.expensesPercLabel);
nodeListForEach(fields, function(current, index) {
if (percentages[index] > 0) {
current.textContent = percentages[index] + '%';
} else {
current.textContent = '---';
}
});
},
getDOMstrings: function() {
return DOMstrings;
}
};
})();
// App Controller - global
var controller = (function(budgetCtrl, UICtrl) {
var setupEventListeners = function() {
var DOM = UICtrl.getDOMstrings();
document.querySelector(DOM.inputBtn).addEventListener('click', ctrlAddItem);
document.addEventListener('keypress', function(event) {
if (event.keyCode === 13 || event.which === 13) {
ctrlAddItem();
}
});
document.querySelector(DOM.container).addEventListener('click', ctrlDeleteItem);
};
var updateBudget = function() {
// 1. Calculate the budget
budgetCtrl.calculateBudget();
// 2. Return the budget
var budget = budgetCtrl.getBudget();
// 3. Display the budget on the UI
UICtrl.displayBudget(budget);
};
var updatePercentages = function() {
// 1. Calculate percentages
budgetCtrl.calculatePercentages();
// 2. Read percentages from the budget controller
var percentages = budgetCtrl.getPercentages();
// 3. Update the UI with the new percentages
UICtrl.displayPercentages(percentages);
};
var ctrlAddItem = function() {
var input, newItem;
// 1. Get the field input data
input = UICtrl.getInput();
if (input.description !== "" && !isNaN(input.value) && input.value > 0) {
// 2. Add the item to the budget controller
newItem = budgetCtrl.addItem(input.type, input.description, input.value);
// 3. Add the item to the UI
UICtrl.addListItem(newItem, input.type);
// 4. Clear the fields
UICtrl.clearFields();
// 5. Calculate and update budget
updateBudget();
// 6. Calculate and update percentages
updatePercentages();
}
};
var ctrlDeleteItem = function(event) {
var itemID, splitID, type, ID;
itemID = event.target.parentNode.parentNode.parentNode.parentNode.id;
if (itemID) {
//inc-1
splitID = itemID.split('-');
type = splitID[0];
ID = parseInt(splitID[1]);
// 1. delete the item from the data structure
budgetCtrl.deleteItem(type, ID);
// 2. Delete the item from the UI
UICtrl.deleteListItem(itemID);
// 3. Update and show the new budget
updateBudget();
// 4. Calculate and update percentages
updatePercentages();
}
};
return {
init: function() {
console.log('App has started');
UICtrl.displayBudget({
budget: 0,
totalIncome: 0,
totalExpenses: 0,
percentage: -1
});
setupEventListeners();
}
};
})(budgetController, UIController);
controller.init();
/**********************************************
*** GENERAL
**********************************************/
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.clearfix::after {
content: "";
display: table;
clear: both;
}
body {
color: #555;
font-family: Open Sans;
font-size: 16px;
position: relative;
height: 100vh;
font-weight: 400;
}
.right {
float: right;
}
.red {
color: #FF5049 !important;
}
.red-focus:focus {
border: 1px solid #FF5049 !important;
}
/**********************************************
*** TOP PART
**********************************************/
.top {
height: 40vh;
background-image: linear-gradient(rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.35)), url(back.png);
background-size: cover;
background-position: center;
position: relative;
}
.budget {
position: absolute;
width: 350px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #fff;
}
.budget__title {
font-size: 18px;
text-align: center;
margin-bottom: 10px;
font-weight: 300;
}
.budget__value {
font-weight: 300;
font-size: 46px;
text-align: center;
margin-bottom: 25px;
letter-spacing: 2px;
}
.budget__income,
.budget__expenses {
padding: 12px;
text-transform: uppercase;
}
.budget__income {
margin-bottom: 10px;
background-color: #28B9B5;
}
.budget__expenses {
background-color: #FF5049;
}
.budget__income--text,
.budget__expenses--text {
float: left;
font-size: 13px;
color: #444;
margin-top: 2px;
}
.budget__income--value,
.budget__expenses--value {
letter-spacing: 1px;
float: left;
}
.budget__income--percentage,
.budget__expenses--percentage {
float: left;
width: 34px;
font-size: 11px;
padding: 3px 0;
margin-left: 10px;
}
.budget__expenses--percentage {
background-color: rgba(255, 255, 255, 0.2);
text-align: center;
border-radius: 3px;
}
/**********************************************
*** BOTTOM PART
**********************************************/
/***** FORM *****/
.add {
padding: 14px;
border-bottom: 1px solid #e7e7e7;
background-color: #f7f7f7;
}
.add__container {
margin: 0 auto;
text-align: center;
}
.add__type {
width: 55px;
border: 1px solid #e7e7e7;
height: 44px;
font-size: 18px;
color: inherit;
background-color: #fff;
margin-right: 10px;
font-weight: 300;
transition: border 0.3s;
}
.add__description,
.add__value {
border: 1px solid #e7e7e7;
background-color: #fff;
color: inherit;
font-family: inherit;
font-size: 14px;
padding: 12px 15px;
margin-right: 10px;
border-radius: 5px;
transition: border 0.3s;
}
.add__description {
width: 400px;
}
.add__value {
width: 100px;
}
.add__btn {
font-size: 35px;
background: none;
border: none;
color: #28B9B5;
cursor: pointer;
display: inline-block;
vertical-align: middle;
line-height: 1.1;
margin-left: 10px;
}
.add__btn:active {
transform: translateY(2px);
}
.add__type:focus,
.add__description:focus,
.add__value:focus {
outline: none;
border: 1px solid #28B9B5;
}
.add__btn:focus {
outline: none;
}
/***** LISTS *****/
.container {
width: 1000px;
margin: 60px auto;
}
.income {
float: left;
width: 475px;
margin-right: 50px;
}
.expenses {
float: left;
width: 475px;
}
h2 {
text-transform: uppercase;
font-size: 18px;
font-weight: 400;
margin-bottom: 15px;
}
.icome__title {
color: #28B9B5;
}
.expenses__title {
color: #FF5049;
}
.item {
padding: 13px;
border-bottom: 1px solid #e7e7e7;
}
.item:first-child {
border-top: 1px solid #e7e7e7;
}
.item:nth-child(even) {
background-color: #f7f7f7;
}
.item__description {
float: left;
}
.item__value {
float: left;
transition: transform 0.3s;
}
.item__percentage {
float: left;
margin-left: 20px;
transition: transform 0.3s;
font-size: 11px;
background-color: #FFDAD9;
padding: 3px;
border-radius: 3px;
width: 32px;
text-align: center;
}
.income .item__value,
.income .item__delete--btn {
color: #28B9B5;
}
.expenses .item__value,
.expenses .item__percentage,
.expenses .item__delete--btn {
color: #FF5049;
}
.item__delete {
float: left;
}
.item__delete--btn {
font-size: 22px;
background: none;
border: none;
cursor: pointer;
display: inline-block;
vertical-align: middle;
line-height: 1;
display: none;
}
.item__delete--btn:focus {
outline: none;
}
.item__delete--btn:active {
transform: translateY(2px);
}
.item:hover .item__delete--btn {
display: block;
}
.item:hover .item__value {
transform: translateX(-20px);
}
.item:hover .item__percentage {
transform: translateX(-20px);
}
.unpaid {
background-color: #FFDAD9 !important;
cursor: pointer;
color: #FF5049;
}
.unpaid .item__percentage {
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1);
}
.unpaid:hover .item__description {
font-weight: 900;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:100,300,400,600" rel="stylesheet" type="text/css">
<link href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css">
<link type="text/css" rel="stylesheet" href="style.css">
<title>Budgety</title>
</head>
<body>
<div class="top">
<div class="budget">
<div class="budget__title">
Available Budget in <span class="budget__title--month">%Month%</span>:
</div>
<div class="budget__value">+ 2,345.64</div>
<div class="budget__income clearfix">
<div class="budget__income--text">Income</div>
<div class="right">
<div class="budget__income--value">+ 4,300.00</div>
<div class="budget__income--percentage"> </div>
</div>
</div>
<div class="budget__expenses clearfix">
<div class="budget__expenses--text">Expenses</div>
<div class="right clearfix">
<div class="budget__expenses--value">- 1,954.36</div>
<div class="budget__expenses--percentage">45%</div>
</div>
</div>
</div>
</div>
<div class="bottom">
<div class="add">
<div class="add__container">
<select class="add__type">
<option value="inc" selected>+</option>
<option value="exp">-</option>
</select>
<input type="text" class="add__description" placeholder="Add description">
<input type="number" class="add__value" placeholder="Value">
<button class="add__btn"><i class="ion-ios-checkmark-outline"></i></button>
</div>
</div>
<div class="container clearfix">
<div class="income">
<h2 class="icome__title">Income</h2>
<div class="income__list">
<!--
<div class="item clearfix" id="income-0">
<div class="item__description">Salary</div>
<div class="right clearfix">
<div class="item__value">+ 2,100.00</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
<div class="item clearfix" id="income-1">
<div class="item__description">Sold car</div>
<div class="right clearfix">
<div class="item__value">+ 1,500.00</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
-->
</div>
</div>
<div class="expenses">
<h2 class="expenses__title">Expenses</h2>
<div class="expenses__list">
<!--
<div class="item clearfix" id="expense-0">
<div class="item__description">Apartment rent</div>
<div class="right clearfix">
<div class="item__value">- 900.00</div>
<div class="item__percentage">21%</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
<div class="item clearfix" id="expense-1">
<div class="item__description">Grocery shopping</div>
<div class="right clearfix">
<div class="item__value">- 435.28</div>
<div class="item__percentage">10%</div>
<div class="item__delete">
<button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
</div>
</div>
</div>
-->
</div>
</div>
</div>
</div>
<script src="app.js"></script>
</body>
</html>
The problem is that in the function formatNumber, the value num is not initialized at first time. For solving this, you can put a default value when the value of num is empty, like this:
var formatNumber = function(num = 0, type = '') {
var numSplit, int, dec, type;
/* + or - befofe a number
on 2 decimals
comma seperating thousands
*/
num = Math.abs(num);
num = num.toFixed(2);
numSplit = num.split('.');
int = numSplit[0];
if (int.length > 3) {
int = int.substr(0, int.length - 3) + ',' + int.substr(int.length - 3, 3); //input 23510, output 23,510
}
dec = numSplit[1];
return (type === 'exp' ? '-' : '+') + ' ' + int + '.' + dec;
};
I have a todolist that you can add new todo, and mark each todo as completed by click checkbox, and select the item visibility of the list by all or active or completed on the footer.
When I select Completed on the footer, it only shows item that is completed.
The problem is when I unmark the completed item in completed view, the remain(especially next one) item's checkbox display incorrectly.
var STORAGE_KEY = 'todo mvc by vue';
var todoStorage = {
data: [],
fetch: function () {
return this.data;
},
save: function (data) {
this.data = data;
//localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
}
}
var filters = {
all: function (todos) {
return todos;
},
active: function (todos) {
return todos.filter(todo => !todo.completed);
},
completed: function (todos) {
return todos.filter(todo => todo.completed);
}
}
var app = new Vue({
el: '.app',
data: {
todos: todoStorage.fetch(),
newTodo: '',
visiblitys: [{
title: 'All',
selected: true,
filter: filters.all
}, {
title: 'Active',
selected: false,
filter: filters.active
}, {
title: 'Completed',
selected: false,
filter: filters.completed
}]
},
computed: {
todosForShow: function () {
return this.currentFilter(this.todos);
},
currentFilter: function () {
return this.visiblitys.find(v => v.selected).filter;
}
},
watch: {
todos: {
handler: function (todos) {
todoStorage.save(todos);
},
deep: true
}
},
methods: {
deleteItem: function (todo) {
this.todos.splice(this.todos.indexOf(todo), 1);
},
deleteCompletedItem: function () {
this.todos = filters.active(this.todos);
},
addItem: function (todo) {
var value = this.newTodo && this.newTodo.trim();
if (!value) return;
this.todos.push({
content: value,
completed: false
});
this.newTodo = '';
},
selectVisiblity: function (visiblity) {
this.visiblitys.forEach(vis => vis.selected = false);
visiblity.selected = true;
},
completeAll: function () {
this.todos.forEach(todo => todo.completed = true);
}
}
});
* {
box-sizing: border-box;
}
header h1 {
text-align: center;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.new-todo {
padding: 16px;
box-shadow: inset 0 -2px 1px rgba(0, 0, 0, 0.03);
font-size: 24px;
width: 100%;
}
li.completed {
text-decoration: line-through;
}
footer {
border-top: 1px solid #e6e6e6;
height: 20px;
padding: 10px 15px;
color: #777;
text-align: center;
position: relative;
}
.filters {
list-style: none;
margin: 0;
padding: 0;
position: absolute;
left: 0;
right: 0;
}
.filters li {
display: inline;
}
.filters li a {
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
color: inherit;
}
.filters li a.selected {
border-color: rgba(175, 47, 47, 0.2);
}
.todo-count {
float: left;
text-align: left;
}
.complete-all {
float: right;
cursor: pointer;
position: relative;
color: black;
}
.todo-list {
clear: both;
}
.clear-completed {
float: right;
cursor: pointer;
position: relative;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-font-smoothing: antialiased;
}
<header>
<h1>Todos</h1>
</header>
<div class="app container">
<input class="new-todo" type="text" v-on:keyup.enter="addItem()" v-model="newTodo"
placeholder="What needs to be done?">
<section class="main" v-show="todos.length > 0">
<button class="complete-all" #click="completeAll()">Complete All</button>
<ul class="todo-list">
<li v-for="todo in todosForShow" :class="{completed: todo.completed}">
<input type="checkbox" v-model="todo.completed">
{{todo.content}} -
remove
</li>
</ul>
<footer>
<span class="todo-count">{{todos.filter(t=>!t.completed).length}} items left</span>
<ul class="filters">
<li v-for="visiblity in visiblitys">
<a href="#" :class="{selected: visiblity.selected}"
#click.prevent="selectVisiblity(visiblity)">{{visiblity.title}}</a>
</li>
</ul>
<button class="clear-completed" v-show="todos.some(t=>t.completed)" #click="deleteCompletedItem()">Clear
Completed</button>
</footer>
</section>
<br>todos raw dataļ¼{{this.todos}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
begin
select the completed in the footer
after uncheck first item
trying to replace customer js with
export default[
{ id: 0, name: 'some one', title: 'zero' },
{ id: 1, name: 'test last', title:'one'},
{ id: 2, name: 'test first', title:'two'},
{ id: 3, name: 'test second', title:'three'},
{ id: 4, name: 'test third', title:'four'},
{ id: 5, name: 'test fourth', title:'five'},
{ id: 6, name: 'test fifth', title:'six'}
];
My app is fine while using the above raw json.
since i am trying to get the date using axios in same file as per below code
Something i am missing to get the data into app.
import axios from 'axios';
export default {
data () {
return {
info: []
}
},
mounted () {
axios
.get('http://localhost/json/test.json')
.then(response => (this.info = response))
}
}
for getting data from url into customer.js
not working in case.
while my app.vue is
<template>
<div id="app">
<Autocomplete :items="customers"
filterby="name"
#change="onChange"
title="Look for a customer"
#selected="customerSelected"/>
</div>
</template>
<script>
import customers from './assets/customers';
import Autocomplete from './components/Autocomplete'
export default {
name: 'App',
mounted() {
this.customers = customers;
},
data() {
return {
customers: []
};
},
methods: {
customerSelected(customer) {
console.log(`Customer Selected:\nid: ${customer.id}\nname: ${customer.name}\ntitle:${customer.title}`);
},
onChange(value) {
// do something with the current value
}
},
components: {
Autocomplete
}
}
</script>
<style>
#app {
margin: 0px auto;
margin-top: 60px;
width: 400px;
}
</style>
and Autocomplete.vue is
<template>
<div class="autocomplete">
<div class="input" #click="toggleVisible" v-text="selectedItem ? selectedItem[filterby] : ''"></div>
<div class="placeholder" v-if="selectedItem == null" v-text="title"></div>
<button class="close" #click="selectedItem = null" v-if="selectedItem">x</button>
<div class="popover" v-show="visible">
<input type="text"
ref="input"
v-model="query"
#keydown.up="up"
#keydown.down="down"
#keydown.enter="selectItem"
placeholder="Start Typing...">
<div class="options" ref="optionsList">
<ul>
<li v-for="(match, index) in matches"
:key="index"
:class="{ 'selected': (selected == index)}"
#click="itemClicked(index)"
v-text="match[filterby]"></li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
items: {
default: [],
type: Array
},
filterby: {
type: String
},
title: {
default: 'Select One...',
type: String
},
shouldReset: {
type: Boolean,
default: true
}
},
data() {
return {
itemHeight: 39,
selectedItem: null,
selected: 0,
query: '',
visible: false
};
},
methods: {
toggleVisible() {
this.visible = !this.visible;
setTimeout(() => {
this.$refs.input.focus();
}, 50);
},
itemClicked(index) {
this.selected = index;
this.selectItem();
},
selectItem() {
if (!this.matches.length) {
return;
}
this.selectedItem = this.matches[this.selected];
this.visible = false;
if (this.shouldReset) {
this.query = '';
this.selected = 0;
}
this.$emit('selected', JSON.parse(JSON.stringify(this.selectedItem)));
},
up() {
if (this.selected == 0) {
return;
}
this.selected -= 1;
this.scrollToItem();
},
down() {
if (this.selected >= this.matches.length - 1) {
return;
}
this.selected += 1;
this.scrollToItem();
},
scrollToItem() {
this.$refs.optionsList.scrollTop = this.selected * this.itemHeight;
}
},
computed: {
matches() {
this.$emit('change', this.query);
if (this.query == '') {
return [];
}
return this.items.filter((item) => item[this.filterby].toLowerCase().includes(this.query.toLowerCase()))
}
}
}
</script>
<style scoped>
.autocomplete {
width: 100%;
position: relative;
}
.input {
height: 40px;
border-radius: 3px;
border: 2px solid lightgray;
box-shadow: 0 0 10px #eceaea;
font-size: 25px;
padding-left: 10px;
padding-top: 10px;
cursor: text;
}
.close {
position: absolute;
right: 2px;
top: 4px;
background: none;
border: none;
font-size: 30px;
color: lightgrey;
cursor: pointer;
}
.placeholder {
position: absolute;
top: 11px;
left: 11px;
font-size: 25px;
color: #d0d0d0;
pointer-events: none;
}
.popover {
min-height: 50px;
border: 2px solid lightgray;
position: absolute;
top: 46px;
left: 0;
right: 0;
background: #fff;
border-radius: 3px;
text-align: center;
}
.popover input {
width: 95%;
margin-top: 5px;
height: 40px;
font-size: 16px;
border-radius: 3px;
border: 1px solid lightgray;
padding-left: 8px;
}
.options {
max-height: 150px;
overflow-y: scroll;
margin-top: 5px;
}
.options ul {
list-style-type: none;
text-align: left;
padding-left: 0;
}
.options ul li {
border-bottom: 1px solid lightgray;
padding: 10px;
cursor: pointer;
background: #f1f1f1;
}
.options ul li:first-child {
border-top: 2px solid #d6d6d6;
}
.options ul li:not(.selected):hover {
background: #8c8c8c;
color: #fff;
}
.options ul li.selected {
background: orange;
color: #fff;
font-weight: 600;
}
</style>
In most of the cases, response consists of several properties and you will need response.data.
if this didn't work then print the response, using console.log(response) and inspect it such that which key holds the JSON data.