v-model on a newly created property? - vue.js

On created I:
created: function () {
_.forEach(this.users, (user) => {
Vue.set(user, 'published', true);
});
}
In my template I have:
<div v-for="user in this.users">
<input type="checkbox" v-model="user.published">
</div>
The issue is the checkbox does not seem to be bound to the newly set published property. Why is this and how can I fix it?
Please note, I am unable to change how I am adding the published property to each user.

Try it that way:
<div v-for="user in users">
<input type="checkbox" v-model="user.published">
<button #click="user.published=!user.published">Toggle</button>
</div>
In your hook:
created() {
for (i in this.users) {
this.users[i].published = true;
}
}

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>

Vue.js adding a toggle and method to a button

I have a button that should toggle and also call a method. How do I achieve this? Seems like it can be only one or the other.
new Vue({
el: "#app",
data: {
iExist:false,
iDoNotExist: true,
},
methods: {
iSignedUpforThis: function(){
console.log("step X");
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p v-show="iExist"> i EXISTS </p>
<p v-show="iDoNotExist">
<strong> You are not found: </strong>
<form >
First name:<br>
<input type="text" name="firstname" value="Mickey">
<br>
Last name:<br>
<input type="text" name="lastname" value="Mouse">
<br><br>
</form>
<BUTTON v-on:click="iExists = iDoNotExist">
TOGGLE MY EXISTENCE
</BUTTON>
</div>
Move
iExists = iDoNotExist to a method:
methods: {
iSignedUpforThis: function(){
this.iExist = this.iDoNotExist
console.log("step X");
}
}
<button v-on:click="iSignedUpForThis">
TOGGLE MY EXISTENCE
</button>
First off to accomplish your desired result you need only one Boolean variable. Then in your method just switch between true and false. Also you have an invalid markup - there is closing tap p but no closing. That's why your example does not work.
Notice: it's bad idea to nest form tag inside p tag, so use div instead. It's considered a good practice to associate your input with it's label using label tag. Also there is shortcut for v-on:click - #click. data should be an function that returns an object, this will prevent . multiple instance to share the same object.
If you follow above recommendations you will make your code much clear and bug-less.
new Vue({
el: '#app',
data: {
isExist: false,
},
methods: {
method() {
this.isExist = !this.isExist
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-show="isExist">I exist</div>
<div v-show="!isExist">
<strong>You are not found:</strong>
<form>
<label>First name:<br>
<input type="text" name="firstname" value="Mickey">
</label>
<br>
<label>Last name:<br>
<input type="text" name="lastname" value="Mouse">
</label>
</form>
</div>
<button #click="method">Toggle</button>
</div>
It might be late but I am sure it will help others. Create a component ToggleButton.js and paste the below codes.
<template>
<label for="toggle_button">
<span v-if="isActive" class="toggle__label">On</span>
<span v-if="! isActive" class="toggle__label">Off</span>
<input type="checkbox" id="toggle_button" v-model="checkedValue">
<span class="toggle__switch"></span>
</label>
</template>
<script>
export default {
data() {
return {
currentState: false
}
},
computed: {
isActive() {
return this.currentState;
},
checkedValue: {
get() {
return this.defaultState
},
set(newValue) {
this.currentState = newValue;
}
}
}
}
</script>
Take a look at the article to learn more https://webomnizz.com/create-toggle-switch-button-with-vue-js/

How to validate a formcontrol with prepopulated data in Angular 5?

I have a form-group. In the form-group, i have a form-array. I have initialized the array with items created from data in the data model with the method as described in angular's documentation on reactive forms, under the section Initialize the secretLairs FormArray. The problem is i need to perform validation.required for each form control in the array. However, since the form-controls already hold values, i do not know how to perform validation.required. The documentation did not go further on how to validate formcontrols in a formarray that are prepopulated.
Here are my source codes:
.html
<!-- list of Questions -->
<div formArrayName="questions">
<!-- <div *ngFor="let que of Questions; let k=index"> -->
<div *ngFor="let question of Ques ; let i=index" [formGroupName]="i" >
<!-- The repeated questions template -->
<h4>{{question.ques}}</h4>
<div style="margin-left: 1em;">
<!-- <div class="form-group">
<label class="center-block">
<input class="form-control" formControlName="ques" >
</label>
</div> -->
<div class="form-group radio" *ngFor="let choice of
question.choices; let j = index">
<input type="radio" formControlName="choices"
class="custom-control-input" [value]="choice.choiceText">
<label>{{choice.choiceText}}</label>
</div>
<br>
<!-- End of the repeated questions template -->
</div>
</div>
</div>
<button type="submit" class="btn btn-danger"
[disabled]="!CheckListForm.valid">Submit</button>
</form>
.ts
export class CheckListFormComponent implements OnInit, OnChanges {
CheckListForm: FormGroup;
Ques: Questions[];
employmenttype = ['Permanent', 'contractor'];
constructor(private fb: FormBuilder,
private checklistservice: ChecklistService) {
this.CreateForm();
}
ngOnInit() {
this.checklistservice.getQuestions(1).subscribe(res =>{ this.Ques =res;
this.setquestions(this.Ques)
});
this.CheckListForm.get('EmploymentType').valueChanges.subscribe(
(EmploymentType: string) => {
if (EmploymentType === 'Permanent') {
this.CheckListForm.get('HRMS').setValidators([Validators.required]);
this.CheckListForm.get('CompanyName')
.setValidators([Validators.nullValidator]);
} else if (EmploymentType === 'contractor') {
this.CheckListForm.get('CompanyName').
setValidators([Validators.required]);
this.CheckListForm.get('HRMS').
setValidators([Validators.nullValidator]);
}
this.CheckListForm.get('HRMS').updateValueAndValidity();
this.CheckListForm.get('CompanyName').updateValueAndValidity();
}
)
}
CreateForm() {
this.CheckListForm = this.fb.group({
name: ['', Validators.required],
EmploymentType: ['', Validators.required],
HRMS: [''],
CompanyName:[''],
questions: this.fb.array([])
})
}
get questions(): FormArray {
return this.CheckListForm.get('questions') as FormArray;
}
setquestions(questions: Questions[]) {
const QuestionsFGs = questions.map(questions => this.fb.group(questions));
const QuestionsFormArray = this.fb.array(QuestionsFGs);
this.CheckListForm.setControl('questions', QuestionsFormArray);
}
As usual, as there is no response from anyone, I will post the answer which i have painstakingly solved.
You cannot validate form-controls through the method i have performed(see my codes). The reason is because the form-controls already hold data and is not empty in the first place. Hence, validation.required will not work.
A solution will be to instead push empty form-controls for each item in the array of the data model.
Validation.required will then work for this case.

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 2 - use same form for adding new and editing

I have following template:
<template>
<div>
<form #submit="save">
<div class="field">
<label class="label">Name</label>
<div class="control">
<input class="input" type="text" placeholder="Name" :value="book.title">
</div>
</div>
<div class="field">
<label class="label">Name</label>
<div class="control">
<input class="input" type="text" placeholder="Name" :value="book.author">
</div>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
book : {}
}
},
methods: {
save() {
}
},
created() {
if(this.$store.state.book != 'undefined'){
this.book = this.$store.state.book;
}
},
computed: {}
}
</script>
<style></style>
So far everything works fine if the book is pass with the this.$store.state.book, but if this is not passed the form is failing, with the error message:
** Error in render function: "TypeError: Cannot read property 'title' of undefined"**
I thought that passing the empty object would dynamically bind the book object and auto create the params.
Is it possible to use the same form for both adding new and editing?
I tried your code, and all you have to do is remove the 'quotes' from 'undefined'. Obviously, it's a string as is, and not a js thing.