Submitting form in Vue.js with ajax - javascript

I'm really stuck on how I would work with submitting a form that makes an ajax request using Vue.js and vue-resource then using the response to fill a div.
I do this from project to project with js/jQuery like this:
view in blade
{!! Form::open(['route' => 'formRoute', 'id' => 'searchForm', 'class' => 'form-inline']) !!}
<div class="form-group">
<input type="text" name="id" class="form-control" placeholder="id" required="required">
</div>
<button type="submit" class="btn btn-default">Search</button>
{!! Form::close() !!}
js/jquery
var $searchForm = $('#searchForm');
var $searchResult = $('#searchResult');
$searchForm.submit(function(e) {
e.preventDefault() ;
$.get(
$searchForm.attr('action'),
$searchForm.serialize(),
function(data) {
$searchResult.html(data['status']);
}
);
});
What I've done/tried so far in Vue.js:
view in blade
{!! Form::open(['route' => 'formRoute', 'id' => 'searchForm', 'class' => 'form-inline']) !!}
<div class="form-group">
<input type="text" name="id" class="form-control" placeholder="id" required="required">
</div>
<button type="submit" class="btn btn-default" v-on="click: search">Search</button>
{!! Form::close() !!}
vue/js
Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('value');
new Vue({
el: '#someId',
data: {
},
methods: {
search: function(e) {
e.preventDefault();
var req = this.$http.get(
// ???, // url
// ???, // data
function (data, status, request) {
console.log(data);
}
);
}
}
});
I'm wondering if it's possible to use components when dealing with the response to output the response data to a div?
Just to summarise everything:
How do I submit a form using vue js and vue-resource instead of my usual jQuery way?
Using a response from ajax, how can I output data into a div preferably using components?

I used this approach and worked like a charm:
event.preventDefault();
let formData = new FormData(event.target);
formData.forEach((key, value) => console.log(value, key));

In order to get the value from input you have to use v-model Directive
1. Blade View
<div id="app">
<form v-on="submit: search">
<div class="form-group">
<input type="text" v-model="id" class="form-control" placeholder="id" required="required">
</div>
<input type="submit" class="btn btn-default" value="Search">
</form>
</div>
<script type="text/javascript">
// get route url with blade
var url = "{{route('formRoute')}}";
Vue.http.headers.common['X-CSRF-TOKEN'] = document.querySelector('#token').getAttribute('value');
var app = new Vue({
el: '#app',
data: {
id: '',
response: null
},
methods: {
search: function(event) {
event.preventDefault();
var payload = {id: this.id};
// send get request
this.$http.get(url, payload, function (data, status, request) {
// set data on vm
this.response = data;
}).error(function (data, status, request) {
// handle error
});
}
}
});
</script>
If you want to pass data to component the use 'props' see docs for more info
http://vuejs.org/guide/components.html#Passing_Data_with_Props
If you want use laravel and vuejs together, then checkout
https://laracasts.com/series/learning-vuejs

Add v-model="id" on your text input
then add it to your data object
new Vue({
el: '#someId',
data: {
id: ''
},
methods: {
search: function(e) {
e.preventDefault();
var req = this.$http.get(
'/api/search?id=' + this.id,
function (data, status, request) {
console.log(data);
}
);
}
}
});
It’s better to remove v-on="click: search" and add v-on="submit: search" on the form tag.
You should add method="GET" on your form.
Make sure you have #someId in your html markup.

Related

How do I access the changed value of the form?

I am doing an exercise of an online course. In this exercise I have a form with 3 inputs and I have to extract them to make a request to a server. My problem is that my JavaScript Code only returns the empty string if I log it in the console, not the changed value. I guess it's accessing the inital value of the html. How can I solve this?
JavaScript Code:
// Initial call if the form is submitted
document.querySelector("#compose-submit").onsubmit = send_mail();
// The send_mail function:
function send_mail() {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
});
return false;
Corresponding html:
<h3>New Email</h3>
<form id="compose-form">
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="submit" class="btn btn-primary" id="compose-submit"/>
</form>
In the first line when you are assigning a callback to the onsubmit event, you need to just pass the function name and not call it.
So, changing your first line of code to
document.querySelector("#compose-submit").onclick = send_mail;
or
bind your event to the form element to make it work with onsumbit event
document.querySelector("#compose-form").onsubmit = send_mail;
should work.
Here's a JSFiddle as a sample (check console)
Change your input type to button to prevent reloading the page after submitting. And you will keep your values
// Initial call if the form is submitted
document.querySelector("#compose-submit").addEventListener('click', () => {
send_mail();
});
// The send_mail function:
function send_mail() {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
console.log(recipients);
console.log(subject);
console.log(body);
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
});
return false;
}
<h3>New Email</h3>
<form id="compose-form">
<div class="form-group">
From: <input disabled class="form-control" value="{{ request.user.email }}">
</div>
<div class="form-group">
To: <input id="compose-recipients" class="form-control">
</div>
<div class="form-group">
<input class="form-control" id="compose-subject" placeholder="Subject">
</div>
<textarea class="form-control" id="compose-body" placeholder="Body"></textarea>
<input type="button" value="Submit" class="btn btn-primary" id="compose-submit" />
</form>
It's because of the submit type, when you submit the form, it submits the values of the form to the given url path of your action attribute of the form <form action="path_to_fetch" method="POST"> and then refreshed the page after. So your javascript code can't catch the values of the form.
One solution is to prevent the form to be refreshed and let your javascript code do the fetching method.
so in your js code, do this:
// Initial call if the form is submitted
document.querySelector("#compose-submit").addEventListener("click", send_mail);
// The send_mail function:
function send_mail(e) {
let recipients = document.querySelector('#compose-recipients').value; // Those return the empty string,
let subject = document.querySelector("#compose-subject").value; // although something was written
let body = document.querySelector("#compose-body").value; // inside
fetch("/emails", {
method: "POST",
body: JSON.stringify({
recipients: recipients,
subject: subject,
body: body
})
})
.then(response => response.json())
.then(result => {
console.log(result);
}).finally(() => {
document.querySelector('#compose-recipients').value = "";
document.querySelector("#compose-subject").value = "";
document.querySelector("#compose-body").value = "";
})
}
Use the finally function to empty the form after submitting the form.
EDIT:
And also change your button type to just button, using the submit type will cause the refresh.
<button class="btn btn-primary" id="compose-submit" type="button">Submit</button>

How to retrieve data from form using a POST route?

I am trying to retrieve data from a Bootstrap form element, and save it to a PostgresSQL database using Express and Knex. There are no errors when I run the route; however, the data from the form is saved as null. Here is my form element (I'm using React):
render() {
return (
<form>
<div className ="form-group">
<label>Add a Note:</label>
<textarea className="form-control" name="note" rows="5">
</textarea>
</div>
<button onClick={this.handleClick} className="btn btn-primary"
type="submit">Submit</button>
</form>
)
}
Here is my fetch to the POST route:
handleClick(e) {
e.preventDefault()
fetch('/create-note', {
method: 'POST'
})
}
Here is my Express POST route (app.use(bodyParser.json()) is included in this file):
app.post('/create-note', (req, res) => {
postNote(req.body.note)
.then(() => {
res.sendStatus(201)
})
})
Here is the Knex postNote function:
export function postNote(newNote) {
const query = knex
.insert({ note_content: newNote })
.into('notes')
return query
}
Any help would be appreciated!
With POST requests you may have to wait for data body to be ready. Try this
app.post('/create-note', (req, res) => {
var body = '';
request.on('data',function(data) { body += data; });
request.on('end', function(data) {
postNote(body)
.then(() => {
res.sendStatus(201)
})
});
})
try the following in your markup, and forgo using fetch
...
<form method="POST" action="/create-note" enctype='application/json'>
...
</form>
...
or since the default encoding for a form is application/x-www-form-encoded (doc), add the following middleware to your express app..
...
app.use(bodyParser.urlencoded({ extended: true }));
...
also you could try...
...
<button ref="form" onClick={this.handleClick} className="btn btn-primary"
type="submit">Submit</button>
...
along with
handleClick(e) {
e.preventDefault();
const data = new FormData(this.refs.form);
fetch('/create-note', {
method: 'POST',
body: data
})
}
I found a solution and want to post it incase anyone else runs into a similar issue. The problem was I wasn't querying textarea's value correctly, so I was passing an undefined variable to the database to save.
Here's the solution I came up with:
handleSubmit(e) {
const data = new FormData(e.target)
const text = {note: data.get('note')}
fetch('/create-note', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(text)
})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className ="form-group">
<label>Add a Note:</label>
<textarea className="form-control" name="note" rows="5">
</textarea>
<button ref="textarea" className="btn btn-primary"
type="submit">Submit</button>
</div>
</form>
)
}
I put a onSubmit event listener on the form, and created a new FormData instance with the form. Then I created an object containing the value of the textarea to pass into the fetch call.

Saving multiple data dynamic form in Laravel 5.1 and Vue JS

I have to add/post data form. But the form dynamically can increase as user 'click' on a button. I've already browse about it and there some answer i get like using $request->all() to fetch all data from input forms.
And then my problem is, my app using VueJS as front-end. Is there any some configuration on VueJS script to post all data from that dynamic form??
My Blade template that will be increase dynamically:
<div id="form-message">
{!! Form::text('rows[0][DestinationNumber]', null, [
'id' => 'recipient',
'class' => 'form-control',
'v-model' => 'newMessage.DestinationNumber'
])
!!}
{!! Form::textarea('rows[0][TextDecoded]', null, [
'rows' => '3',
'id' => 'recipient',
'class' => 'form-control',
'v-model' => 'newMessage.TextDecoded'
])
!!}
</div>
That zero number will increase depends on how much user click add button.
And then here my VueJS script
var newSingleMessage = new Vue({
el: '#newsinglemsg',
data: {
newMessage: {
DestinationNumber: '',
TextDecoded: ''
},
},
methods: {
onSubmitForm: function(e) {
e.preventDefault();
var message = this.newMessage;
this.$http.post('api/outbox', message);
message = { DestinationNumber: '', TextDecoded: '' };
this.submitted = true;
}
}
});
On laravel controller, i have simple logic to test result how data passed.
$input = $request->all();
$output = dd($input);
return $output;
And, I test it using 2 additional form. So, the data should be 3 rows. The result (checked from FireBug) to be like this
{"DestinationNumber":"1234567890","TextDecoded":"qwertyuio"}
Data passed just one, and then the type is JSON. Even I use return $output->toArray(), type still JSON.
Oh yeah, once more. Idk how to make the zero number increase dynamically using javascript. When testing, i just manual add the form. Here my add click function javascript
var i = 0,
clone = $('#form-message').clone(),
recipient = document.getElementById('recipient');
recipient.setAttribute('name', 'rows['+ i +'][DestinationNumber]');
clone.appendTo('.form-message:last');
i++;
For second and next rows, name attribute not added on the input elements.
Thanks
You're mixing blade and jquery and vue in a way that is pretty confusing. Check out this JS fiddle that accomplishes all of this with Vue:
https://jsfiddle.net/cr8vfgrz/10/
You basically have an array of messages that are automatically mapped to inputs using v-for. As those inputs change, your messages array changes. Then when submit is pressed, you just post this.messages and the array of messages is sent to server. Then you can clear the array to reset the form.
Template code:
<div id="form-message">
<button class="btn btn-default" #click="addNewMessage">New Message</button>
<template v-for="message in messages">
<input type="text" v-model="message.DestinationNumber" class="form-control">
<textarea rows="3" v-model="message.TextDecoded" class="form-control"></textarea>
</template>
<button class="btn btn-success" #click.prevent="submitForm">Submit</button>
</div>
Vue code:
var newSingleMessage = new Vue({
el: '#form-message',
data: {
messages: [
{
DestinationNumber: '',
TextDecoded: ''
}
],
submitted:false
},
methods: {
addNewMessage: function(){
this.messages.push({
DestinationNumber: '',
TextDecoded: ''
});
},
submitForm: function(e) {
console.log(this.messages);
this.$http.post('api/outbox', {messages:this.messages})
.then(function(response){
//handle success
console.log(response);
}).error(function(response){
//handle error
console.log(response)
});
this.messages = [{ DestinationNumber: '', TextDecoded: '' }];
this.submitted = true;
}
}
});
Edit:
In the controller you can use $request->input('messages'); which will be the array of messages. You can insert multiple new Outbox model using:
Outbox::insert($request->input('messages'));
or
foreach($request->input('messages') as $message){
Outbox::create($message);
}

How to delete from the database using JQuery and Laravel

I have the following code with an if statement depending if a user has saved an article or not. I'm simply trying to delete the article from the database using jquery. I unsure where im going wrong? help is much appreciated!
View:
<form action="{{URL::route('article-delete')}}" method="post" id="article_one_delete">
<div class="form-group">
<input type="hidden" name="first_desc" value="{{$firstrow->description}}" class="form-control">
</div>
<div class="form-group">
<input type="hidden" name="first_title" value="{{$firstrow->title1}}" class="form-control">
</div>
<button type ="button" id="Recodelete" class="btn btn-success btn-xs">UnSave</button>
{{Form::token()}}
</form>
Route:
Route::delete('/home/', array( 'as' => 'article-delete',
'uses' => 'HomeController#deletearticle'));
Controller:
public function deletearticle(){
$firsttitle = Input::get('first_title');
$articledelete = UserSaveArticle::where('user_id', Auth::id()
->where ('user_save_articles.chosen_title', $firsttitle))->delete();
return true;
JQuery:
$(document).ready(function(){
$('#Recodelete').on('click', function(){
var article_one_delete = $('#article_one_delete').serializeArray();
var url_d = $('#article_one_delete').attr('action');
$.get(url_d, article_one_delete, function(data){
console.log(data);
});
});
});
You should define right route for DELETE article, like this:
Route::delete('/article/{id}', ['as' => 'article-delete', 'uses' => 'HomeController#deleteArticle']);
In the HomeController $id variable (article ID) will be available as a method parameter:
function deleteArticle($id)
{
…
}
In PHP side you defined DELETE route, it means you should make DELETE request on JS side using the ajax method:
$.ajax({
url: '/article/' + articleId,
type: 'DELETE',
success: function(result) {
// Do something with the result
}
});

Using post from Angular.js does not work

Ive built a rest-API to add todos in a mongodb. I can successfully save instances by using the following setup in postman:
http://localhost:3000/api/addtodo x-www-form-urlencoded with values text="Test", completed: "false".
Now when I try to replicate this with Angular, it doesnt work, the todo is saved but without the text and completed attributes, I cant seem to access the text or completed values from body. What am I doing wrong? Code below:
Angular-HTML:
<div id="todo-form" class="row">
<div class="col-sm-8 col-sm-offset-2 text-center">
<form>
<div class="form-group">
<!-- BIND THIS VALUE TO formData.text IN ANGULAR -->
<input type="text" class="form-control input-lg text-center" placeholder="I want to buy a puppy that will love me forever" ng-model="formData.text">
</div>
<!-- createToDo() WILL CREATE NEW TODOS -->
<button type="submit" class="btn btn-primary btn-lg" ng-click="createTodo()">Add</button>
</form>
</div>
</div>
Angular-js:
$scope.createTodo = function() {
$http.post('/api//addtodo', $scope.formData)
.success(function(data) {
$scope.formData = {}; // clear the form so our user is ready to enter another
$scope.todos = data;
console.log(data);
})
.error(function(data) {
console.log('Error: ' + data);
});
};
REST-API:
router.post('/addtodo', function(req,res) {
var Todo = require('../models/Todo.js');
var todo = new Todo();
todo.text = req.body.text;
todo.completed = req.body.completed;
todo.save(function (err) {
if(!err) {
return console.log("created");
} else {
return console.log(err);
}
});
return res.send(todo);
});
$http.post sends it's data using application/json and not application/x-www-form-urlencoded. Source.
If you're using body-parser, make sure you've included the JSON middleware.
app.use(bodyParser.json());
Either that or change your default headers for angular.
module.run(function($http) {
$http.defaults.headers.post = 'application/x-www-form-urlencoded';
});

Categories