ERROR 422 when update data inside modal with axios.put [laravel + vuejs 3] - vue.js

I am using Laravel + VueJS 3 to build a small project,
I use axios.put method for update details for single user in a table row via a modal, but I have problems when I click on submit button of a form inside a modal with axios.put, even I filled all data for all inputs but It still said the errors below, can you guys show me how can I fix this please?
Thanks!
ERROR
My backend:
public function updateUser(Request $req, User $user)
{
$req->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email,' . $user->id,
'password' => 'same:confirmPassword|max:64',
'roles' => 'required',
]);
$input = $req->all();
if (!empty($input['password'])) {
$input['password'] = Hash::make($input['password']);
} else {
$input = Arr::except($input, 'password');
}
$user->update($input);
$user->syncRoles($input['roles']);
return $this->sendResponse($user, 'Updated!');
}
My JS Code:
import axios from "axios";
let API_URL = "http://localhost:8000";
export default {
name: "manageUsers",
components: {},
data() {
return {
users: [],
userInfo: {
id: 0,
name: "",
username: "",
phone: "",
email: "",
password: "",
},
};
},
methods: {
refreshUsers() {
axios.get(`${API_URL}/api/users/allusers`).then((res) => {
this.users = res.data.data;
});
},
getUserInfo(user) {
axios
.get(`${API_URL}/api/users/show/` + user.id)
.then((res) => {
this.userInfo.id = res.data.data.id;
this.userInfo.name = res.data.data.name;
this.userInfo.email = res.data.data.email;
this.userInfo.username = res.data.data.username;
this.userInfo.phone = res.data.data.phone;
})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
},
updateUser() {
axios
.put(`${API_URL}/api/users/update/${this.userInfo.id}`)
.then((res) => {
this.refreshUsers();
alert(res.data);
})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
},
},
mounted() {
this.refreshUsers();
},
};
My VueJS template code:
<template>
<table class="table table-striped" id="datatable">
<tbody>
<tr v-for="(user, id) in users" :key="user.id">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.username }}</td>
<td class="text-right">
<button
class="btn btn-link btn-warning btn-icon btn-sm"
data-toggle="modal" data-target="#userEditModal"
#click="getUserInfo(user)">
<i class="tim-icons icon-pencil"></i>
</button>
</td>
</tr>
</tbody>
</table>
<!-- EDIT USER MODAL -->
<div class="modal modal-black fade" id="userEditModal" tabindex="-1" role="dialog"
aria-labelledby="userEditModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="userEditModal">
Edit user <strong class="text-primary">{{ userInfo.username }}</strong>
</h4>
<button type="button" class="close"
data-dismiss="modal" aria-hidden="true">
<i class="tim-icons icon-simple-remove"></i>
</button>
</div>
<form class="form-horizontal">
<div class="modal-body">
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Username</label>
<div class="col-md-9">
<div class="form-group">
<input type="text" class="form-control" name="username"
v-model="userInfo.username" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Name</label>
<div class="col-md-9">
<div class="form-group">
<input type="text" class="form-control" name="name"
v-model="userInfo.name" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Email</label>
<div class="col-md-9">
<div class="form-group">
<input type="email" name="email" class="form-control"
v-model="userInfo.email" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Roles</label>
<div class="col-md-9">
<div class="form-group">
<input type="roles" name="roles" class="form-control"
v-model="userInfo.roles" />
</div>
</div>
</div>
</div>
<div class="modal-footer d-flex flex-row">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button type="submit" class="btn btn-primary" data-dismiss="modal"
#click="updateUser()">
Save changes
</button>
</div>
</form>
</div>
</div>
</div>
<!-- END EDIT USER MODAL -->
</template>```

I think you're not passing any parameters to your put call. axios docs
example:
axios.put('https://httpbin.org/put', { hello: 'world' });
When an issue like this arises you can always check your network tab in your browser. to see what data is send to your server.

Related

The below given code is not working for me. And giving an error "vueuploadComponent.html:396 Uncaught ReferenceError: FileUpload is not defined"

Here is the code in vue.js for multi Image uploading. Actually this code is not working for me I am facing an error "vueuploadComponent.html:396 Uncaught ReferenceError: FileUpload is not defined". So here I thing i doing some thing wrong with import a module. So please let me know where I am going wrong.
<template>
<div id = "vueUpload" class="example-full">
<button type="button" class="btn btn-danger float-right btn-is-option" #click.prevent="isOption = !isOption">
<i class="fa fa-cog" aria-hidden="true"></i>
Options
</button>
<h1 id="example-title" class="example-title">Full Example</h1>
<div v-show="$refs.upload && $refs.upload.dropActive" class="drop-active">
<h3>Drop files to upload</h3>
</div>
<div class="upload" v-show="!isOption">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Thumb</th>
<th>Name</th>
<th>Width</th>
<th>Height</th>
<th>Size</th>
<th>Speed</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-if="!files.length">
<td colspan="9">
<div class="text-center p-5">
<h4>Drop files anywhere to upload<br/>or</h4>
<label :for="name" class="btn btn-lg btn-primary">Select Files</label>
</div>
</td>
</tr>
<tr v-for="(file, index) in files" :key="file.id">
<td>{{index}}</td>
<td>
<img class="td-image-thumb" v-if="file.thumb" :src="file.thumb" />
<span v-else>No Image</span>
</td>
<td>
<div class="filename">
{{file.name}}
</div>
<div class="progress" v-if="file.active || file.progress !== '0.00'">
<div :class="{'progress-bar': true, 'progress-bar-striped': true, 'bg-danger': file.error, 'progress-bar-animated': file.active}" role="progressbar" :style="{width: file.progress + '%'}">{{file.progress}}%</div>
</div>
</td>
<td>{{file.width || 0}}</td>
<td>{{file.height || 0}}</td>
<td>{{$formatSize(file.size)}}</td>
<td>{{$formatSize(file.speed)}}</td>
<td v-if="file.error">{{file.error}}</td>
<td v-else-if="file.success">success</td>
<td v-else-if="file.active">active</td>
<td v-else></td>
<td>
<div class="btn-group">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button">
Action
</button>
<div class="dropdown-menu">
<a :class="{'dropdown-item': true, disabled: file.active || file.success || file.error === 'compressing' || file.error === 'image parsing'}" href="#" #click.prevent="file.active || file.success || file.error === 'compressing' ? false : onEditFileShow(file)">Edit</a>
<a :class="{'dropdown-item': true, disabled: !file.active}" href="#" #click.prevent="file.active ? $refs.upload.update(file, {error: 'cancel'}) : false">Cancel</a>
<a class="dropdown-item" href="#" v-if="file.active" #click.prevent="$refs.upload.update(file, {active: false})">Abort</a>
<a class="dropdown-item" href="#" v-else-if="file.error && file.error !== 'compressing' && file.error !== 'image parsing' && $refs.upload.features.html5" #click.prevent="$refs.upload.update(file, {active: true, error: '', progress: '0.00'})">Retry upload</a>
<a :class="{'dropdown-item': true, disabled: file.success || file.error === 'compressing' || file.error === 'image parsing'}" href="#" v-else #click.prevent="file.success || file.error === 'compressing' || file.error === 'image parsing' ? false : $refs.upload.update(file, {active: true})">Upload</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#" #click.prevent="$refs.upload.remove(file)">Remove</a>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="example-foorer">
<div class="footer-status float-right">
Drop: {{$refs.upload ? $refs.upload.drop : false}},
Active: {{$refs.upload ? $refs.upload.active : false}},
Uploaded: {{$refs.upload ? $refs.upload.uploaded : true}},
Drop active: {{$refs.upload ? $refs.upload.dropActive : false}}
</div>
<div class="btn-group">
<file-upload
class="btn btn-primary dropdown-toggle"
:post-action="postAction"
:put-action="putAction"
:extensions="extensions"
:accept="accept"
:multiple="multiple"
:directory="directory"
:create-directory="createDirectory"
:size="size || 0"
:thread="thread < 1 ? 1 : (thread > 5 ? 5 : thread)"
:headers="headers"
:data="data"
:drop="drop"
:drop-directory="dropDirectory"
:add-index="addIndex"
v-model="files"
#input-filter="inputFilter"
#input-file="inputFile"
ref="upload">
<i class="fa fa-plus"></i>
Select
</file-upload>
<div class="dropdown-menu">
<label class="dropdown-item" :for="name">Add files</label>
<a class="dropdown-item" href="#" #click="onAddFolder">Add folder</a>
<a class="dropdown-item" href="#" #click.prevent="addData.show = true">Add data</a>
</div>
</div>
<button type="button" class="btn btn-success" v-if="!$refs.upload || !$refs.upload.active" #click.prevent="$refs.upload.active = true">
<i class="fa fa-arrow-up" aria-hidden="true"></i>
Start Upload
</button>
<button type="button" class="btn btn-danger" v-else #click.prevent="$refs.upload.active = false">
<i class="fa fa-stop" aria-hidden="true"></i>
Stop Upload
</button>
</div>
</div>
<div class="option" v-show="isOption">
<div class="form-group">
<label for="accept">Accept:</label>
<input type="text" id="accept" class="form-control" v-model="accept">
<small class="form-text text-muted">Allow upload mime type</small>
</div>
<div class="form-group">
<label for="extensions">Extensions:</label>
<input type="text" id="extensions" class="form-control" v-model="extensions">
<small class="form-text text-muted">Allow upload file extension</small>
</div>
<div class="form-group">
<label>PUT Upload:</label>
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="radio" name="put-action" id="put-action" value="" v-model="putAction"> Off
</label>
</div>
<div class="form-check">
<label class="form-check-label">
<input class="form-check-input" type="radio" name="put-action" id="put-action" value="/upload/put" v-model="putAction"> On
</label>
</div>
<small class="form-text text-muted">After the shutdown, use the POST method to upload</small>
</div>
<div class="form-group">
<label for="thread">Thread:</label>
<input type="number" max="5" min="1" id="thread" class="form-control" v-model.number="thread">
<small class="form-text text-muted">Also upload the number of files at the same time (number of threads)</small>
</div>
<div class="form-group">
<label for="size">Max size:</label>
<input type="number" min="0" id="size" class="form-control" v-model.number="size">
</div>
<div class="form-group">
<label for="minSize">Min size:</label>
<input type="number" min="0" id="minSize" class="form-control" v-model.number="minSize">
</div>
<div class="form-group">
<label for="autoCompress">Automatically compress:</label>
<input type="number" min="0" id="autoCompress" class="form-control" v-model.number="autoCompress">
<small class="form-text text-muted" v-if="autoCompress > 0">More than {{$formatSize(autoCompress)}} files are automatically compressed</small>
<small class="form-text text-muted" v-else>Set up automatic compression</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="add-index" class="form-check-input" v-model="addIndex"> Start position to add
</label>
</div>
<small class="form-text text-muted">Add a file list to start the location to add</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="drop" class="form-check-input" v-model="drop"> Drop
</label>
</div>
<small class="form-text text-muted">Drag and drop upload</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="drop-directory" class="form-check-input" v-model="dropDirectory"> Drop directory
</label>
</div>
<small class="form-text text-muted">Not checked, filter the dragged folder</small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="create-directory" class="form-check-input" v-model="createDirectory"> Create Directory
</label>
</div>
<small class="form-text text-muted">The directory file will send an upload request. The mime type is <code>text/directory</code></small>
</div>
<div class="form-group">
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" id="upload-auto" class="form-check-input" v-model="uploadAuto"> Auto start
</label>
</div>
<small class="form-text text-muted">Automatically activate upload</small>
</div>
<div class="form-group">
<button type="button" class="btn btn-primary btn-lg btn-block" #click.prevent="isOption = !isOption">Confirm</button>
</div>
</div>
<div :class="{'modal-backdrop': true, 'fade': true, show: addData.show}"></div>
<div :class="{modal: true, fade: true, show: addData.show}" id="modal-add-data" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add data</h5>
<button type="button" class="close" #click.prevent="addData.show = false">
<span>×</span>
</button>
</div>
<form #submit.prevent="onAddData">
<div class="modal-body">
<div class="form-group">
<label for="data-name">Name:</label>
<input type="text" class="form-control" required id="data-name" placeholder="Please enter a file name" v-model="addData.name">
<small class="form-text text-muted">Such as <code>filename.txt</code></small>
</div>
<div class="form-group">
<label for="data-type">Type:</label>
<input type="text" class="form-control" required id="data-type" placeholder="Please enter the MIME type" v-model="addData.type">
<small class="form-text text-muted">Such as <code>text/plain</code></small>
</div>
<div class="form-group">
<label for="content">Content:</label>
<textarea class="form-control" required id="content" rows="3" placeholder="Please enter the file contents" v-model="addData.content"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" #click.prevent="addData.show = false">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
<div :class="{'modal-backdrop': true, 'fade': true, show: editFile.show}"></div>
<div :class="{modal: true, fade: true, show: editFile.show}" id="modal-edit-file" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit file</h5>
<button type="button" class="close" #click.prevent="editFile.show = false">
<span>×</span>
</button>
</div>
<form #submit.prevent="onEditorFile">
<div class="modal-body">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" class="form-control" required id="name" placeholder="Please enter a file name" v-model="editFile.name">
</div>
<div class="form-group" v-if="editFile.show && editFile.blob && editFile.type && editFile.type.substr(0, 6) === 'image/'">
<label>Image: </label>
<div class="edit-image">
<img :src="editFile.blob" ref="editImage" />
</div>
<div class="edit-image-tool">
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary" #click="editFile.cropper.rotate(-90)" title="cropper.rotate(-90)"><i class="fa fa-undo" aria-hidden="true"></i></button>
<button type="button" class="btn btn-primary" #click="editFile.cropper.rotate(90)" title="cropper.rotate(90)"><i class="fa fa-repeat" aria-hidden="true"></i></button>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary" #click="editFile.cropper.crop()" title="cropper.crop()"><i class="fa fa-check" aria-hidden="true"></i></button>
<button type="button" class="btn btn-primary" #click="editFile.cropper.clear()" title="cropper.clear()"><i class="fa fa-remove" aria-hidden="true"></i></button>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" #click.prevent="editFile.show = false">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script src='https://unpkg.com/vue#2.5.16/dist/vue.js'></script>
<script type="module">
import Cropper from 'cropperjs'
import ImageCompressor from '#xkeshi/image-compressor'
import { FileUpload } from "vue-upload-component";
</script>
<script>
new Vue({
el: '#vueUpload',
components: {
FileUpload,
},
data() {
return {
files: [],
accept: 'image/png,image/gif,image/jpeg,image/webp',
extensions: 'gif,jpg,jpeg,png,webp',
// extensions: ['gif', 'jpg', 'jpeg','png', 'webp'],
// extensions: /\.(gif|jpe?g|png|webp)$/i,
minSize: 1024,
size: 1024 * 1024 * 10,
multiple: true,
directory: false,
drop: true,
dropDirectory: true,
createDirectory: false,
addIndex: false,
thread: 3,
name: 'file',
postAction: '/upload/post',
putAction: '/upload/put',
headers: {
'X-Csrf-Token': 'xxxx',
},
data: {
'_csrf_token': 'xxxxxx',
},
autoCompress: 1024 * 1024,
uploadAuto: false,
isOption: false,
addData: {
show: false,
name: '',
type: '',
content: '',
},
editFile: {
show: false,
name: '',
}
}
},
watch: {
'editFile.show'(newValue, oldValue) {
// 关闭了 自动删除 error
if (!newValue && oldValue) {
this.$refs.upload.update(this.editFile.id, { error: this.editFile.error || '' })
}
if (newValue) {
this.$nextTick( () => {
if (!this.$refs.editImage) {
return
}
let cropper = new Cropper(this.$refs.editImage, {
autoCrop: false,
})
this.editFile = {
...this.editFile,
cropper
}
})
}
},
'addData.show'(show) {
if (show) {
this.addData.name = ''
this.addData.type = ''
this.addData.content = ''
}
},
},
methods: {
inputFilter(newFile, oldFile, prevent) {
if (newFile && !oldFile) {
// Before adding a file
// 添加文件前
// Filter system files or hide files
// 过滤系统文件 和隐藏文件
if (/(\/|^)(Thumbs\.db|desktop\.ini|\..+)$/.test(newFile.name)) {
return prevent()
}
// Filter php html js file
// 过滤 php html js 文件
if (/\.(php5?|html?|jsx?)$/i.test(newFile.name)) {
return prevent()
}
// Automatic compression
// 自动压缩
if (newFile.file && newFile.error === "" && newFile.type.substr(0, 6) === 'image/' && this.autoCompress > 0 && this.autoCompress < newFile.size) {
newFile.error = 'compressing'
const imageCompressor = new ImageCompressor(null, {
convertSize: 1024 * 1024,
maxWidth: 512,
maxHeight: 512,
})
imageCompressor.compress(newFile.file)
.then((file) => {
this.$refs.upload.update(newFile, { error: '', file, size: file.size, type: file.type })
})
.catch((err) => {
this.$refs.upload.update(newFile, { error: err.message || 'compress' })
})
}
}
if (newFile && newFile.error === "" && newFile.file && (!oldFile || newFile.file !== oldFile.file)) {
// Create a blob field
// 创建 blob 字段
newFile.blob = ''
let URL = (window.URL || window.webkitURL)
if (URL) {
newFile.blob = URL.createObjectURL(newFile.file)
}
// Thumbnails
// 缩略图
newFile.thumb = ''
if (newFile.blob && newFile.type.substr(0, 6) === 'image/') {
newFile.thumb = newFile.blob
}
}
// image size
// image 尺寸
if (newFile && newFile.error === '' && newFile.type.substr(0, 6) === "image/" && newFile.blob && (!oldFile || newFile.blob !== oldFile.blob)) {
newFile.error = 'image parsing'
let img = new Image();
img.onload = () => {
this.$refs.upload.update(newFile, {error: '', height: img.height, width: img.width})
}
img.οnerrοr = (e) => {
this.$refs.upload.update(newFile, { error: 'parsing image size'})
}
img.src = newFile.blob
}
},
// add, update, remove File Event
inputFile(newFile, oldFile) {
if (newFile && oldFile) {
// update
if (newFile.active && !oldFile.active) {
// beforeSend
// min size
if (newFile.size >= 0 && this.minSize > 0 && newFile.size < this.minSize) {
this.$refs.upload.update(newFile, { error: 'size' })
}
}
if (newFile.progress !== oldFile.progress) {
// progress
}
if (newFile.error && !oldFile.error) {
// error
}
if (newFile.success && !oldFile.success) {
// success
}
}
if (!newFile && oldFile) {
// remove
if (oldFile.success && oldFile.response.id) {
// $.ajax({
// type: 'DELETE',
// url: '/upload/delete?id=' + oldFile.response.id,
// })
}
}
// Automatically activate upload
if (Boolean(newFile) !== Boolean(oldFile) || oldFile.error !== newFile.error) {
if (this.uploadAuto && !this.$refs.upload.active) {
this.$refs.upload.active = true
}
}
},
alert(message) {
alert(message)
},
onEditFileShow(file) {
this.editFile = { ...file, show: true }
this.$refs.upload.update(file, { error: 'edit' })
},
onEditorFile() {
if (!this.$refs.upload.features.html5) {
this.alert('Your browser does not support')
this.editFile.show = false
return
}
let data = {
name: this.editFile.name,
error: '',
}
if (this.editFile.cropper) {
let binStr = atob(this.editFile.cropper.getCroppedCanvas().toDataURL(this.editFile.type).split(',')[1])
let arr = new Uint8Array(binStr.length)
for (let i = 0; i < binStr.length; i++) {
arr[i] = binStr.charCodeAt(i)
}
data.file = new File([arr], data.name, { type: this.editFile.type })
data.size = data.file.size
}
this.$refs.upload.update(this.editFile.id, data)
this.editFile.error = ''
this.editFile.show = false
},
// add folder
onAddFolder() {
if (!this.$refs.upload.features.directory) {
this.alert('Your browser does not support')
return
}
let input = document.createElement('input')
input.style = "background: rgba(255, 255, 255, 0);overflow: hidden;position: fixed;width: 1px;height: 1px;z-index: -1;opacity: 0;"
input.type = 'file'
input.setAttribute('allowdirs', true)
input.setAttribute('directory', true)
input.setAttribute('webkitdirectory', true)
input.multiple = true
document.querySelector("body").appendChild(input)
input.click()
input.onchange = (e) => {
this.$refs.upload.addInputFile(input).then(function() {
document.querySelector("body").removeChild(input)
})
}
},
onAddData() {
this.addData.show = false
if (!this.$refs.upload.features.html5) {
this.alert('Your browser does not support')
return
}
let file = new window.File([this.addData.content], this.addData.name, {
type: this.addData.type,
})
this.$refs.upload.add(file)
}
}
})
</script>
Assuming you're using Lian Yue's vue-upload-component and have installed it successfully, try removing the curly braces from your import:
import FileUpload from "vue-upload-component";
This will set FileUpload to the default export from vue-upload-component which I believe is what you want

Uncaught TypeError: _ctx. is not a function [VueJS 3]

I have problems when I put all my buttons inside one component and use click event to trigger the modals, I can put single button to single component and use event click with created custom components but I am questioning is there any way to put all buttons inside a components and that still works.
Buttons.vue
<template>
<button
class="btn btn-link btn-info btn-icon btn-sm"
data-toggle="modal" data-target="#userInfoModal"
#click="getUserInfo(user)">
<i class="icon-alert-circle-exc"></i>
</button>
<button
class="btn btn-link btn-warning btn-icon btn-sm"
data-toggle="modal" data-target="#userEditModal"
#click="getUserInfo(user)">
<i class="icon-pencil"></i>
</button>
<button
class="btn btn-link btn-danger btn-icon btn-sm"
data-toggle="modal" data-target="#userRemoveModal"
#click="getUserInfo(user)">
<i class="icon-simple-remove"></i>
</button>
</template>
usersManage.vue
<template>
<div class="col-md-12">
<div class="card">
<div class="card-header d-flex flex-row">
<h4 class="card-title align-self-center">Users Manager</h4>
<button class="btn btn-success btn-fab btn-icon btn-round mb-3 ml-2"
data-toggle="modal" data-target="#addUserModal">
<i class="icon-add"></i>
</button>
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Email</th>
<th>Username</th>
<th class="text-right">Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="(user, id) in users" :key="user.id">
<td>{{ user.id }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
<td>{{ user.username }}</td>
<td class="text-right">
<!--- BUTTON COMPONENT HERE --->
<Buttons />
<!--- END BUTTON COMPONENT --->
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- MODALS -->
<!-- ADD USER MODAL -->
<div
class="modal modal-black fade" id="addUserModal"
tabindex="-1" role="dialog" aria-labelledby="addUserModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="addUserModal">Add new user</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<i class="tim-icons icon-simple-remove"></i>
</button>
</div>
<form class="form-horizontal">
<div class="modal-body">
<div class="d-flex flex-row">
<label class="col-md-4 col-form-label">Name</label>
<div class="col-md-6">
<div class="form-group">
<input
type="name"
name="name"
class="form-control"
v-model="newUser.name"
/>
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-4 col-form-label">Username</label>
<div class="col-md-6">
<div class="form-group">
<input type="username" name="username" class="form-control"
v-model="newUser.username" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-4 col-form-label">Email</label>
<div class="col-md-6">
<div class="form-group">
<input type="email" name="email" class="form-control"
v-model="newUser.email" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-4 col-form-label">Password</label>
<div class="col-md-6">
<div class="form-group">
<input type="password" name="password" class="form-control"
v-model="newUser.password" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-4 col-form-label">Confirm Password</label>
<div class="col-md-6">
<div class="form-group">
<input type="password" name="confirmPassword" class="form-control"
v-model="newUser.confirmPassword" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-4 col-form-label">Roles</label>
<div class="col-md-6">
<div class="form-group">
<input type="roles" name="roles" class="form-control"
v-model="newUser.roles" />
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Cancel
</button>
<button type="submit" class="btn btn-primary" #click.stop.prevent="addUser()">
Create user
</button>
</div>
</form>
</div>
</div>
</div>
<!-- END ADD USER MODAL -->
<!-- USER's INFO MODAL -->
<div class="modal modal-black fade" id="userInfoModal"
tabindex="-1" role="dialog" aria-labelledby="userInfoModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="userInfoModal">
<strong class="text-primary">
{{ userInfo.username }} - {{ userInfo.name }}
</strong>'s Basic Information
</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<i class="tim-icons icon-simple-remove"></i>
</button>
</div>
<div class="modal-body" id="userInfo">
<div class="row">
<div class="col-6">
<p>ID: {{ userInfo.id }}</p>
<p>Phone: {{ userInfo.phone }}</p>
<p>Username: {{ userInfo.username }}</p>
</div>
<div class="col-6">
<p>Name: {{ userInfo.name }}</p>
<p>Email: {{ userInfo.email }}</p>
</div>
</div>
</div>
<div class="modal-footer d-flex flex-row-reverse">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
<!-- END USER's INFO MODAL -->
<!-- EDIT USER MODAL -->
<div class="modal modal-black fade" id="userEditModal"
tabindex="-1" role="dialog" aria-labelledby="userEditModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="userEditModal">
Edit user
<strong class="text-primary">
{{ userInfo.name }} - {{ userInfo.username }}
</strong>
</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<i class="tim-icons icon-simple-remove"></i>
</button>
</div>
<form class="form-horizontal" method="PUT">
<div class="modal-body">
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Username</label>
<div class="col-md-9">
<div class="form-group">
<input type="text" class="form-control" name="username"
v-model="userInfo.username" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Name</label>
<div class="col-md-9">
<div class="form-group">
<input type="text" class="form-control" name="username"
v-model="userInfo.name" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Email</label>
<div class="col-md-9">
<div class="form-group">
<input type="email" name="email" class="form-control"
v-model="userInfo.email" />
</div>
</div>
</div>
<div class="d-flex flex-row">
<label class="col-md-3 col-form-label">Roles</label>
<div class="col-md-9">
<div class="form-group">
<input type="roles" name="roles" class="form-control"
v-model="userInfo.roles" />
</div>
</div>
</div>
</div>
<div class="modal-footer d-flex flex-row">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Close
</button>
<button type="submit" class="btn btn-primary" data-dismiss="modal"
#click="updateUser()">
Save Changes
</button>
</div>
</form>
</div>
</div>
</div>
<!-- END EDIT USER MODAL -->
<!-- REMOVE USER MODAL -->
<div class="modal modal-black fade" id="userRemoveModal"
tabindex="-1" role="dialog" aria-labelledby="userRemoveModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="userRemoveModal">
Confirm delete user
<strong class="text-primary">
{{ userInfo.username }} - {{ userInfo.name }}
</strong>?
</h4>
<button
type="button"
class="close"
data-dismiss="modal"
aria-hidden="true"
>
<i class="tim-icons icon-simple-remove"></i>
</button>
</div>
<div class="modal-body h4 text-white text-center mt-4">
Delete user
<strong class="text-danger">
{{ userInfo.username }} - {{ userInfo.name }}
</strong>
?
</div>
<div class="modal-footer d-flex flex-row">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Cancel
</button>
<button type="button" class="btn btn-danger" data-dismiss="modal"
#click="removeUser()">
Delete User
</button>
</div>
</div>
</div>
</div>
<!-- END REMOVE USER MODAL -->
<!-- END MODALS -->
</template>
<script>
import axios from "axios";
import InfoButton from ".../components/cores/Buttons.vue";
const API_URL = "http://localhost:8000/api";
export default {
name: "manageUsers",
components: { InfoButton },
data() {
return {
users: [],
newUser: {
name: null,
username: null,
email: null,
password: null,
confirmPassword: null,
roles: null,
},
userInfo: {
id: 0,
name: "",
username: "",
phone: "",
email: "",
password: "",
},
};
},
methods: {
refreshUsers() {
axios.get(`${API_URL}/users/allusers`).then((res) => {
this.users = res.data.data;
});
},
addUser() {
axios
.post(`${API_URL}/users/create`, this.newUser)
.then((res) => {})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
this.$router.push("/manager/users");
},
getUserInfo(user) {
axios
.get(`${API_URL}/users/show/` + user.id)
.then((res) => {
this.userInfo.id = res.data.data.id;
this.userInfo.name = res.data.data.name;
this.userInfo.email = res.data.data.email;
this.userInfo.username = res.data.data.username;
this.userInfo.phone = res.data.data.phone;
})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
},
updateUser() {
axios
.put(`${API_URL}/users/update/${this.userInfo.id}`, {
name: this.userInfo.name,
username: this.userInfo.username,
email: this.userInfo.email,
password: null,
roles: this.userInfo.roles,
})
.then((res) => {
this.refreshUsers();
})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
},
removeUser() {
axios
.delete(`${API_URL}/users/delete/${this.userInfo.id}`)
.then((res) => {
this.refreshUsers();
})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
},
},
mounted() {
this.refreshUsers();
},
};
</script>
I had the same problem and the solution was to send each button to a different function

The requested module does not provide an export named vuejs 3

I have tried to use export default and export default legend but it still got error
The requested module '/src/legends.js?t=1637071' does not provide an export named 'legend'
in console log, how can I fix this problem?
Thank you!!
legends.js
import axios from "axios";
const API_URL = "http://localhost:8000/api";
function add(url, type) {
axios
.post(`${API_URL}/${url}`, this.newRole)
.then((res) => {})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
}
function remove(url, type) {
axios
.post(`${API_URL}/${url}`, this.newRole)
.then((res) => {})
.catch((error) => {
console.log("ERRRR:: ", error.response.data);
});
}
export default legend
manageRoles.vue
<template>
<div class="col-md-12">
<div class="card">
<div class="card-header d-flex flex-row">
<h4 class="card-title align-self-center">Roles Manager</h4>
<button
class="btn btn-success btn-fab btn-icon btn-round mb-3 ml-2"
data-toggle="modal"
data-target="#addRoleModal">
<i class="icon-simple-add"></i>
</button>
</div>
<div class="card-body">
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Role Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr v-for="role in roles" :key="role.id">
<td>
{{ role.id }}
</td>
<td>
{{ role.name }}
</td>
<Buttons />
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- MODALS -->
<!-- ADD NEW ROLE MODAL -->
<div
class="modal modal-black fade" id="addRoleModal"
tabindex="-1" role="dialog" aria-labelledby="addRoleModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Add new role</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<i class="icon-simple-remove"></i>
</button>
</div>
<form class="form-horizontal">
<div class="modal-body">
<div class="d-flex flex-row">
<label class="col-md-4 col-form-label">Role name</label>
<div class="col-md-6">
<div class="form-group">
<input type="name" name="name" class="form-control"
v-model="newRole.name" />
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Cancel
</button>
<button type="submit" class="btn btn-primary" #click.stop.prevent="addRole()">
Add new role
</button>
</div>
</form>
</div>
</div>
</div>
<!-- END ADD NEW ROLE MODAL -->
<!-- REMOVE ROLE MODAL -->
<div class="modal modal-black fade" id="roleRemoveModal"
tabindex="-1" role="dialog" aria-labelledby="roleRemoveModal" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" id="roleRemoveModal">
Confirm delete role
<strong class="text-primary">
{{ roleInfo.name }}
</strong>
</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
<i class="icon-simple-remove"></i>
</button>
</div>
<div class="modal-body h4 text-white text-center mt-4">
Really want to delete role
<strong class="text-danger">
{{ roleInfo.name }}
</strong>?
</div>
<div class="modal-footer d-flex flex-row">
<button type="button" class="btn btn-secondary" data-dismiss="modal">
Cancel
</button>
<button type="button" class="btn btn-danger" data-dismiss="modal" #click="removeRole()">
Delete role
</button>
</div>
</div>
</div>
</div>
<!-- END REMOVE ROLE MODAL -->
<!-- END MODALS -->
</template>
<script>
import Buttons from "../components/cores/Buttons.vue";
import { legend } from "/src/legends.js";
export default {
name: "manageRoles",
components: { Buttons },
data() {
return {
roles: [],
newRole: {
name: null,
},
roleInfo: {
id: 0,
name: "",
},
};
},
methods: {
addRole() {
legend.add(`roles/createRole`);
this.$router.push("/manager/roles");
},
removeRole() {
legend.remove(`roles/createRole`);
this.$router.push("/manager/roles");
},
},
mounted() {
this.refreshRoles();
},
};
</script>
export default is default export, as the name implies. Regardless of how the variable that holds a value of default export is called, it's supposed to be imported as default import, not named import with brackets:
const legend = ...;
export default legend;
and
import legendCanBeImportedUnderAnyName from "/src/legends.js"
Alternatively, it can be made named export, it also needs to be imported as such:
export const legend = ...;
and
import { legend } from "/src/legends.js"
Try this.import * as legend from "/src/legends.js";

Nuxt component variable not updated

I wrote the following code for my navbar:
<template>
<div>
<div v-if="!$auth.loggedIn" data-tip="Login" class="tooltip tooltip-bottom">
<nuxt-link to="/login" class="btn btn-square btn-ghost">
<solid-login-icon class="w-6 h-6" />
</nuxt-link>
</div>
<div v-else class="flex items-stretch">
<a class="pr-2 btn btn-ghost rounded-btn"> Welcome, {{ this.$auth.user.username }}! 👋 </a>
<div data-tip="Logout" class="tooltip tooltip-bottom">
<button class="pr-2 btn btn-square btn-ghost" #click="logout()">
<solid-login-icon class="w-6 h-6" />
</button>
</div>
</div>
</div>
</template>
Which is include in the following login page:
<template>
<div class="h-screen shadow bg-base-200 drawer drawer-mobile">
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
<div class="drawer-content">
<NavBar />
<div class="grid grid-cols-1 p-5 md:grid-cols-6">
<div class="col-span-1 md:col-span-2 md:col-start-3">
<div class="bg-white shadow card">
<div class="card-body">
<h2 class="text-left card-title">Login</h2>
<form #submit.prevent="userLogin">
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.username"
type="text"
placeholder="Username"
class="input input-bordered"
/>
</div>
<div class="form-control">
<label class="label">
<span class="label-text">Username</span>
</label>
<input
v-model="login.password"
type="password"
placeholder="Password"
class="input input-bordered"
/>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary btn-md">Login</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<SideBar />
</div>
</template>
<script>
export default {
data() {
return {
login: {
username: '',
password: '',
},
}
},
methods: {
async userLogin() {
try {
const response = await this.$auth.loginWith('local', { data: this.login })
} catch (err) {}
},
},
}
</script>
Upon loggin in with correct credentials the page keeps dispalying the "Login"-icon instead of the Welcome message.
I've tried to replace !$auth.loggedIn with loggedIn (coming from the data function) and with !this.$auth.loggedIn" but both don't seem to solve the issue

VueJS + Two instances of vForm in one component

I'm using laravel + VueJS for front-end. I have a groups component to handle groups creation and groups permissions. I need to use two vForms: One to create groups, and the other to create / assign permissions for the group.
The problem is when I send the permissions form, laravel receives data of the first form, this i suppose is because I create that instance first. I think I should create two instances of vForm, but I do not know how. Is this possible?
My component code:
<template>
<div class="container">
<div class="row mt-5">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Grupos</h3>
<div class="card-tools">
<button class="btn btn-success" #click="newGroupModal" v-if="$can('groupscreate')"> <i class="fas fa-user-plus fa-fw"></i> Nuevo Grupo </button>
</div>
</div>
<!-- /.card-header -->
<div class="card-body table-responsive p-0">
<table class="table table-hover">
<tbody>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Fecha Alta</th>
<th>Fecha Act</th>
<th>Acc.</th>
</tr>
<tr v-for="group in groups" :key="groups.id">
<td>{{ group.id }}</td>
<td>{{ group.name }}</td>
<td>{{ group.created_at | formattedDate }}</td>
<td>{{ group.updated_at | formattedDate }}</td>
<td><i class="fas fa-edit"></i></td>
<td><i class="fas fa-key"></i></td>
</tr>
</tbody>
</table>
</div>
<!-- /.card-body -->
</div>
<!-- /.card -->
</div>
</div>
<!-- Modal -->
<div class="modal fade" id="groupModal" tabindex="-1" role="dialog" aria-labelledby="groupModal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="groupModal">Nuevo Grupo</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form #submit.prevent="editMode ? updateGroup() : createGroup()">
<div class="modal-body">
<div class="form-group">
<input v-model="form.name" type="text" name="name" placeholder="Name"
class="form-control" :class="{ 'is-invalid': form.errors.has('name') }">
<has-error :form="form" field="name"></has-error>
</div>
</div>
<div class="modal-footer">
<button v-show="editMode" type="button" class="btn btn-danger" #click="deleteGroup" v-if="$can('groupsdelete')">Eliminar</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cerrar</button>
<button type="submit" class="btn btn-primary" v-if="$can('groupsedit')">Guardar</button>
</div>
</form>
</div>
</div>
</div>
<!-- Modal Permissions-->
<div class="modal fade" id="groupPermissionsModal" tabindex="-1" role="dialog" aria-labelledby="groupPermissionsModal" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="userModal">Permisos por Grupo</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<form #submit.prevent="updateGroupPermissions()">
<div class="modal-body">
<div class="form-group">
<label class="control-label">Usuarios</label><br>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="usersview" value="usersview" v-model="groupPermissions">
<label class="form-check-label" for="usersview">Ver</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="userscreate" value="userscreate" v-model="groupPermissions">
<label class="form-check-label" for="userscreate">Crear</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="usersedit" value="usersedit" v-model="groupPermissions">
<label class="form-check-label" for="usersedit">Editar</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="usersdelete" value="usersdelete" v-model="groupPermissions">
<label class="form-check-label" for="usersdelete">Eliminar</label>
</div>
</div>
<div class="form-group">
<label class="control-label">Grupos</label><br>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="groupsview" value="groupsview" v-model="groupPermissions">
<label class="form-check-label" for="groupsview">Ver</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="groupscreate" value="groupscreate" v-model="groupPermissions">
<label class="form-check-label" for="groupscreate">Crear</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="groupsedit" value="groupsedit" v-model="groupPermissions">
<label class="form-check-label" for="groupsedit">Editar</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="groupsdelete" value="groupsdelete" v-model="groupPermissions">
<label class="form-check-label" for="groupsdelete">Eliminar</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cerrar</button>
<button type="submit" class="btn btn-primary" v-if="$can('permissionsedit')">Guardar</button>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
editMode: false,
groups: {},
groupPermissions: {},
form: new Form({
id: '',
name : '',
}),
formPermissions: new Form({
users: [],
groups: []
}),
}
},
methods: {
newGroupModal(){
this.editMode = false;
this.form.reset();
$('#groupModal').modal('show');
},
newGroupPermissionsModal(groupId){
this.loadGroupPermissions(groupId);
this.form.reset();
$('#groupPermissionsModal').modal('show');
this.form.fill(this.groupPermissions);
},
newEditGroupModal(group){
this.editMode = true;
this.form.reset();
$('#groupModal').modal('show');
this.form.fill(group);
},
loadGroups(){
this.$Progress.start();
axios.get('api/group').then(({data}) => (this.groups = data.data));
this.$Progress.finish();
},
loadGroupPermissions(groupId){
this.$Progress.start();
axios.get('api/permissions/group/' + groupId).then(({data}) => (this.groupPermissions = data));
this.$Progress.finish();
},
createGroup(){
this.$Progress.start();
this.form.post('api/group')
.then(() => {
Fire.$emit('GroupInform');
$('#groupModal').modal('hide');
Toast.fire({
type: 'success',
title: 'Usuario creado satisfactoriamente.'
})
this.form.reset();
this.$Progress.finish();
})
.catch(() => {
this.$Progress.fail();
})
},
updateGroup(groupId){
this.$Progress.start();
this.form.put('api/group/' + this.form.id)
.then(() => {
Fire.$emit('GroupInform');
$('#groupModal').modal('hide');
Toast.fire({
type: 'success',
title: 'Usuario actualizado satisfactoriamente.'
})
this.form.reset();
this.$Progress.finish();
})
.catch(() => {
this.$Progress.fail();
})
},
deleteGroup(){
Swal.fire({
title: 'Estas seguro?',
text: "No podrás restaurar los datos eliminados.",
type: 'warning',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#14b750',
confirmButtonText: 'Si'
}).then((result) => {
if (result.value) {
this.form.delete('api/group/'+this.form.id).then(()=>{
Toast.fire({
type: 'success',
title: 'Usuario eliminado satisfactoriamente.'
})
Fire.$emit('GroupInform');
$('#groupModal').modal('hide');
}).catch(()=> {
Swal.fire("Error!", "Algo anda mal.", "warning");
this.$Progress.fail();
});
}
})
},
updateGroupPermissions(){
this.$Progress.start();
this.form.post('api/permissions/group/1')
.then(() => {
Fire.$emit('GroupInform');
$('#groupModal').modal('hide');
Toast.fire({
type: 'success',
title: 'Usuario actualizado satisfactoriamente.'
})
this.form.reset();
this.$Progress.finish();
})
.catch(() => {
this.$Progress.fail();
})
}
},
mounted() {
this.loadGroups();
Fire.$on('GroupInform', () => {
this.loadGroups();
});
}
}
</script>
Simply add a new variable with a different name than 'form' as a new instance from v-form
form2: new Form({
id: '',
name : '',
})
then access it like that:
<div class="form-group">
<input v-model="form2.name" type="text" name="name" placeholder="Name" class="form-control" :class="{ 'is-invalid': form.errors.has('name') }">
<has-error :form="form2" field="name"></has-error>
</div>