Vue 2 - use same form for adding new and editing - vue.js

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.

Related

Laravel + vue: Error message only showing the first letter of the sentence

I'm just starting to learn laravel+vue. I was able to follow a tutorial from this yt: https://www.youtube.com/watch?v=JZDmBWRPWlw. Though it seems outdated, I was still able to follow his steps. I'm using the laravel-mix 6.0.6 and vue 2.6.12.
Using inspect element>network, I can see that I'm throwing the correct error message in array.
{"component":"Users\/Create","props":{"app":{"name":"Laravel"},"errors":{"name":"The name field is required.","email":"The email field is required."}},"url":"\/users\/create","version":"207fd484b7c2ceeff7800b8c8a11b3b6"}
But somehow it is not displaying the complete error message. Right now it just show the first letter of the sentence. LOL. Sample error message is: The email field is required and it will just display the letter "T". Below is my Create.vue. Basically it is just a user create form with simple validation.
Create.vue
<template>
<layout>
<div class="container">
<div class="col-md-6">
<div v-if="Object.keys(errors).length > 0" class="alert alert-danger mt-4">
{{ errors[Object.keys(errors)[0]][0] }}
</div>
<form action="/users" method="POST" class="my-5" #submit.prevent="createUser">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control" id="name" placeholder="Name" v-model="form.name">
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control" id="email" placeholder="Email" v-model="form.email">
</div>
<div class="form-group">
<label for="name">Password</label>
<input type="password" class="form-control" id="password" placeholder="Password" v-model="form.password">
</div>
<button type="submit" class="btn btn-primary">Create User</button>
</form>
</div>
</div>
</layout>
</template>
<script>
import Layout from '../../Shared/Layout'
export default {
props: ['errors'],
components: {
Layout,
},
data() {
return {
form: {
name: '',
email: '',
password: '',
}
}
},
methods: {
createUser() {
this.$inertia.post('/users', this.form)
.then(() => {
// code
})
}
}
}
</script>
Edit:
I have this error on my console
[Vue warn]: Error in v-on handler: "TypeError: Cannot read property
'then' of undefined"
found in
---> at resources/js/Pages/Users/Create.vue
Your error call is probably getting only the first letter due to [0]. Try to change to:
{{ errors[Object.keys(errors)[0]] }}
Strings can also be read as arrays. If you do this:
$a = "TEST";
echo $a[0];
That would print only T.
That is probably the problem.

How to create data binding with array input ( multiple input) on vue

I have form input using vue js and this input have button to add more column input this button. like this picture image. So on this single input I use v-model and its work , but on my new form this v-model and data binding didn't work. You can see my form like this :
on this new from , this v-model didn't work
<script type="x-template" id="form-input">
<div class="field">
<div class="field-body">
<div class="field">
<label class="label">Nama Barang: </label>
<p class="control is-expanded">
<input
type="text"
id="nama_barang"
class="input"
// v-model="userData.nama_barang" ---> if i add this v-model like this this form not showing , if i remove this its work , but i need v-model to store data
placeholder="nama barang">
</p>
</div>
<div class="field">
<label class="label">Satuan: </label>
<p class="control is-expanded">
<input
type="text"
id="satuan"
class="input"
// v-model="userData.satuan" ---> if i add this v-model like this this form not showing , if i remove this its work , but i need v-model to store data
placeholder="Satuan">
</p>
</div>
<div class="field">
<label class="label">Quantity:</label>
<p class="control is-expanded">
<input
type="number"
id="qtt"
class="input"
//v-model="userData.qtt" ---> if i add this v-model like this this form not showing , if i remove this its work , but i need v-model to store data
placeholder="Qtt" >
</p>
</div>
<div class="field">
<label class="label">Harga:</label>
<p class="control is-expanded">
<input class="input"
type="number"
id="harga"
//v-model="userData.harga" ---> if i add this v-model like this this form not showing , if i remove this its work , but i need v-model to store data
placeholder="Harga">
</p>
</div>
<div class="field">
<label class="label">Harga Total:</label>
<p class="control is-expanded">
{{(userData.qtt * userData.harga) | currency}} // its didnt work because this v-model didnt work
</p>
</div>
</div>
</div>
and its my export default
export default {
data(){
return{
fields: [],
count: 0,
userData:[{
rek_id:'',
tgl_pengajuan:'',
suplier_id:'',
status:'Aktif',
}],
rek:{},
suplier:{},
fields: [],
count: 0,
}
},
components:{
},
methods:{
submit() {
this.errors = {};
axios.post('/pengadaan/store_induk_pencairan', this.userData).then(response => {
window.location = response.data.redirect;
}).catch(error => {
if (error.response.status === 422) {
this.errors = error.response.data.errors || {};
}
});
},
addFormElement: function(type) {
this.fields.push({
'type': type,
id: this.count++
});
},
},
so how this v-model on new form can work like one single form ? this v-model only work on only first form
userData is a array, but in the v-model, you are calling like a js object

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/

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
}
});