Filtering items, checkbox issue laravel + vue js - vue.js

I have a "Messages" table in the database. I am trying to make a filter by read/unread
For the filter, I am trying to make two checkboxes, and a "isread" variable, however I cant manage to make it work, heres what I have:
<input
type="checkbox"
id="1"
class="read"
v-model="isread"
:value="1"
/>
<input
type="checkbox"
id="0"
class="unread"
v-model="isread"
:value="0"
/>
The issue is that I get tons of errors in the console, plus the checkboxes get ticked/unticked at the same time (like its the same checkbox). My expected result, is that the variable "isread" stores value "0" if the "0" checkbox is checked, and "1" if the "1" is checked. Or, if both - both values get stored. Could you help me?

If I understand your requirement correctly, You are trying to filtered out the existing list of messages based on the read and unread messages. If Yes, You can try this solution :
var vm = new Vue({
el:"#app",
data:{
messages: [
'read1',
'read2',
'read3',
'read4',
'unread5',
'unread6',
'unread7',
'unread8',
'read9',
'read10',
],
isread: null,
isunread: null,
filteredMessages: []
},
mounted() {
this.filteredMessages = this.messages;
},
methods: {
check(e) {
if (e.target.checked && (e.target.value === '1')) {
this.filteredMessages = this.messages.filter((item) => item.indexOf('unread') === -1)
this.isunread = 0;
} else if (e.target.checked && (e.target.value === '0')) {
this.filteredMessages = this.messages.filter((item) => item.indexOf('unread') !== -1)
this.isread = 0;
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
Read :<input
type="checkbox"
id="1"
class="read"
v-model="isread"
:value="1"
#change="check($event)"
/>
Unread :<input
type="checkbox"
id="0"
class="unread"
v-model="isunread"
:value="0"
#change="check($event)"
/>
<ul class="list">
<li v-for="(message, index) in filteredMessages" :key="index">{{ message }}</li>
</ul>
</div>

Related

V-model inside v-for is filling all the inputs

In few words I have multiple Todolists, once I try to post a new Todo inside the Todolist all the inputs of other Todolists gets fill in with the same words. How can I solve this?
Edit: I can post a new todo without problems and it will appear on the relative todolist (see addTodo method). The ONLY problem is that the v-model is for all the todolists on the field, not only for the one I'm writing in, so as soon as I start to write inside an input I got all the inputs filled.
<div class="todolist" v-for="todolist in todolists" :key="todolist.id">
<div class="td-title">
<h5 class="text-center m-0 py-2 text-light">
{{ todolist.title }}
</h5>
</div>
<form
#submit.prevent="addTodo(todolist.id)"
class="td-inputs d-flex align-items-center justify-content-center"
>
// this is the v-model
<input v-model="todo.title" class="px-2" type="text" />
<button type="submit">
<i class="fas fa-plus fa-2x"></i>
</button>
</form>
<div>
<div v-for="todo in todolist.todos" :key="todo.id" class="todo">
{{ todo.title }}
</div>
<div>
<i class="fas fa-times" #click="cancel(todolist.id)"></i>
</div>
</div>
</div>
data
data() {
return {
todolists: [],
loading: true,
todo: {
title: "",
todolist_id: "",
user_id: ""
},
};
},
Methods
getTodoLists() {
axios
.get("http://127.0.0.1:8000/api/todolists")
.then((res) => {
this.todolists = res.data;
this.loading = false;
})
.catch((err) => {
console.log(err);
});
},
cancel(id) {
axios
.delete(`http://127.0.0.1:8000/api/todolists/${id}`)
.then(() => {
this.getTodoLists();
})
.catch((err) => {
console.log(err);
});
},
addTodo(todolist) {
axios
.post(`http://127.0.0.1:8000/api/${todolist}/todos`, this.todo)
.then(() => {
this.todo = {}
this.getTodoLists();
})
.catch((err) => {
console.log(err);
});
},
Like down here: I'm writing on the left input and it shows even on the right input.
SOLVED:
With this computed property (with setter and getter) I solved my problem, now just the input in which I'm typing in is filled, and the todo can be post without a problem.
computed: {
getTitle: {
get: function () {
return "";
},
set: function (value) {
this.todo.title = value;
},
},
},
And this is the v-model with the new computed property instead of todo.title
<form
#submit.prevent="addTodo(todolist.id)"
class="td-inputs d-flex align-items-center justify-content-center"
>
<input v-model="getTitle" class="px-2" type="text" />
<button type="submit">
<i class="fas fa-plus fa-2x"></i>
</button>
</form>
You have a variable in data called "todo" and then you are reusing that variable name inside your inner v-for:
<div v-for="todo in todolist.todos" :key="todo.id" class="todo">
{{ todo.title }}
</div>
I think todo is referring to the todo from your data, not from the v-for. Thus, all todo items refer to the same variable. Try to rename one of them and see if it solves the problem.
You are binding your input to your todo declared data object.
Instead, you should bind your input to your todolist object in this way:
<div class="todolist" v-for="todolist in todolists" :key="todolist.id">
....
<input v-model="todolist.title" class="px-2" type="text" />
....
</div>
SOLVED:
With this computed property (with setter and getter) I solved my problem, now just the input in which I'm typing in is filled, and the todo can be post without a problem.
computed: {
getTitle: {
get: function () {
return "";
},
set: function (value) {
this.todo.title = value;
},
},
},
And this is the v-model with the new computed property instead of todo.title
<form
#submit.prevent="addTodo(todolist.id)"
class="td-inputs d-flex align-items-center justify-content-center"
>
<input v-model="getTitle" class="px-2" type="text" />
<button type="submit">
<i class="fas fa-plus fa-2x"></i>
</button>
</form>

Array of Dynamic Dependent Select Box in Vue.js

I have an array of Depend select box which contains Universities and courses. Each university has its own course. and I have built the course dropdown which depends on the university. I can successfully get university course from server request but the problem is when I change the select university it's changing all course fields. How I can get rid of the problem please give me some ideas. Thanks
<template>
<form #submit.prevent="handleSubmit">
<div class="col col-md-12">
<div v-for="(interest, index) in interests" :key="index" class="row">
<div class="col col-md-6">
<div class="form-group mb-4">
<label for="select-ins">Interested Universities </label>
<select
v-model="interest.institute_id"
class="form-control"
#change="onChangeUniversity($event)"
>
<option disabled value="">Select a University</option>
<option
v-for="institute in institutes"
:key="institute.id"
:value="institute.id"
>
{{ institute.institute_name }}
</option>
</select>
</div>
</div>
<div class="col col-md-6">
<div class="form-group mb-4">
<label>Interested Course</label>
<select
v-model="interest.course_id"
class="form-control"
#change="onChangeCourse($event)"
>
<option disabled value="">Select a Course</option>
<option
v-for="course in courses"
:key="course.id"
:value="course.id"
>
{{ course.course_name }}
</option>
</select>
</div>
</div>
<div class="col col-md-12 text-right">
<div class="row ml-4">
<div v-show="index == interests.length - 1">
<button
class="btn btn-warning mb-2 mr-2 btn-rounded"
#click.prevent="add"
>
Add
</button>
</div>
<div v-show="index || (!index && interests.length > 1)">
<button
class="btn btn-danger mb-2 mr-2 btn-rounded"
#click.prevent="remove"
>
Remove
</button>
</div>
</div>
</div>
</div>
</div>
</form>
</template>
<script>
export default {
data() {
return {
institutes: [],
courses: [],
interests: [
{
institute_id: "",
course_id: "",
},
],
};
},
mounted() {
axios.get("/institues").then((res) => {
this.institutes = res.data;
});
},
methods: {
onChangeUniversity(event) {
let universityId = event.target.value;
axios.get(`/institute-course/${universityId}`).then((res) => {
this.courses = res.data;
});
},
add() {
this.interests.push({
institute_id: "",
course_id: "",
});
},
remove(index) {
this.interests.splice(index, 1);
},
},
};
</script>
check screenshot
http://prntscr.com/115mkn5
lets start at your mounted hook.
you call for a API to receive all available institutes. so far so good. each institute got is own ID, this is important for later, lets keep that in mind.
now your using a function which will then call on a "change" event, like onChangeUniversity this is a good way on preventing to overload data in a page, nice idea just to fetch data only when they are needed.
then comes the tricky part which makes it difficult for you and everyone else reading your code.
you have this courses array in your data which normally belongs to the related institute. this array should not be handled as a second array apart from institutes, it should be a child of it.
like check this data structur:
institutes: [
{
institute_name: "WhatEver1",
id: 0,
courses: [{ course: 1 }, { course: 2 }, { course: 3 }],
}
]
instead of this:
institutes: [
{
institute_name: "WhatEver1",
id: 0,
},
],
courses: [{ course: 1 }, { course: 2 }, { course: 3 }],
the first option above is a good nested way to display your data as loop inside a loop.
which means you have to push your courses inside your institute of choice with the belonged id.
your onChangeUniversity function should than do something like this:
onChangeUniversity(event) {
let universityId = event.target.value;
axios.get(`/institute-course/${universityId}`).then((res) => {
const foundedId = this.institutes.findIndex(institute => institute.id === universityId)
this.institutes[foundedId].courses = res.data
});
},
after that its much easier to iterate over and display the data inside the options. and i am sure you will not have that issue anymore.
just try it like that first and give feedback.
Update
<div class="form-group mb-4">
<label>Interested Course</label>
<select
v-model="interest.course_id"
v-if="institute.courses.length !== 0" <-------HERE
class="form-control"
#change="onChangeCourse($event)"
>
<option disabled value="">Select a Course</option>
<option
v-for="course in institute.courses"
:key="course.id"
:value="course.id"
>
{{ course.course_name }}
</option>
</select>
</div>
you need a render condition to stop your courses loop from being iterated when there is no data inside.
also make sure you await till the fetching of courses is completed.
async onChangeUniversity(event) {
let universityId = event.target.value;
await axios.get(`/institute-course/${universityId}`).then((res) => {
this.courses = res.data;
});
},
and also in your mounted hook
async mounted() {
await axios.get("/institues").then((res) => {
this.institutes = res.data;
});
},
if you still struggle please give me a CodeSandbox of your current code.

Binding to array fields in vue.js

I want to make multiple 'in-place' editable date fields in table rows.
An example for a single field below works.
I show the currentdate (oldDate) as a label. User clicks on 'Change', an input field appears, after editing the user can Accept or Cancel.
https://jsfiddle.net/asrajan55/qv6crg84/
<div id="root">
<label>Test Date:</label>
<span v-show="!makeEditable"> {{ oldDate }} </span>
<span v-show = "makeEditable">
<input type="date" v-model="newDate" required=""/>
<button #click="acceptClicked">Accept</button>
<button name="cancel" #click="makeEditable=false">Cancel</button>
</span>
<button v-show="!makeEditable" #click="makeEditable=true" >Change</button>
</div>
new Vue({
el: "#root",
data: {
oldDate: '2019-02-04',
newDate: '2019-02-04',
makeEditable: false,
},
methods: {
acceptClicked(){
if (this.newDate!='') {
this.oldDate=this.newDate;
this.makeEditable=false;
}
}
}
});
However if I try multiple(2) fields the click event fires (sometimes) but nothing seems to happen. No errors in console. Also the Vue debugger in the browser does not immediately update the changed fields. Please help. I am desperate and pulling my hair out!
https://jsfiddle.net/asrajan55/9uhkr4w0/3/
<div id="root">
<div v-for="(item,index) in oldDates">
<label for="">Test Date:</label>
<span v-show="!editables[index]">{{item}}</span>
<input v-show="editables[index]" type="date" v-model="oldDates[index]"/>
<button v-show="editables[index]">Accept</button>
<button v-show="editables[index]" #click="editables[index]=false">Cancel</button>
<button v-show="!editables[index]" #click="makeEditable(index)">Change</button>
<hr />
</div>
</div>
new Vue({
el: "#root",
data: {
oldDates: ['2019-01-04', '2019-02-04'],
newDates: ['2019-01-04', '2019-02-04'],
editables: [false, false]
},
methods: {
makeEditable(index) {
alert(index);
this.editables[index] = true;
}
}
});
The problem was that you were mutating the array in place,
creating a new array reference and passing it would solve the issue
fixed here : https://jsfiddle.net/e3L2zcna/
makeEditable(index) {
this.editables = this.editables.map((val,i) => i===index || val);
}
Try using this.$set(this.editables, index, true);
Vue can't detect changes to arrays if you directly access an element using []. Read about it here:
https://vuejs.org/2016/02/06/common-gotchas/#Why-isn%E2%80%99t-the-DOM-updating

Validation Error messages on form load

About the issue
I am using Laravel 5.6.7 with vue.js. vee-validate is being used for validation
When the form loads, it shows validation error messages. User did not even click the submit button. Below is the screenshot.
Code
<template>
<div>
<form role="form">
<input v-validate data-vv-rules="required" type="text"
v-model="UpdateForm.First_Name">
<p v-if="errors.has('First Name')">{{ errors.first('First Name') }}</p>
<button type="button">
Update Profile
</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
UpdateForm: {
First_Name: ''
}
}
},
created() {
this.GetProfile();
},
methods: {
GetProfile() {
axios.post("some api url", {}).then(response => {
this.UpdateForm.First_Name = response.data.Data.First_Name;
});
}
}
}
</script>
Could I get rid of validation error messages on form load?
This is not the expected behavior. For initial validating you need to inform it with v-validate.initial.
Maybe you are defining this to happen when declaring v-validate or in other place.
Vue.use(VeeValidate);
new Vue({
el: '#demo'
})
.is-danger{
color: red;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate#latest/dist/vee-validate.js"></script>
<div id="demo">
<label>This one needs touching</label>
<input type="text" name="name" v-validate="'required'">
<div v-show="errors.has('name')" class="is-danger">Errors: {{ errors.first('name') }}</div>
<br/>
<label>This one does not need touching</label>
<input name="name2" v-validate.initial="'required'" type="text">
<div v-show="errors.has('name2')" class="is-danger">{{ errors.first('name2') }}</div>
</div>
Changed
this.editForm.First_Name = Data.User.First_Name;
to
if(Data.User.First_Name != null && Data.User.First_Name != "") {
this.editForm.First_Name = Data.User.First_Name;
}
and validation is working fine now. Basically the variable is not initialized.

vue js get multiple values from inputs

So I have 2 blocks of HTML, each containing 2 input fields and when submitting the form, I want to get all values from the inputs, and then create an object from the values...
As of know I've done it with plain vanilla JS and it works as it should, however if feels like to touching the DOM a bit to much, and also are very much depending on a specific DOM struckture, and therefore I was thinking there must be a better way, the VUE way so to speak, however im a bit stuck on how to do this the VUE way, which is why posting the question here in hope of getting some useful tips :)
HTML:
<form novalidate autocomplete="off">
<div class="input-block-container">
<div class="input-block">
<input type="text" placeholder="Insert name" name="name[]" />
<input-effects></input-effects>
</div>
<div class="input-block">
<input type="email" placeholder="Insert email address" name="email[]" />
<input-effects></input-effects>
</div>
</div>
<div class="input-block-container">
<div class="input-block">
<input type="text" placeholder="Insert name" name="name[]" />
<input-effects></input-effects>
</div>
<div class="input-block">
<input type="email" placeholder="Insert email address" name="email[]" />
<input-effects></input-effects>
</div>
</div>
<button class="button button--primary" #click.prevent="sendInvites"><span>Send</span></button>
</form>
JS:
methods: {
createDataObject() {
let emailValues = document.querySelectorAll('input[type="email"]');
emailValues.forEach((email) => {
let name = email.parentNode.parentNode.querySelector('input[type="text"]').value;
if(email.value !== "" && name !== "") {
this.dataObj.push({
email: email.value,
name
});
}
});
return JSON.stringify(this.dataObj);
},
sendInvites() {
const objectToSend = this.createDataObject();
console.log(objectToSend);
//TODO: Methods to send data to server
}
}
You can provide data properties for each of your inputs if you have static content.
data: function() {
return {
name1: '',
email1: '',
name2: '',
email2: ''
}
}
Then use them in your template:
<input type="text" placeholder="Insert name" v-model="name1" />
Access in method by this.name1
Try this
<div id="app">
<h1> Finds </h1>
<div v-for="find in finds">
<input name="name[]" v-model="find.name">
<input name="email[]" v-model="find.email">
</div>
<button #click="addFind">
New Find
</button>
<pre>{{ $data | json }}</pre>
</div>
Vue Component
new Vue({
el: '#app',
data: {
finds: []
},
methods: {
addFind: function () {
this.finds.push({ name: '', email: '' });
}
enter code here
}
});