Have trouble edit my to do list content via Vuex - vue.js

I have made a to do list and wrote a code to edit my to do list title via VUEX but it doesn't work properly.
I would really apreaciate if someone can help me with it.
SandBox code example
Actually i want to filter the tasks in my view to select the one is clicked and then change its content to hat user types
VUEX state
tasks: [],
VUEX mutations
EDIT_TODO(state, task) {
state.tasks.filter((o) => {
o.id = task.id;
});
}
component
<template>
<div style="background-color: white; color: black; padding: 20px">
<input type="text" v-model="inputText" />
<br />
<button #click="editToDo">update value</button>
{{ task.title }}
</div>
<script>
export default {
props: ["task"],
data() {
return {
inputText: this.task.title,
};
},
methods: {
editToDo() {
console.log("hhh");
this.$store.commit("EDIT_TODO", this.inputText);
},
}
};
</script>
link to github project

Related

Vuejs Role based login with different authorization

I am new to vue js and I am working on a simple project about role based login and listing report. In my design, there are two type of user: HAuser and supplier. How should I redirect different user to their corresponding page and authorize them with different access right?
login component:
<template>
<div class="auth-inner">
<h3>{{ userType }} {{ $t('Login') }}</h3>
<form v-on:submit.prevent="onSubmit">
<div class="form-group">
<label>{{ $t('username') }}</label>
<input v-model="loginForm.username" type="username" class="form-control" :placeholder="$t('username')" />
</div>
<div class="form-group">
<label>{{ $t('password') }}</label>
<input v-model="loginForm.password" type="password" class="form-control" :placeholder="$t('password')" />
</div>
<div class="d-grid gap-2">
<button class="btn btn-primary" type="submit">{{ $t('Login') }}</button>
<vue-recaptcha
ref="recaptcha"
#verify="onCaptchaVerified"
#expired="onCaptchaExpired"
sitekey="6LfCmnEhAAAAAIsEHJx8QXbUHIAvIsuuwQW4JGj_"
class="mt-3" />
</div>
<div v-if="showErrorMessage" class="recaptcha-error-message"><strong>{{ $t('recaptcha-error-message') }}</strong></div>
</form>
</div>
</template>
<script>
import { VueRecaptcha } from 'vue-recaptcha';
export default {
name: 'login',
props: ['userType'],
components: { VueRecaptcha },
data(){
return{
showErrorMessage: false,
recaptchaToken: '',
status: '',
sucessfulServerResponse: '',
serverError: '',
recaptchaVerified: false,
submitted: false,
loading: false,
returnUrl: '',
error: '',
loginForm: {
username: '',
password: '',
}
}
},
methods: {
onCaptchaVerified: function (recaptchaToken) {
this.showErrorMessage = false;
this.loginForm.recaptchaVerified = true;
this.recaptchaToken = recaptchaToken;
},
onCaptchaExpired: function () {
this.loginForm.recaptchaVerified = false;
this.$refs.recaptcha.reset();
if (!this.loginForm.recaptchaVerified) {
this.showErrorMessage = true;
return ; // prevent form from submitting
}
},
onSubmit () {
if (!this.loginForm.recaptchaVerified) {
this.showErrorMessage = true;
return ; // prevent form from submitting
}
}
}
}
</script>
<style>
.recaptcha-error-message {
color: red;
}
.auth-inner {
width: 450px;
margin:auto;
background: #ffffff;
box-shadow: 0px 14px 80px rgba(34, 35, 58,0.2);
padding: 40px 55px 45px 55px;
border-radius: 15px;
transition: all .3s;
}
</style>
different user view:
HAuser:
<template>
<Login userType='HAuser'/>
</template>
<script>
import Login from '#/components/Login.vue';
export default {
components: {
Login
}
}
</script>
<style>
</style>
Supplier view:
<template>
<Login userType='Supplier' />
</template>
<script>
import Login from '#/components/Login.vue';
export default {
components: {
Login
},
}
</script>
<style>
</style>
report const
{
"reports": [
{ "type": "Supplier", "name": "Summary of Users Last Access Time" },
{ "type": "Supplier", "name": "Capital Budget Report - Grand Summary" },
{ "type": "HAuser", "name": "(Workflow) Report on Site Directions/Memo Status" },
{ "type": "HAuser", "name": "Yearly Budget Forecast Working Sheet by Project" },
{ "type": "HAuser", "name": "Report on SWD's Lotteries Fund Project Under Block" }
]
}
You would want to look into router-guards. You can use them to do some checks before routing further and if needed route the user elsewhere. So for example:
When your user logs in at that point you know the role. Then you route to the default page, but if you detect in the guard that the role should go to another page you redirect to that page instead of the default page.
https://router.vuejs.org/guide/advanced/navigation-guards.html#global-before-guards
There are of course other options like creating a computed property on the login page that get the role from your pinia (vuex) store.. put a watcher on that computed property also in the login page and when it changes route to the correct page.

Pass object to component - vue js

I've tried a few different things and now must ask for some help (thanks in advance).
I'm creating a simple Vue js app where a component form emits data as a object (this works) to its parent.
the parent then runs a v-for loop and passes the Object data to a component which displays the data (this does not work).
Vue Version
($ vue --version
#vue/cli 4.4.1)
Parent code:
<template>
<div class="MEDS">
<goalForm #goal_data="goal_create($event)"/>
<section>
<div v-for="(goalItem, index) in this.goals_list_container" v-bind:key="index">
<goalItem :goal="goalItem"/>
</div>
</section>
</div>
</template>
// # is an alias to /src
import goalForm from '#/components/Goal_form.vue'
import goalItem from '#/components/Goal_item.vue'
export default {
name: 'MEDS',
components: {
goalForm,
goalItem
},
data(){
return{
// Recievs goals from goalForm on submit, this is an array of objects
goals_list_container: [],
}
},
methods: {
goal_create(payload){
this.goals_list_container.push(payload);
console.log(this.goals_list_container)
}
}
}
GOAL ITEM (that should display the goal)
<template>
<div>
<h3>{{goal.title}}</h3>
</div>
</template>
export default {
prop: ['goal'],
data(){
return {
goal: {}
}
},
watch: {
}
}
Goal_form: (EDITED)
<div>
<form action="" class="goalForm" #submit.prevent="emit_Goal">
<input type="text" name="title" id="title" v-model="title">
<input type="text" name="description" id="description" v-model="des">
<input type="date" name="dueDate" id="dueDate" v-model="dueDate">
<input type="number" name="priority" id="priority" v-model="priority">
<input type="submit" class="submit">
</form>
</div>
</template>
<script>
export default {
data() {
return {
title: null,
des: null,
dueDate: null,
priority: null,
goal_data: {}
}
},
methods: {
push_goal(){
this.goal_data.title = this.title
this.goal_data.des = this.des
this.goal_data.dueDate = this.dueDate
this.goal_data.priority = this.priority
},
emit_Goal(){
// Move goal details into Object to be Emited
this.push_goal()
// Emit the form to the parent on submit
this.$emit('goal_data', this.goal_data)
}
}
}
</script>
<style lang="scss" scoped>
form {
display: flex;
flex-direction: column;
input {
&[name="title"]{
}
}
}
</style>
The for loop seems to work as each submit of the Goal_form creates a new instance of the Goal_item component.... But it does not populate with any data.
I Am either getting this totally wrong or have missed something small but any help would be greatly appreciated -
W

Vue open a component in a component

In App.vue I have a button to open a component . Inside the component BigForm, I also have a button to open a component named, . But as I open the component. Vue re-render the page with the warning:
The "data" option should be a function that returns a per-instance value in component definitions.
App.Vue
<template>
<div id="app">
<button #click="showModal()">Show</button>
<BigForm v-if="modal" />
</div>
</template>
<script>
import BigForm from "./components/BigForm";
export default {
name: "App",
components: {
BigForm,
},
data() {
return {
modal: false,
};
},
methods: {
showModal() {
this.modal = !this.modal;
},
},
};
</script>
BigForm.vue:
<template>
<div class="hello">
<form style="height: 300px; width: 300px; background-color: green">
<button #click="showSmallForm()">Show small form</button>
<SmallForm
v-if="toggleSmallForm"
style="width: 100px; height: 100px; background-color: yellow"
/>
</form>
</div>
</template>
<script>
import SmallForm from "./SmallForm";
export default {
name: "HelloWorld",
components: {
SmallForm,
},
data() {
return {
toggleSmallForm: false,
};
},
methods: {
showSmallForm() {
this.toggleSmallForm = !this.toggleSmallForm;
},
},
};
</script>
And SmallForm.vue:
<template>
<form>
<input placeholder="Small form input" />
<button>This is small form</button>
</form>
</template>
This is the code to my example in codesandbox:
https://codesandbox.io/s/late-cdn-ssu7f?file=/src/App.vue
The problem is not related to Vue itself but the HTML.
When you use <button> inside <form>, the default type of the button is submit (check this) - when you click the button, the form is submitted to the server causing the page to reload.
You can prevent that by explicitly setting type <button type="button"> (HTML way) or by preventing default action (Vue way) <button #click.prevent="showSmallForm()">Show small form</button> (see event modifiers)
Also note that using <form> in another <form> is not allowed in HTML

In vue.js how can I filter products by size, color, category & by selecting each of these categories in step wise slider

In vue.js how can I filter products by size, color, category & by selecting each of these categories in step-wise slider where I have to select each filter one by one step-wise & at last I need to display the products which pass through the filter.
Please share code examples and ask specific questions about where you are stuck. This question is very broad and is difficult to answer.
I'll try to provide an answer as best as I can.
You might have a ProductList component that may look something like this:
<template>
<!-- your template -->
</template>
<script>
import RangeSlider from "./RangeSlider";
export default {
name: "ProductList",
components: {
RangeSlider
},
data() {
return {
products: [],
filters: {
color: null,
size: null,
category: null
},
options: {
color: ["Red", "Yellow", "Green"],
size: ["Small", "Medium", "Large"],
category: ["Men", "Women", "Boy", "Girl"]
}
};
}
};
</script>
The RangeSlider can use the native <input type="range" /> control to build the functionality you want.
In this example, it takes a label and an array of options to build the control, and will emit a change event when the user changes the value of the control by sliding, which is captured in ProductList to set the filters. You can then use the filters object and make an API call to fetch your products.
<template>
<div class="range-slider">
<label>
<strong>{{ label }}</strong>
</label>
<div>
<input type="range" min="0" :max="max" step="1" #change="onInputChange" :value="rangeValue">
</div>
<div>{{ options[rangeValue] }}</div>
</div>
</template>
<script>
export default {
name: "RangeSlider",
props: ["label", "options"],
data() {
return {
rangeValue: 0
};
},
mounted() {
this.onChange(0);
},
methods: {
onInputChange(e) {
this.onChange(e.target.value);
},
onChange(rangeValue) {
this.rangeValue = rangeValue;
let selectedOption = this.options[this.rangeValue];
this.$emit("change", selectedOption);
}
},
computed: {
max() {
return this.options.length - 1;
}
}
};
</script>
<style>
.range-slider {
padding: 1rem;
border-bottom: 1px solid;
}
</style>
Here is the working example on CodeSandbox: https://codesandbox.io/s/rangesliderwithoptionsexample-6pe10

VueJS: #click.native.stop = "" possible?

I have several nested components on the page with parents component having #click.native implementation. Therefore when I click on the area occupied by a child component (living inside parent), both click actions executed (parent and all nested children) for example
<products>
<product-details>
<slide-show>
<media-manager>
<modal-dialog>
<product-details>
<slide-show>
<media-manager>
<modal-dialog>
</products>
So I have a list of multiple products, and when I click on "canvas" belonging to modal dialog - I also get #click.native fired on product-details to which modal-dialog belongs. Would be nice to have something like #click.native.stop="code", is this possible?
Right now I have to do this:
#click.native="clickHandler"
and then
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
code
<template>
<div class="media-manager">
<div v-if="!getMedia">
<h1>When you're ready please upload a new image</h1>
<a href="#"
class="btn btn--diagonal btn--orange"
#click="upload=true">Upload Here</a>
</div>
<img :src="getMedia.media_url"
#click="upload=true"
v-if="getMedia">
<br>
<a class="arrow-btn"
#click="upload=true"
v-if="getMedia">Add more images</a>
<!-- use the modal component, pass in the prop -->
<ModalDialog
v-if="upload"
#click.native="clickHandler"
#close="upload=false">
<h3 slot="header">Upload Images</h3>
<p slot="body">Hello World</p>
</ModalDialog>
</div>
</template>
<script>
import ModalDialog from '#/components/common/ModalDialog';
export default {
components: {
ModalDialog,
},
props: {
files: {
default: () => [],
type: Array,
},
},
data() {
return {
upload: false,
}
},
computed: {
/**
* Obtain single image from the media array
*/
getMedia() {
const [
media,
] = this.files;
return media;
},
},
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
}
};
</script>
<style lang="scss" scoped>
.media-manager img {
max-width: 100%;
height: auto;
}
a {
cursor: pointer;
}
</style>
Did you check the manual? https://v2.vuejs.org/v2/guide/events.html
There is #click.stop="" or #click.stop.prevent=""
So you don't need to use this
methods: {
clickHandler(e) {
e.stopPropagation();
console.log(e);
}
}
In the Vue, modifiers can be chained. So, you are free to use modifiers like this:
#click.native.prevent or #click.stop.prevent
<my-component #click.native.prevent="doSomething"></my-component>
Check events
I had the same problem. I fixed the issue by using following:
<MyComponent #click.native.prevent="myFunction(params)" />