todo list how to properly add delete function in Vue3? - javascript

I have created a Vue3 to-do list project with VueCLI(VueX) for practice. I can add items to the array of objects and display them from objects.
Now, I want to implement a delete function that when I click the delete button beside the item, it deletes the element and also removes the object from array.
Here is my code:
NoteInput.vue
<template>
<div>
<input
type="text"
v-model="inputValue"
#keyup.enter="addItem"
/>
</div>
</template>
<script>
import { ref } from 'vue'
import { useStore } from 'vuex'
export default {
setup() {
const inputValue = ref()
const store = useStore()
const addItem = () => {
if (inputValue.value !== '') {
store.commit('addItem', inputValue.value)
}
inputValue.value = ''
}
return {
inputValue,
addItem
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
NoteItem.vue
<template>
<div>
<div
v-for="(item, index) in list"
:key="index"
>
<span>{{item.title}}</span>
<span>
<button #click="deleteItem">Delete</button>
</span>
</div>
</div>
</template>
<script>
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
const list = store.state.list
const deleteItem = () => {
// store.commit('deleteItem', this.item.title)
console.log()
}
return {
list,
deleteItem
}
}
}
</script>
store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
list: []
},
getters: {
},
mutations: {
addItem(state, item) {
state.list.push({
title: item,
status: 'normal'
})
},
deleteItem(state, item) {
}
},
actions: {
},
modules: {
}
})

Please modify your NoteItem.vue and store/index.js files as below.
Working codesandbox link https://codesandbox.io/s/vue-3-vuex-4-vue-router-forked-ei4x1r
NoteItem.vue
<template>
<div>
<div
v-for="(item, index) in list"
:key="index"
>
<span>{{item.title}}</span>
<span>
<button #click="deleteItem(index)">Delete</button>
</span>
</div>
</div>
</template>
<script>
import { useStore } from 'vuex'
export default {
setup() {
const store = useStore()
const list = store.state.list
const deleteItem = () => {
store.commit('deleteItem', index)
}
return {
list,
deleteItem
}
}
}
</script>
store/index.js
import { createStore } from 'vuex'
export default createStore({
state: {
list: []
},
getters: {
},
mutations: {
addItem(state, item) {
state.list.push({
title: item,
status: 'normal'
})
},
deleteItem(state, index) {
state = state.list.splice(index, 1);
}
},
actions: {
},
modules: {
}
})

Related

how to call a function from another component in vue3?

i have tried to using $on method and this.$root.$refs.compname_component = this; but got some errors,Please refer below my codes
formComponent.vue
<template>
<div v-if="showForm">
create Form
</div>
</template>
<script>
export default {
props:[],
setup(props) {
return props;
},
data() {
return {
formData:{},
showForm:false
}
},
created() {
// this.$root.$refs.tableCommon = this;
// this.$root.$refs.compname_component = this;
},
mounted() {
console.log('form mounted');
// this.$root.$on("displayForm", () => {
// this.displayForm();
// });
},
methods: {
displayForm:function(){
this.showForm = true;
}
},
}
</script>
commonComponent.vue
<template>
<div class="col-10 text-end custom-inline-spacing mb-3">
<button type="button" class="btn btn-outline-secondary" #click="showCreateForm">Create</button>
</div>
</template>
<script>
export default {
props: [],
setup() {
return {}
},
data() {
return {
}
},
mounted() {
console.log('mounted common')
},
methods: {
showCreateForm : function(){
// this.$refs.form.displayForm();
// this.$root.$refs.compname_component.displayForm();
// this.$root.$emit("displayForm");
this.createForm.displayForm();
}
}
}
</script>
app.js
require('./bootstrap')
import { createApp } from 'vue'
import tableCommon from './components/CommonComponent'
import createForm from './components/formComponent';
const app = createApp({})
app.component('vue-common', tableCommon);
app.component('create-form', createForm);
app.mount('#app')
actualy what i want means call formComponent.displayForm() from CommonComponent.
If you want to conditionally display child component, you can move logic out of that component into the parent component.
Parent.vue
<template>
<FormComponent v-if="showComponent" />
</template>
Alternatively, you can pass a prop into FormComponent if you need to conditionally display only a part of that component.
Parent.vue
<template>
<FormComponent v-bind:show-component="showComponent" />
</template>
FormComponent.vue
<template>
<div v-if="showComponent">
...
</div>
<div>
...
</div>
</template>

Quasar Multi select value component using Vuejs

I'm using Vuejs and Quasar on my project, I'm trying to do an autocomplete select to select some value, when the user tries to type some text, an API is sent to the server to retrieve. all the values contains that text, heres the code :
<template>
<div class="autocomplete">
<q-select
filled
label="Search"
v-model="searchTerm"
use-input
use-chips
multiple
#filter="filterFn"
#input-value="inputValue"
#filter-abort="abortFilterFn"
:options="searchResult"
style="width: 395px"
:option-label=""
option-value="text"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey"> No results </q-item-section>
</q-item>
</template>
</q-select>
<div>
<back-button #click="go" data-test="btn-back" forwardicon="arrowright" />
</div>
<script>
import { defineComponent, ref, computed } from "vue";
import { apiProductService } from "../../models/";
import apiEndPoints from "../../models/api";
import BackButton from "../ui/";
import { useRouter } from "vue-router";
import { useSearchStore } from "../../store/";
import _ from "lodash";
import { debounce } from "quasar";
export default defineComponent({
name: "search-bar",
components: { BackButton },
setup(props, context) {
const router = useRouter();
let searchTerm = ref(null);
let searchResult = ref([]);
const search = useSearchStore();
function filterFn(val, update, abort) {
if (searchResult.value.length > 0) {
update();
return;
}
abortFilterFn();
document.addEventListener('keypress', function(e) {
true
});
}
function abortFilterFn() {
// console.log('delayed filter aborted')
}
const inputValue = computed(() => debounce(suggestions, 0).bind(this));
function suggestions(val) {
if (val) {
getSearchData(val);
document.addEventListener('keypress', function(e) {
true
});
} else {
searchResult.value = [];
}
}
const getSearchData = async (val) => {
await apiProductService(
apiEndPoints.GetSearchSuggestions.method,
apiEndPoints.GetSearchSuggestions.url,
{
q: val,
top: 5,
suggester: "sg",
}
).then((response) => {
searchResult.value = response?.data?.suggestions || [];
});
};
}
return {
searchTerm,
searchResult,
filterFn,
inputValue
};
},
});
the problem with code is when I try to type for example the term "tes", I can see the data retrieved for the db, when I clic on the desired value, the type text is savec on the multi selected component like:
how can I remove the type text please ?
Use ref and use updateInputValue for clear input.
https://codepen.io/Pratik__007/pen/RwMWbwK

Vuex global state change does not trigger re-render component in v-for loop in Nuxt

I have difficult to use vuex global state combine with re-render child-component in Vue.js.
The global state is mutated but does not re-render its data in v-for loop.
All list of data is rendered, but when the new data changes, component in /blog does not change data in it.
Here is some code:
/store/index.js
export const state = () => ({
allData: [],
})
export const getters = {
getAllData: (state) => state.allData,
}
export const mutations = {
GET_DATAS(state, payload) {
state.allData = payload
},
UPDATE_DATA(state, payload) {
const item = state.allData[payload.index]
Object.assign(item, payload)
},
}
export const actions = {
getDatas({ commit, state }, payload) {
return fetch(`URL_FETCH`)
.then((data) => data.json())
.then((data) => {
commit('GET_DATAS', data)
})
.catch((err) => console.log(err))
},
updateData({ commit, state }, payload) {
commit('UPDATE_DATA', payload)
},
}
in /layouts/default.vue
beforeCreate() {
this.$store.dispatch('getDatas').then(() => {
connectSocket()
})
},
methods: {
connectSocket() {
// connect & received message from socket
// received message from socket
this.$root.$emit('updateData', {
index: 12,
price: 34,
change: 56,
percent: 78,
})
},
},
and in /pages/blog/index.vue
<template>
<div>
<div
v-for="index in getAllData"
:key="index.name"
class="w-100 grid-wrapper"
>
<div>{{ index.price }}</div>
<div>{{ index.change }}</div>
<div>{{ index.percent }}</div>
</div>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
data() {
return {}
},
computed: {
...mapGetters(['getAllData']),
},
mounted() {
this.$root.$on('updateData', (item) => {
this.$store.dispatch('updateData', {
index: item.index,
price: item.price,
percent: item.percent,
change: item.change,
})
})
},
}
</script>
Here is a complete example on how to use Vuex and load the data efficiently into a Nuxt app (subjective but using good practices).
/pages/index.vue
<template>
<div>
<main v-if="!$fetchState.pending">
<div v-for="user in allData" :key="user.id" style="padding: 0.5rem 0">
<span>{{ user.email }}</span>
</div>
</main>
<button #click="fakeUpdate">Update the 2nd user</button>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
export default {
data() {
return {
mockedData: {
name: 'John Doe',
username: 'jodoe',
email: 'yoloswag#gmail.com',
phone: '1-770-736-8031 x56442',
website: 'hildegard.org',
},
}
},
async fetch() {
await this.setAllData()
},
computed: {
...mapState(['allData']),
},
methods: {
...mapActions(['setAllData', 'updateData']),
fakeUpdate() {
this.updateData({ index: 1, payload: this.mockedData })
},
},
}
</script>
/store/index.js
import Vue from 'vue'
export const state = () => ({
allData: [],
})
export const mutations = {
SET_ALL_DATA(state, payload) {
state.allData = payload
},
UPDATE_SPECIFIC_DATA(state, { index, payload }) {
Vue.set(state.allData, index, payload)
},
}
export const actions = {
async setAllData({ commit }) {
try {
const httpCall = await fetch('https://jsonplaceholder.typicode.com/users')
const response = await httpCall.json()
commit('SET_ALL_DATA', response)
} catch (e) {
console.warn('error >>', e)
}
},
updateData({ commit }, { index, payload }) {
commit('UPDATE_SPECIFIC_DATA', { index, payload })
},
}

Hello! How to pull data from localStorage in Vue.js and render on the page?

The task is to integrate the cart as a separate component in Vuejs into a finished project, written not in Vuejs. There is a part of a function for adding an item to the cart, which stores data in localStorage.
for (let i = 0; i < addToCartBtns.length; i++) {
addToCartBtns[i].addEventListener("click", () => {
notification.classList.add("notification--opened");
setTimeout(closeNotification, 4000);
qtyChanger(products[i]);
});
}
function qtyChanger(product) {
let productQty= localStorage.getItem('qty');
productQty= parseInt(productQty);
if(productQty) {
localStorage.setItem("qty", productQty + parseInt(input.value));
} else {
localStorage.setItem("qty", input.value);
activateCart();
}
setItems(product);
}
function setItems(product) {
let cartItems = localStorage.getItem("productsInCart");
cartItems = JSON.parse(cartItems);
if (cartItems !== null) {
if (cartItems[product.id] == undefined) {
cartItems = {
...cartItems,
[product.id]: product
}
}
cartItems[product.id].qty += parseInt(input.value);
} else {
product.qty = parseInt(input.value);
cartItems = {
[product.id]: product
};
}
localStorage.setItem("productsInCart", JSON.stringify(cartItems));
}
function closeNotification() {
if (notification.classList.contains("notification--opened")) {
notification.classList.remove("notification--opened")
}
}
function onLoadProductQty() {
let productQty = localStorage.getItem("qty");
if(productQty) {
activateCart()
}
}
onLoadProductQty();
this is my store.js file in a vue cart, where I'm trying to get localStorage data
import {
createApp
} from 'vue';
import {
createStore
} from 'vuex';
let storage = JSON.parse(localStorage.getItem("productsInCart"));
let store = createStore({
state: {
products: storage ? storage : []
},
mutations: {
SET_TO_LOCALSTORAGE: (state, products) => {
state.products = products;
},
CHANGE_LOCALSTORAGE: (state, products) => {
state.products = products;
localStorage.setItem("productsInCart", JSON.stringify(products));
},
....
},
actions: {
SET_PRODUCTS_TO_LOCALSTORAGE({ commit, products }) {
commit("SET_TO_LOCALSTORAGE", products);
commit("ACTIVATE_CART");
},
....
CHANGE_STATE_LOCALSTORAGE({ commit }) {
commit("CHANGE_LOCALSTORAGE");
}
},
getters: {
PRODUCTS(state) {
return state.products;
}
}
});
const app = createApp({});
app.use(store);
export default store;
And here I am trying to call loading from store.js
<template>
<div
class="cells"
v-if=" PRODUCTS && PRODUCTS.length">
<div class="cell cell-xl-8">
<cart/>
</div>
<cart-form/>
</div>
<div class="page-message" v-else>
.......
</template>
<script>
import cart from './components/cart.vue'
import cartForm from './components/cart-form.vue'
import {mapActions, mapGetters} from 'vuex'
export default {
components: { cartForm, cart },
name: "app",
computed: {
...mapGetters([
'PRODUCTS'
])
},
methods: {
...mapActions([
'SET_PRODUCTS_TO_LOCALSTORAGE'
])
},
mounted() {
this.SET_PRODUCTS_TO_LOCALSTORAGE()
}
}
</script>
please, tell me what I'm doing wrong??

how to add Firebase to a Vuex todo list app?

I am building a simple Vue.js todo list app using Vue.js, Vuex, and Firebase. The Vuex store dispatches, commits, and returns the inputted data just as it should, but I want to be able to connect the app to a Firestore database. So far, I have managed to set up the app so that data is pushed into the collection, but I also want the database to return a snapshot of the firestore data to the DOM, as well as to enable deleting of data from database. I have experience with these Firestore methods in simple non Vuex-projects, but am not sure how to synthesize Firestore methods with a Vuex store. How can I do this? Here is what I have so far. Thanks so much!
<!--GetTodo.vue-->
<template>
<div id="get-todo" class="container">
<input class="form-control" :value="newTodo" #change="getTodo" placeholder="I need to...">
<button class="btn btn-primary" #click="addTodo">Add New Post</button>
<ul class="list-group">
<li class="list-group-item" v-for="todo in todos">
{{todo.body}}
<div class="btn-group">
<button type="button" #click="remove(todo)" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-remove-circle"></span> Remove
</button>
</div>
</li>
</ul>
</div>
</template>
<script>
export default {
methods: {
getTodo(e) {
this.$store.dispatch('getTodo', e.target.value)
},
addTodo() {
this.$store.dispatch('addTodo')
this.$store.dispatch('clearTodo')
},
remove(todo){
this.$store.dispatch('removeTodo', todo)
}
},
computed: {
todos(){
return this.$store.getters.todos
},
newTodo() {
return this.$store.getters.newTodo
}
}
}
</script>
<style>
</style>
//store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
import db from '../firebase';
export default new Vuex.Store({
state: {
todos: [],
newTodo: ''
},
mutations: { //syncronous, committed
GET_TODO(state, todo){
state.newTodo = todo
},
ADD_TODO(state){
state.todos.push({
body: state.newTodo,
completed: false
})
db.collection('messages').add({
content: state.newTodo
})
},
REMOVE_TODO(state, todo){
var todos = state.todos
todos.splice(todos.indexOf(todo), 1)
},
CLEAR_TODO(state){
state.newTodo = ''
}
},
actions: { //asyncronous, dispatched
getTodo({commit}, todo){
commit('GET_TODO', todo)
},
addTodo({commit}){
commit('ADD_TODO')
},
removeTodo({commit}, todo){
commit('REMOVE_TODO', todo)
},
clearTodo({commit}){
commit('CLEAR_TODO')
}
},
getters: {
newTodo: state => state.newTodo,
todos: state => state.todos.filter((todo) => {
return !todo.completed
})
}
})
<!--App.vue-->
<template>
<div id="app" class="container">
<GetTodo></GetTodo>
</div>
</template>
<script>
import GetTodo from './components/GetTodo.vue'
export default {
components: {
GetTodo
}
}
</script>
<style>
body {
font-family: Helvetica, sans-serif;
}
li {
margin: 10px;
}
</style>
You can make sync in your mutation, see the example below:
source: https://www.codewall.co.uk/how-to-create-a-real-time-to-do-list-app-with-vue-vuex-firebase-tutorial/
import Vue from 'vue'
import Vuex from 'vuex'
import { db } from '#/main'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
items: null
},
getters: {
getItems: state => {
return state.items
}
},
mutations: {
setItems: state => {
let items = []
db.collection('items').orderBy('created_at').onSnapshot((snapshot) => {
items = []
snapshot.forEach((doc) => {
items.push({ id: doc.id, title: doc.data().title })
})
state.items = items
})
}
},
actions: {
setItems: context => {
context.commit('setItems')
}
}
})
import { db } from '#/main'
export default {
name: 'home',
beforeCreate: function () {
this.$store.dispatch('setItems')
},
data: function () {
return {
myTodo: '',
errors: ''
}
},

Categories

Resources