Dynamically display fetched data in input field using Laravel 8 Vue Js - javascript

I have a simple registration form in Laravel 8 using Vue js where I need to check first if the user who refers the person registering exists in my database prior to submitting. if a record exists, I need to dynamically display the user's full name in the input field on the #change event.
Here's my Vue component:
<template>
<div>
<h2>TESTING</h2>
<form #submit.prevent="submit" >
<input type="text" class="form-control" v-model="form.ucode" #change="getUser()">
<input type="text" class="form-control" v-model="form.uname">
</form>
</div>
</template>
<script>
export default {
data: function(){
return{
form: {
ucode: "",
uname: "",
},
}
},
methods:{
getUser(){
axios.get('api/checkUser?ucode=' + this.form.ucode).then(res=>{
this.form.uname = res.data.first_name
})
}
}
}
Here's my ResellerController and API route:
Route::get('/checkUser', [ResellerController::class, 'show']);
public function show()
{
$ucode = request('ucode');
$user = DB::table('resellers')->where('username', $ucode)->select('id', 'first_name')->get();
return response()->json($user);
}
I think I don't have issues with my controller because it returns back the correct JSON data
[{"id":1,"first_name":"William Hardiev"}]
But when I test my code, uname is undefined.
form:Object
ucode:"williambola_05"
uname:undefined
Can anyone help me with this?

You issue is the JSON response that you receive from the server. You are getting a JSON Array from the server, whereas your JS code is handling a JSON object
You can handle it like this:
<template>
<div>
<h2>TESTING</h2>
<form #submit.prevent="submit">
<input
type="text"
class="form-control"
v-model="form.ucode"
#change="getUser()"
/>
<input type="text" class="form-control" v-model="form.uname" />
</form>
</div>
</template>
<script>
import axios from "axios";
export default {
data: function() {
return {
form: {
ucode: "",
uname: ""
}
};
},
methods: {
getUser() {
axios.get("api/checkUser/?ucode=" + this.form.ucode).then(res => {
this.form.uname = res.data[0].first_name;
});
}
}
};
</script>
OR you can just change the get query on the server side to simply return a single JSON object rather than an array and your js code should automatically start working:
$user = DB::table('resellers')
->where('username', $ucode)
->select('id', 'first_name')
->first();

Related

InertiaJS keep form data after validation error

In my InertiaJS/VueJS project I have a prop that receive some data from the backend:
event: {
type: Object,
default: () => { return {} }
},
That's how the event obj looks in the backend:
['name' => 'Event Name']
I use toRefs to convert the reactive prop and update its properties in the UI:
const eventRef = toRefs(props).event
So the Event has the name 'Event Name' when the component loads, when I update the event name in the UI to 'New Name' and submit the form, I send the eventRef obj in the request to create the new event:
Inertia.post(url, eventRef, only: ['global'])
If there's a validation error in the backend, I return it to the frontend and show the error in the UI (This is working without problems). The problem I have is that Inertia (or maybe VueJS) is returning the object eventRef to his previous state when the component is created. Which means that the name property of the eventRef changes to 'Event Name' again, instead of staying with 'New Name` that was updated in the UI. I would like to preserve the state of the object after I submit the form. This is my Inertia response:
component: "Events/EventNew"
props: {
global: {} // Global object
}
url: "/app/qa/events/new"
version: null
As you can see I'm not even getting the 'event' prop from the backend, so it shouldn't be updated. After reading Inertia docs I thought that a simple preserveState:true in the request options would do the job but this is not happening. Every time the server returns an Inertia response, the eventRef obj is 'reset'.
What am I missing here? I would appreciate some help
I believe I had the same problem using Inertia with Vue2. If I understood correctly, you probably seeing this on a form where you trying to update and entry, right? Your validation is working but the form keeps resetting itself to the previous state. If that's the case, what solved this for me was this:
Instead of using Inertia.post() directly, use the Inertia Form Helper instead
Vue 2
<template>
<form #submit.prevent="form.post('/login')">
<!-- email -->
<input type="text" v-model="form.email">
<div v-if="form.errors.email">{{ form.errors.email }}</div>
<!-- password -->
<input type="password" v-model="form.password">
<div v-if="form.errors.password">{{ form.errors.password }}</div>
<!-- remember me -->
<input type="checkbox" v-model="form.remember"> Remember Me
<!-- submit -->
<button type="submit" :disabled="form.processing">Login</button>
</form>
</template>
<script>
export default {
data() {
return {
form: this.$inertia.form({
email: null,
password: null,
remember: false,
}),
}
},
}
</script>
Vue 3
<template>
<form #submit.prevent="form.post('/login')">
<!-- email -->
<input type="text" v-model="form.email">
<div v-if="form.errors.email">{{ form.errors.email }}</div>
<!-- password -->
<input type="password" v-model="form.password">
<div v-if="form.errors.password">{{ form.errors.password }}</div>
<!-- remember me -->
<input type="checkbox" v-model="form.remember"> Remember Me
<!-- submit -->
<button type="submit" :disabled="form.processing">Login</button>
</form>
</template>
<script>
import { useForm } from '#inertiajs/inertia-vue3'
export default {
setup () {
const form = useForm({
email: null,
password: null,
remember: false,
})
return { form }
},
}
</script>
I solved the problem, it was the toRefs that was modifying the props in the component after the request was sent. Using a reactive object was the solution:
const eventRef = reactive(props.event)

vue.js post list not updating after form submission

In my vue app I have two components one which is a form that posts the form data to my api. And the other gets and displays these posts in a section on the page. My issue is that when I submit a new post the posts lists aren't updated. The data stays the same unless I refresh the page. How can I get my posts list to update when I submit the form?
My Code:
client/src/App.vue
<template>
<div id="app">
<MainHeader :modalVisability="modal" v-on:showModal="toggleModal" />
<div id="content_wrap">
<Summary />
</div>
<OppForm :modalVisability="modal" />
</div>
</template>
<script>
import MainHeader from './components/MainHeader.vue';
import OppForm from './components/oppForm.vue';
import Summary from './components/Summary.vue';
export default {
name: 'App',
components: {
MainHeader,
Summary,
OppForm
},
data () {
return {
modal: false
}
},
methods: {
toggleModal (modalBool) {
this.modal = modalBool;
}
}
}
</script>
client/src/components/oppForm.vue
<template>
<div id="opp_form_modal" >
<form #submit.prevent="SubmitOpp" v-if="modalVisability">
<input type="text" name="company_name" v-model="company_name">
<button type="submit">Submit</button>
</form>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'oppForm',
props: {
modalVisability: Boolean,
},
data () {
return {
company_name: ''
}
},
methods: {
SubmitOpp () {
axios.post('http://localhost:5000/', {
company_name: this.company_name,
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
}
}
</script>
client/src/components/Summary.vue
<template>
<div id="summary_section">
<h2>Summary</h2>
<div id="summary_board">
<div class="column">
<div class="head">
<h3>Opportunities</h3>
</div>
<div class="body">
<div class="post"
v-for="(post, index) in posts"
:key="index"
>
<p class="company">{{ post.company_name }}</p>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return{
posts: []
};
},
created() {
axios.get('http://localhost:5000/')
.then(res => {
// console.log(res);
const data = res.data;
this.posts = data;
})
.catch(error => console.log(error));
}
}
</script>
The problem is that you're actually fetching your posts only on the app creation (i.e. inside the created() method).
You should wrap your axios call inside a function updatePosts() and then call it whenever you add a new post successfully, or you could create a custom event that is triggered whenever a new post is added.
created() is called only once (see vue lifecycle) so you fetch API before submitting form.
Try to add some console.log to understand what is called when.
You could use an global event bus and send form value as event data to summary. I could imagine also a solution where event is used to "tell" summary that form was submitted (just boolean, not data itself). In summary you then call API each time you receive event.
Or simple add an "update" button to summary to manually call API.
See Communication between sibling components in VueJs 2.0
or global vue instance for events for detailed examples.

Ember Octane Upgrade How to pass values from component to controller

Upgrade from Ember <3.15 to >=3.15. How do I pass form values from a controller into a component?
I cannot begin to explain the number of diagnostic combinations attempted and their corresponding errors received. So, I figure it best to ask how it should be done correctly? Is Glimmer involved?
A simple example: pass a change password from old password to both a new and confirm password via a component to a controller. In the Component, I keep getting onsubmit() is not a function error.
Code example:
User Input Form
ChangePasswordForm.hbs
<div class="middle-box text-center loginscreen animated fadeInDown">
<div>
<h3>Change Password</h3>
<form class="m-t" role="form" {{on "submit" this.changePassword}}>
{{#each errors as |error|}}
<div class="error-alert">{{error.detail}}</div>
{{/each}}
<div class="form-group">
{{input type="password" class="form-control" placeholder="Old Password" value=oldPassword required="true"}}
</div>
<div class="form-group">
{{input type="password" class="form-control" placeholder="New Password" value=newPassword required="true"}}
</div>
<div class="form-group">
{{input type="password" class="form-control" placeholder="Confirm Password" value=confirmPassword required="true"}}
</div>
<div>
<button type="submit" class="btn btn-primary block full-width m-b">Submit</button>
</div>
</form>
</div>
</div>
Template Component
ChangePassword.hbs
<Clients::ChangePasswordForm #chgpwd={{this.model}} {{on "submit" this.changePassword}} #errors={{this.errors}} />
Component
ChangePasswordForm.js
import Component from '#glimmer/component';
import { tracked } from '#glimmer/tracking';
import { action } from '#ember/object';
export default class ChangePasswordForm extends Component {
#tracked oldPassword;
#tracked newPassword;
#tracked confirmPassword;
#tracked errors = [];
#action
changePassword(ev) {
// Prevent the form's default action.
ev.preventDefault();
this.oldPassword = ev.oldPassword;
this.newPassword = ev.newPassword;
this.confirmPassword = ev.confirmPassword;
// Call the form's onsubmit method and pass in the component's values.
this.onsubmit({
oldPassword: this.oldPassword,
newPassword: this.newPassword,
confirmPassword: this.confirmPassword
});
}
}
Controller
ChangePassword.js
import Controller from '#ember/controller';
import { inject as service } from '#ember/service';
import { action } from '#ember/object';
export default class ChangePassword extends Controller {
#service ajax
#service session
#action
changePassword(attrs) {
if(attrs.newPassword == attrs.oldPassword)
{
this.set('errors', [{
detail: "The old password and new password are the same. The password was not changed.",
status: 1003,
title: 'Change Password Failed'
}]);
}
else if(attrs.newPassword != attrs.confirmPassword)
{
this.set('errors', [{
detail: "The new password and confirm password must be the same value. The password was not changed.",
status: 1003,
title: 'Change Password Failed'
}]);
}
else
{
let token = this.get('session.data.authenticated.token');
this.ajax.request(this.store.adapterFor('application').get('host') + "/clients/change-password", {
method: 'POST',
data: JSON.stringify({
data: {
attributes: {
"old-password" : attrs.oldPassword,
"new-password" : attrs.newPassword,
"confirm-password" : attrs.confirmPassword
},
type: 'change-passwords'
}
}),
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/vnd.api+json',
'Accept': 'application/vnd.api+json'
}
})
.then(() => {
// Transistion to the change-password-success route.
this.transitionToRoute('clients.change-password-success');
})
.catch((ex) => {
// Set the errors property to the errors held in the ex.payload.errors. This will allow the errors to be shown in the UI.
this.set('errors', ex.payload.errors);
});
}
}
}
Model
ChangePassword.js
import Route from '#ember/routing/route';
import AbcAuthenticatedRouteMixin from '../../mixins/abc-authenticated-route-mixin';
export default Route.extend(AbcAuthenticatedRouteMixin, {
//export default class ChangePasswordRoute extends Route(AbcAuthenticatedRouteMixin, {
model() {
return {
oldPassword: '',
newPassword: '',
confirmPassword: ''
};
},
})
There is no onsubmit method in #glimmer/component, so you cannot call this.onsubmit inside an action in the component.
First, you need to pass the action created in your controller to your component. This can be done like this:
<ChangePasswordForm #chgpwd={{this.model}} #changePassword={{action 'changePassword'}} />
Remember, you cannot pass data up any more in a glimmer component, you need to use an action since everything is one way binding.
Second, you need to call this action inside your glimmer component:
this.args.changePassword({
oldPassword: this.oldPassword,
newPassword: this.newPassword,
confirmPassword: this.confirmPassword
});
I've created an Ember Twiddle for you to show this example working.

Can't Submit Axios Post form Nuxt.js (VueJS)

I'm playing around with my first ever form in Vue. I've created my app with Nuxt.
I'm able to get data via an axios get request from my API but I can't seem to post data.
new.vue
<template>
<section class="container">
<div>
<h1>Gins</h1>
<form #submit.prevent="addGin">
<h4>New Product</h4>
<p>
<label for="name" class="input-label">Title:</label>
<input id="name" v-model="title" type="text" name="name" class="input">
</p>
<p>
<button type="submit" value="Submit" class="button">Add Gin</button>
</p>
</form>
</div>
</section>
</template>
<script>
import axios from 'axios'
export default {
data() {
return {
title: '',
errors: []
}
},
methods: {
addGin() {
axios.post('/apv/v1/gins', this.title)
.then((Response) => {})
.catch((err) => {
this.errors.push(err)
})
}
}
}
</script>
When clicking the submit button, I'm not receiving any errors, but I can confirm no entry is added to my API database.
My API is running on a different server localhost:4000 and I have set up the proxy in nuxt.config.js
axios: {
proxy: true
},
proxy: {
'/api/v1/': 'http://localhost:4000'
},
I've experimented with both <form #submit.prevent="addGin"> and <form v-on:submit.prevent="addGin"> but this doesn't seem to make a difference.
What else might I be missing?
Add #nuxtjs/axios module into modules part of nuxt.config
Use this.$axios instead of imported one. Proof: https://axios.nuxtjs.org/usage
OK so was really close. Changing my axios params to title: this.title, apparently did the trick.

Vue JS form issue - mutating vuex store state outside handlers

I am currently getting the [vuex] Do not mutate vuex store state outside mutation handlers error only when I try to edit the form, if I am posting a new plugin it works fine. From this doc I'm not sure where I'm going wrong - while I fetch the plugin from vuex, I try to give the local state those values and then leave vuex alone. Ideally once fetched vuex, I wouldn't need to touch it again until the form is submitted. But I'm not sure what is causing the error exactly
<template>
<div>
<h4>{{this.$route.query.mode==="new"?"New":"Edit"}} Plugin</h4>
<form class="">
<label>Id</label>
<input :value="plugin.id" class="" type="text" #input="updateId">
<label>Name</label>
<input :value="plugin.name" class="" type="text" #input="updateName">
<label>Description</label>
<textarea :value="plugin.description" class="" type="text" #input="updateDescription"></textarea>
<label>Version</label>
<input :value="plugin.version" class="" type="text" #input="updateVersion">
<button type="submit" #click.prevent="submitForm">Submit</button>
</form>
</div>
</template>
<script>
import util from '~/assets/js/util'
export default {
created() {
if (this.mode === 'edit') {
this.plugin = this.$store.state.currentLicence.associatedPlugins.find(p => p.pluginId === this.$route.query.pluginId)
}
},
methods: {
updateId(v) {
this.plugin.id = v.target.value
},
updateName(v) {
this.plugin.name = v.target.value
},
updateDescription(v) {
this.plugin.description = v.target.value
},
updateVersion(v) {
this.plugin.version = v.target.value
}
},
computed: {
mode() { return this.$route.query.mode }
},
data: () => ({
plugin: {
id: null,
name: null,
description: null,
version: null
}
})
}
</script>
Thanks for any help, clearly my understanding of the way that vuex and local state are handled is flawed
You are getting this error because you are editing the state directly.
this.plugin = this.$store.state.currentLicence.associatedPlugins.find(p => p.pluginId === this.$route.query.pluginId) - this is exactly this part of code where you put the object from the store directly into the data, therefore by editing the field you are directly editing the state. Don't do that!
You should always use stuff like (I am not sure how nested computed will work but I don't think you have to nest it):
computed: {
plugin: {
id: {
get () { // get it from store }
set (value) { // dispatch the mutation with the new data }
}
}
}
There is a nice package whill will do most work for you: https://github.com/maoberlehner/vuex-map-fields . You can use it to semi-automatic generate computed with getters and setters for each field.

Categories