How to get Laravel validation errors in react component which is in Laravel blade - javascript

I'm new to React. I'm using react form component partially in the Laravel blade. Then how can I send validation error messages from controllers to that react component which is resides in the Laravel blade file.
In my Controller,
public function store(Request $request)
{
$rules = [
'name' => 'required',
'publish_at' => 'required|datetime'
];
$this->validate($request, $rules);
$book = Book::create([
'name' => $request->name,
'publish_at' => $request->publish_at
]);
return response()->json($book);
}
In my laravel blade,
<form method="POST" action="patients">
#csrf
<div class="form-group">
<label for="name">Name</label>
<input type="text" name="name" class="form-control" placeholder=". . .">
#error('name')
<span class="text-danger">{{ $message }}</span>
#enderror
</div>
<div id="publish_at"></div> <!-- this is react component -->
<button type="submit">Submit</button>
</form>

According to Laravel docs, they send a response with 422 code on
failed validation:
If the incoming request was an AJAX request, no redirect will be
generated. Instead, an HTTP response with a 422 status code will be
returned to the browser containing a JSON representation of the
validation errors
*So, you just need to handle response and, if validation failed, add a
validation message to the state, something like in the following code
snippet*
request = $.ajax({
url: "/user",
type: "post",
data: 'email=' + email + '&_token={{ csrf_token() }}',
data: {'email': email, '_token': $('meta[name=_token]').attr('content')},
beforeSend: function(data){console.log(data);},
error: function(jqXhr, json, errorThrown) {
if(jqXhr.status === 422) {
//status means that this is a validation error, now we need to get messages from JSON
var errors = jqXhr.responseJSON;
var theMessageFromRequest = errors['email'].join('. ');
this.setState({
validationErrorMessage: theMessageFromRequest,
submitted: false
});
}
}.bind(this)
});
After that, in the 'render' method, just check if this.state.validationErrorMessage is set and render the message somewhere:
render: function() {
var text = this.state.submitted ? 'Thank you! Expect a follow up at '+email+' soon!' : 'Enter your email to request early access:';
var style = this.state.submitted ? {"backgroundColor": "rgba(26, 188, 156, 0.4)"} : {};
return (
<div>
{this.state.submitted ? null :
<div className="overall-input">
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true}>
<input type="email" className="input_field" onChange={this._updateInputValue} ref="email" value={this.state.email} />
<div className="validation-message">{this.state.validationErrorMessage}</div>
<div className="button-row">
<a href="#" className="button" onClick={this.saveAndContinue}>Request Invite</a>
</div>
</ReactCSSTransitionGroup>
</div>
}
</div>
)
}

Related

After Filling all Fields laravel sending 'required' error

I am trying to submit a form using axios post request in laravel. In this form i have 3 fields, name,age and a file called image.
here is the form
<form action="{{route('forms.store')}}" method="post" enctype="multipart/form-data">
#{{name}}
#csrf
<span v-if="errors.name">#{{errors.name[0]}}</span>
<label for="name">Name:</label>
<input type="text" name="name" id="name" v-model="name">
<span v-if="errors.age">#{{errors.age[0]}}</span>
<label for="age">Age:</label>
<input type="text" name="age" id="age" v-model="age">
<label for="image">Image:</label>
<span v-if="errors.image">#{{errors.image[0]}}</span>
<input type="file" name="image" id="image" #change="imageChanged">
<button #click.prevent="submitForm">Submit</button>
</form>
Here is my vueJs code:
const app = new Vue({
el: '#app',
data:{
name:'',
age:'',
image:'',
errors:{}
},
methods:{
imageChanged(e){
app.image = e.target.files[0]
console.log(e.target.files[0]);
},
submitForm(){
const config = { headers: { 'Content-Type': 'multipart/form-data' } };
const fd = new FormData(this.$data);
fd.append('image',this.image);
axios.post('{{route('forms.store')}}',this.fd,config).then((response)=>{
console.log(response.data);
}).catch((error)=>{
//console.log(error.response.data);
this.errors = error.response.data.errors;
})
}
}
});
And here is my controller
public function store(Request $request)
{
$this->validate($request, [
'name' => 'required',
'age' => 'required',
]);
if ($request->hasFile('image')) {
$image = $request->file('image');
return $ext = $image->extension();
} else {
return "NOT OK";
}
}
So here I am validating name and age. But my problem is when I fill the form and submit the form,
It sends back errors that name and age field is required.
where am I doing wrong and how to receive this data in the controller.
Thank you in advance.
I believe your code is in error in this part. changes:
axios.post('{{route('forms.store')}}',this.fd,config)
to:
axios.post('{{route('forms.store')}}',fd,config)

"Uncaught TypeError: Cannot read property 'create' of undefined" while using stripe payment method Stripe.charges.create({}) in angularJS/NodeJS

Hello I am new to AngularJS and working on a project where i am creating a payment form with stripe. I have create the form and create my JS code as described in the stripe's website. I am getting true response for card verification but payment method gives me this error on console "Uncaught TypeError: Cannot read property 'create' of undefined",
Following is my HTML code:
<div class="checkout_popup" id="checkout_popup">
<div class="col-md-12"><h3>Form</h3></div>
<form id="payment-form" method="post">
<div class="col-md-12"><input type="email" id="email" placeholder="Email" /></div>
<div class="col-md-12"><input type="text" id="card-number" data-stripe="number" value="4242424242424242" placeholder="Card Number (16 Digit)"/></div>
<div class="col-md-12"><input type="text" id="card-cvc" placeholder="cvc" data-stripe="cvc" value="123" /></div>
<div class="col-md-12"><input type="text" id="card-expiry-month" data-stripe="exp_month" value="12" placeholder="Month Expire" /></div>
<div class="col-md-12"><input type="text" id="card-expiry-year" data-stripe="exp_year" value="2017" placeholder="Year Expire" /></div>
<div class="col-md-12"><input type="button" id="pay-now" value="Pay Now" ng-click="submitstripe()" /></div>
</form>
</div>
and this the JS code:
.controller('UserAccountController', function($scope, $http, $state, $stateParams, $filter) {
$scope.submitstripe = function(){
console.log('ready stripe');
Stripe.card.createToken({
number: document.getElementById('card-number').value,
cvc: document.getElementById('card-cvc').value,
exp_month: document.getElementById('card-expiry-month').value,
exp_year: document.getElementById('card-expiry-year').value
}, stripeResponseHandler);
return false;
};
})
function stripeResponseHandler(status, response) {
if (response.error) { // Problem!
console.log(response.error.message);
} else { // Token was created!
// Get the token ID:
var token = response.id;
// Insert the token into the form so it gets submitted to the server:
console.log('Credit card verified, your token is : '+token);
var email = document.getElementById('email').value;
var charge = Stripe.charges.create({
amount: 10, // Amount in cents
currency: "usd",
source: token,
description: "test charges"
}, function(err, charge) {
if (err && err.type === 'StripeCardError') {
// The card has been declined
alert('Your card is not valid');
}
document.getElementById('card-number').value = '';
document.getElementById('card-cvc').value = '';
document.getElementById('card-expiry-month').value = '';
document.getElementById('card-expiry-year').value = '';
document.getElementById('checkout_popup').style.display = 'none';
alert('payment successfull');
});
}
}
Looks like you're trying to process the charge on the client side. But the documentation states:
Use Stripe's API and your server-side code to process charges.
The client side library is different from the NodeJS library. You're trying to call stripe.charges on the client library that doesn't exist. This logic should be created on the Server side.
If you check the source code for the Client side library here you will see that the charges object doesn't exist.
Instead, it's available here in the NodeJS library

Symfony2: manually submit a form without class via AJAX

We have an old website where I have implemented a form that is sent by AngularJS to a PHP script and after processing an email message get sent. If the form is not valid the PHP script returns a JSON with the validation errors. Since we already use Symfony for some other applications (REST APIs), I thought it would be nice to reimplement my plain PHP script in Symfony.
For the sake of simplicity I put only a small but relevant fragment of my code. This is what I have:
HTML (ng-app is bound on body tag, not shown here):
<form name="infoscreenForm" class="form-horizontal" enctype="multipart/form-data" ng-controller="FormController">
<div class="form-group">
<div class="col-lg-1 control-label">*</div>
<div class="col-lg-11 input-group">
<input type="text" class="form-control" id="contact_person"
name="contact_person" ng-model="formData.contactPerson"
placeholder="Kontaktperson">
</div>
<span class="text-warning" ng-show="errors.contactPerson">
{{ errors.contactPerson }}
</span>
</div>
<div class="form-group">
<div class="col-lg-1 control-label">*</div>
<div class="col-lg-11 input-group">
<span class="input-group-addon">#</span>
<input type="email" class="form-control" id="email" name="email"
ng-model="formData.email" placeholder="E-Mail">
</div>
<span class="text-warning" ng-show="errors.email">
{{ errors.email }}
</span>
</div>
<div class="form-group">
<div class="col-lg-1 control-label"> </div>
<div class="col-lg-11 input-group">
<input type="file" class="form-control" id="file" name="file"
file-model="formData.file"
accept="application/pdf,image/jpeg,image/png">
</div>
<span class="text-warning" ng-show="errors.file">
{{ errors.file }}
</span>
</div>
<div class="form-group">
<button type="submit" class="btn btn-default" id="submit"
name="submit" ng-click="submitForm()">
Formular absenden
</button>
</div>
</form>
JS:
var app = angular.module('InfoscreenApp', []);
app.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
app.factory('multipartForm', ['$http', function ($http) {
return {
post : function (uploadUrl, data) {
var fd = new FormData();
for (var key in data) {
fd.append(key, data[key]);
}
return $http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers : { 'Content-Type': undefined }
});
}
};
}]);
app.controller('FormController', ['$scope', 'multipartForm', function ($scope, multipartForm) {
$scope.formData = {};
$scope.submitForm = function () {
var uploadUrl = 'http://localhost:8000/infoscreen';
multipartForm.post(uploadUrl, $scope.formData)
.then(function (data) {
console.log(data);
if (data.success) {
$scope.message = data.data.message;
console.log(data.data.message);
} else {
$scope.errors = data.data.errors;
}
});
};
}]);
With the plain PHP script everything works fine. Here is what I tried to do in Symfony:
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\EmailType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Email;
class DefaultController extends Controller
{
/**
* #Route("/infoscreen", name="infoscreen")
*/
public function infoscreenAction(Request $request)
{
$defaultData = array('message' => 'infoscreenForm');
$form = $this->createFormBuilder($defaultData)
->add('contactPerson', TextType::class, array(
'constraints' => array(
new NotBlank(),
)
))
->add('email', EmailType::class, array(
'constraints' => array(
new NotBlank(),
new Email(),
)
))
->add('file', FileType::class)
->add('submit', SubmitType::class)
->getForm();
;
$form->submit($request->request->get($form->getName()));
$data = $form->getData();
if ($form->isValid()) {
echo 'Alles ok';
// send an email
}
$errors = array();
$validation = $this->get('validator')->validate($form);
foreach ($validation as $error) {
$errors[$error->getPropertyPath()] = $error->getMessage();
}
$response = new Response();
$response->setContent(json_encode(array(
'form_data' => $data,
'errors' => $errors,
)));
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
CSRF is disabled in config.yml. The form is not bound to an entity class. After submitting the form I get the following object in the console:
{
data: Object,
status: 200,
config: Object,
statusText: "OK"
}
The important part is in data: Object:
{
form_data: {
contactPerson: null,
email: null,
message: "infoscreenForm",
file: null
},
errors : {
children[contactPerson].data = "This value should not be blank",
children[email].data = "This value should not be blank"
}
}
This happens when I submit the form with some values entered in the fields. It seems that the submitted data is not bound to the form in the controller. I'm probably missing something, but I stuck here and have no idea how to proceed. I tried with $form->bind($request), $form->handleRequest($request) and few other things, but it didn't work. Even if I bind the fields individually, I still don't get their values in the form.
Can somebody please help me.
Thanks in advance.
Try
$this->get('form.factory')->createNamedBuilder(null, 'form', $defaultData)
instead of
$this->createFormBuilder($defaultData)

SilverStripe submit HTML form through Ajax

I want to pass data from a simple HTML form to a controller through Ajax, then process the data and return a response back.
At the moment I have the following:
HomePage.ss
<form method="POST" class="form-horizontal submit-form" onsubmit="return checkform(this);">
<!-- Text input-->
<div class="form-group">
<label class="col-md-4 control-label" for="name">Name</label>
<div class="col-md-8">
<input id="name" name="name" type="text" placeholder="insert full Name" class="form-control input-md" required="" />
</div>
</div>
<!-- Button -->
<div class="form-group">
<label class="col-md-4 control-label" for="send-btn"></label>
<div class="col-md-8">
<button id="send-btn" name="send-btn" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
JavaScript
$('form.submit-form').submit(function() {
$.ajax({
type: 'POST',
url: 'processForm',
data: $(this).serialize(),
success: function(data) {
alert('data received');
}
});
});
HomePage.php
class HomePage_Controller extends Page_Controller {
public function events() {
$events = CalendarEvent::get();
return $events;
}
public function processForm() {
if (Director::is_ajax()) {
echo 'ajax received';
} else {
//return $this->httpError(404);
return 'not ajax';
}
}
}
In developer tools I can see that I got the xhr processForm with a 404 not found error.
How do I get this Ajax form working correctly with the SilverStripe controller?
Spider,
I've done something similar to below. This is a quick and dirty demo and hasn't been tested, but it may get you going in the right path. If you're unfamiliar with how forms work within SilverStripe there is a lesson for front end forms in SilverStripe. I've found the lessons useful personally and provide the code for the lesson as well: http://www.silverstripe.org/learn/lessons/introduction-to-frontend-forms?ref=hub
Page.php
<?php
class Page extends SiteTree
{
}
class Page_Controller extends Content_Controller
{
private static $allowed_actions = array(
'MyForm',
);
public function MyForm()
{
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.min.js');
Requirements::javascript(THIRDPARTY_DIR . '/jquery-validate/jquery.validate.min.js');
Requirements::javascript('/path/to/your/validation/script.js');
$fields = FieldList::create(
TextField::create('name')
->setTitle('Name')
);
$actions = FieldList::create(
FormAction::create('doSubmit')
->setTitle('Submit')
);
$requiredFields = RequiredFields::create(
'name'
);
$form = Form::create($this, 'MyForm', $fields, $actions, $requiredFields);
return $form;
}
public function doSubmit($data, $form)
{
//process $data or create your new object and simpley $form->saveInto($yourObject); then $yourObject->write()
//then deal with ajax stuff
if ($this->request->isAjax()) {
return $this->customise(array(
'YourTemplateVar' => 'Your Value'
))->renderWith('YourIncludeFile');
} else {
//this would be if it wasn't an ajax request, generally a redirect to success/failure page
}
}
}
YourValidationScript.js
(function ($) {
$(function () {
$('#MyForm_Form').validate({
submitHandler: function (form) {
$.ajax({
type: $(form).attr('method'),
url: $(form).attr('action') + "?isAjax=1",
data: $(form).serialize()
})
.done(function (response) {
$('.content').html(response);
})
.fail(function (xhr) {
alert('Error: ' + xhr.responseText);
});
},
rules: {
name: "required"
}
});
})
})(jQuery);
You need to understand how HTTP request routing is handled in SilverStripe.
When you send request POST /processForm, it is treated as page and managed by ModelAsController. That is why you get 404 error - there is no SiteTree record with URLSegment = processForm.
Solution 1
Use Form object. It creates all routing configuration automatically during runtime. Read more
https://docs.silverstripe.org/en/3.3/tutorials/forms/
https://docs.silverstripe.org/en/3.3/developer_guides/forms/
Solution 2
Use this approach, when you really want to go down to the simple one method request handler. Register custom controller and routing.
You specify your route in mysite/_config/routing.yml
---
Name: siteroutes
---
Director:
rules:
processCustomForm: CustomFormController
Handle your request
class CustomFormController extends Controller
{
public function handleRequest( SS_HTTPRequest $request, DataModel $model ) {
if (!$request->isPost()) {
// handle invalid request
}
$name = $request->postVar('name')
// process your form
}
}

Laravel - Check if username already exists before submitting form with jQuery AJAX

I've made a registration form with a lot of fields. Since when I submit data and the validator redirects back with errors some inputs are empty and the user has to lose time refilling them, I want to implement some front-end validations.
I'm stuck on checking if an username is already used on submit button press becasuse I'm not expert about AJAX.
In the AuthController I've created a function that returns a Json containing a response in relation of existence or not of the username in the database.
class UserAuthController extends Controller
{
public function isUserNameInUse( $username )
{
if (Auth::where('username', $username) != null){
return [ 'is_used' => 1 ];
}
return [ 'is_used' => 0 ];
}
}
In the routes.php there are these lines:
Route::group([ 'as' => 'api', 'prefix' => 'api', 'namespace' => 'Api'], function () {
Route::group([ 'as' => 'auth', 'prefix' => 'auth'], function () {
Route::any('/is_username_in_use/{username}', [
'as' => 'isUserNameInUse',
'uses' => 'UserAuthController#isUserNameInUse']);
});
});
The view is like that (only a piece of the form):
<form action="{{ route('web.company.postSignup') }}" method="post" id="signup-form" class="form-horizontal">
{!! csrf_field() !!}
#include( 'errors.handler' )
<label for="username">
{{ _('Username*') }} </label>
<input type="text" class="form-control" name="username" id="username"
value="{{ Input::old('username') }}" required>
<label for="password">
{{ _('Password*') }}
</label>
<input type="password" class="form-control" name="password" id="password"
value="{{ Input::old('password') }}" onchange="form.confirmPassword.pattern = this.value;"
required>
<label for="confirmPassword">
{{ _('Confirm Password*') }}
</label>
<input type="password" class="form-control" name="confirmPassword" id="confirmPassword" required>
<button class="btn btn-warning" id="submit-btn" type="submit">{{ _('Sign Up') }}</button>
</form>
This is the script, for now I've only tried to log the response of the controller, but it prints anything.
$(document).ready(function () {
$('form#signup-form').submit(function () {
var input_username = $('input[name=username]').val();
console.log(input_username);
$.getJSON('/api/auth/is_username_in_use/' + input_username, function (json) {
console.log(json);
});
return false;
});
});
There is no need to make an explicit check if user name is in use. You may skip this part and instead, when you storing your user's data validate them accordingly.
An example of this might be
public function store(Request $request)
{
$this->validate($request, [
'username' => 'required|unique:users',
'password' => 'required|confirmed'
]);
// process your logic
}
This way, if validation failed, you'll get a json response object containing error messages.
Note, this will work if you're on Laravel 5. If you are on 4.* refer to documentation for validation part.
You should change return [ 'is_used' => 0 ]; into return Response::json([ 'is_used' => 0 ]); and add use Response; to the top of your controller.

Categories

Resources