With Axios I get a form created with Symfony FormBuilder, which I then display in a modal:
template.html.twig:
productId = {{product.id}};
var url = Routing.generate("stripe_admin_product_update_form", {id: productId});
axios.get(url)
.then(function(response){
var form = response.data.form;
Swal.fire({
title: "Modifier ?",
html: form,
icon: "question",
showCancelButton: true,
allowOutsideClick: () => !Swal.isLoading(),
preConfirm: function(result)
{
//submit form
}
});
});
controller.php
/**
* #Route("/admin/stripe/product/{id}/update/form", name="stripe_admin_product_update_form", options={"expose"=true})
*
*/
public function getUpdateProductForm(StripeProduct $product)
{
$form = $this->createFormBuilder($product)
->add("name")
->add("unitLabel")
->add("bankStatementLabel")
->getForm();
// if($form->isSubmitted() && $form->isValid())
// {
// Traitment
// }
$response = [
"code" => 200,
"form" => $this->render("stripe_admin/product/_form_edit.html.twig", [
"form" => $form->createView(),
])->getContent()
];
return new JsonResponse($response);
}
It gives me something like:
How can I now validate the form with Axios?
The goal is therefore to return to the function, and that the line :
if($form->isSubmitted() && $form->isValid())
be detected, so that I can handle any errors and do the rest of the processing
You have to handle the request like a classic form submission (understand not submitted with AJAX)
/**
* #Route("/admin/stripe/product/{id}/update/form", name="stripe_admin_product_update_form", options={"expose"=true})
*
*/
public function getUpdateProductForm(Request $request, StripeProduct $product)
{
$form = $this->createFormBuilder($product)
->add("name")
->add("unitLabel")
->add("bankStatementLabel")
->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid())
{
//Traitment
}
$response = [
"code" => 200,
"form" => $this->render("stripe_admin/product/_form_edit.html.twig", [
"form" => $form->createView(),
])->getContent()
];
return new JsonResponse($response);
}
Related
In my Vue component, I'm sending an Axios request with an array of multiple files. How can I handle the individual files in my Laravel controller?
I always have an error saying 'Invalid argument supplied for foreach()'.
My Vue method to send the files:
uploadFiles() {
this.isPending = true;
this.error = null;
let f = new FormData();
f.append('files', this.files);
axios.post(`items/${this.$route.params.productId}/upload_files`, f)
.then((res) => {
console.log(res);
this.isPending = false;
}).catch((err) => {
console.log(err);
this.isPending = false;
this.error = 'Er is iets misgegaan. Probeer het nog een keer.';
});
}
My controller function:
public function upload_files(Request $request, $id)
{
$request->validate([
'files' => 'required'
]);
foreach ($request['files'] as $file) {
Storage::put($file->getClientOriginalName(), file_get_contents($file));
$path = $request->file('files')->store('public');
return $path;
}
}
So i am trying to update a user from the admin panel, i get the values from the form through a v-model and then i do my axios.put with all the data in a FormData(). The issue is that i get an error 500 saying that x field can't be empty, so i guess my FormData() isn't being passed on to the controller.
I tried with a post method and it worked fine. So i wonder what i did wrong ?
Here's the Vuejs code :
<script>
export default {
data () {
return {
search: '',
headers: [
{ text: 'ID', align: 'start', value: 'id'},
{ text: 'Name', value: 'name' },
{ text: 'Profile', value: 'profile' },
{ text: 'Email', value: 'email' },
{ text: 'Created At', value: 'created_at' },
{ text: 'Actions', value: 'actions' },
],
users: null,
editedUser: null,
dialog: false,
}
},
methods: {
getUsers(){
axios.get('../admin/getUsers')
.then(response => this.users = response.data)
},
editUser(item){
this.editedUser = item;
this.dialog = true;
},
submitEditedUser(){
let data = new FormData();
data.append('id', this.editedUser.id)
data.append('name', this.editedUser.name)
data.append('profile', this.editedUser.profile)
data.append('email', this.editedUser.email)
axios.put('../admin/updateUser/' + this.editedUser.id, data)
.then(res => {
console.log('done');
})
.catch(err => {
console.log('changes failed');
})
}
},
mounted(){
this.getUsers();
}
}
</script>
And here's the controller code :
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function updateUser($id, Request $request)
{
$user = User::find($id);
$user->name = request('name');
$user->profile = request('profile');
$user->email = request("email");
$user->save();
}
Everything works fine with post so nothing's wrong with the variable or the form, i think it really is just the data that's not being passed on. Although i want to use the put method because it is originally used for updating data.
Thanks !
can you try this? if this not work you can dd(request) inside the controller and see if is empty
public function updateUser($id, Request $request)
{
$user = User::find($id);
$user->name = $request->data['name'];
$user->profile = $request->data['profile'];
$user->email = $request->data['email'];
$user->save();
}
i created a form using AJAX because i have several alternatives concerning the fields.
I have correct information in my javascript and make tests... my first select use the following function and generates form
function setParentSector() {
$("#listSectors").html("");
$("#createSector").html("");
if($('#langname option:selected').val() !=0) {
var obj = { 'id': $('#langname option:selected').val() };
if (obj['id'] != 1) {
ajaxSectors(obj);
}
else
{
// another form generated here ...
$('#createSector').append("something else");
}
}
};
I use a "classical" ajax ..
function ajaxSectors(objSetParent) {
$.ajax({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
url: '/admin/ajax/sectorParent',
type: 'post',
dataType: 'json',
async: true,
success: function (result) {
$('#listSectors').append("<label for='langname'>label </label> " +
"<select class='form-control m-input m-input--air' id='sectors' onclick='setLangTranslation()'>" +
"<option value='0' selected>Select value</option></select>" +
"<span class='m-form__help' id='existsAlready'>");
var count = result.length;
for (var i = 0; i < count; i++) {
if (result[i].deleted_at === null) {
$('#sectors').append("<option value='" + result[i].sector_id + "'>" + result[i].sectname + "</option>");
}
else {
console.log("peanuts");
}
}
},
data:objSetParent,
error: function (result) {
},
complete: function (result) {
//console.log("complete");
}
});
}
This part of code works fine and i display what i want...
When I want to save into DB the form, I plan to use the store method and I create the $request->validate()
In the store method I have :
$request->validate([
'admin' => 'required',
'langname' => 'required',
'sectname' => 'required',
'sectshortname' => 'nullable',
]);
return view ('test')
The test view contains just in order to see what i post ..
If i keep the validate part, the page is just refreshed and not validated...
Without the request validate I display the view and i just see the value of the input with the token.
Thanks for your answers. Let's hope my question is "clear" enough
Use this code I hope this code works for you please use this Use Validator;
$rules = [
'admin' => 'required',
'langname' => 'required',
'sectname' => 'required',
'sectshortname' => 'nullable',
];
$data = $request->all();//or you can get it by one by one
$validator = Validator::make($data , $rules);
if ($validator->fails()) {
$error=[];
$errors = $validator->messages();
foreach($errors->all() as $error_msg){
$error[]= $error_msg;
}
return response()->json(compact('error'),401);
}
return view ('test')
I am getting my ajax callback in normal custom form, but on form alter its not working.
function sample_ajax_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
if ($form_id === 'node_sampleajax_form' || $form_id === 'node_sampleajax_edit_form') {
$form['field_nametrain']= array(
'#title' => t('training name'),
'#type' => 'select',
'#options' => _load_training(),
'#required' => FALSE,
'#ajax' => [
'callback' => [$this, 'changeOptionsAjax'],
// 'callback' => '::changeOptionsAjax',
'wrapper' => 'second_field_wrapper',
],
);
$form['field_namedomain'] = [
'#type' => 'select',
'#title' => t('Domain program'),
'#options' => $this->getOptions($form_state),
'#prefix' => '<div id="second_field_wrapper">',
'#suffix' => '</div>',
];
return $form;
}
}
function _load_training() {
$training = array('- Select domain training -');
$query = db_select("node__field_trainingname", "a");
$query->fields("a", array('field_trainingname_value', 'entity_id'));
$query->orderBy("a.field_trainingname_value");
$result = $query->execute();
while($row = $result->fetchObject()){
$training[$row->entity_id] = $row->field_trainingname_value;
}
return $training;
}
function changeOptionsAjax(array &$form, FormStateInterface $form_state) {
return $form['field_namedomain'];
}
function getOptions(array &$form, FormStateInterface $form_state) {
$cvvv = $form_state->getValue('field_nametrain');
<!-- return ["shgsh", $form_state->get(['field_nametrain'])]; -->
$options = array('- Select subdomain category -');
$query = db_select("node__field_trainingname", "a");
$query->fields("a", array('field_trainingname_value', 'entity_id'));
$query = db_select("node__field_cms", "b");
$query->fields("b", array('field_cms_value', 'entity_id'));
$query->join("node__field_trainingname", "b", "b.entity_id=a.entity_id");
$query->condition("a.entity_id", $cvvv);
$result = $query->execute();
while($row = $result->fetchObject()){
$options[$row->entity_id] = $row->field_cms_value;
}
return $options;
}
On using $this->getOptions($form_state) it represent the error log it is not an object and throws website encounter error in front end. But on custom form no error came only in formalter it throws error.
Kindly suggest me ideas to apply in form_alter of Drupal 8
The .module file, where your form alter hook is located, is not a class, therefore there is no $this. Your custom form however is a class (usually in your_module/src/Form/YourForm.php), that's why it works there but not in the .module file.
Further reading: http://www.php.net/manual/en/language.oop5.basic.php
and What does the variable $this mean in PHP?
In your case you should be able to just call
'#options' => getOptions($form, $form_state),
And more on a side note: I would strongly recommend to do some code refactoring.
In your custom submit handler, firt get the form object from the form state.
$formObj = $formState->getFormObject();
then call submitForm() on the form object and pass the form and form state variables.
$formObj->submitForm($form, $formState);
and finally, you just need to simply trigger the save() function on the object.
$formObj->save($form, $formState);
So the whole solution is something like
function YOR_CUSTOM_SUBMIT_HANLDLER(array $form, FormStateInterface $form_state) {
/** #var Drupal\user\RegisterForm $entity */
$formObj = $form_state->getFormObject();
$formObj->submitForm($form, $form_state);
$formObj->save($form, $form_state);
}
Hi I'm having a problem outputting my json information on saving method in the model. I get the following error -
UnexpectedValueException in Response.php line 397:
The Response content must be a string or object implementing __toString(), "boolean" given.
I do validation on the model while saving and in the validate method of the model I need to out put the json but I'm getting boolean instead of json object
Javascript:
submit: function(e) {
e.preventDefault();
var contact = this.model.save({
firstname: this.firstname.val(),
lastname: this.lastname.val(),
company: this.company.val(),
email_address: this.email_address.val(),
description: this.description.val(),
}, {success:function(response){ console.log(response)}, wait: true});
Contact Model:
class Contact extends Model
{
protected $table = "contacts";
protected $fillable = ['firstname', 'lastname', 'company', 'email_address', 'description'];
public static function boot() {
parent::boot();
static::creating(function($model) {
return $model->validate('POST');
});
static::updating(function($model) {
return $model->validate('PUT');
});
static::saving(function($model) {
return $model->validate('PUT');
});
}
public function rules($method)
{
switch($method)
{
case 'GET':
case 'DELETE':
{
return [];
}
case 'POST':
{
return [
'firstname' => 'required',
'lastname' => 'required',
'email_address' => 'required|email|unique:contacts,email_address',
'description' => 'requried'
];
}
case 'PUT':
case 'PATCH':
{
return [
'firstname' => 'required',
'lastname' => 'required',
'email_address' => 'required|email|unique:contacts,email_address,'.$this->id,
'description' => 'required',
];
}
default: break;
}
return [];
}
public function messages() {
return [
'firstname.required' => 'Please enter your first name.',
'lastname.required' => 'Please enter your first name.',
'email_address.required' => 'Please enter a email address.',
'email_address.email' => 'Please enter a valid email address',
'email_address.unique' => 'The email is not unique.',
'description' => 'Please enter a description.'
];
}
public function validate($method)
{
$data = $this->attributes;
// if( $data['slug'] === '') {
// // if the slug is blank, create one from title data
// $data['slug'] = str_slug( $data['title'], '-' );
// }
// make a new validator object
$v = Validator::make($data, $this->rules($method), $this->messages());
// check for failure
if ($v->fails())
{
// set errors and return false
// json here not return response it's always boolean true or false
return new JsonResponse(array('error' => true, 'errors' => $v->messages()));
}
// validation pass
return true; //new JsonResponse(array('errors'=>false));
}
public function errors() {
return $this->errors;
}
public function user() {
return $this->hasOne('App\User', 'email', 'email_address');
}
}
Saving the model:
public function update(Request $request, $id) {
$contact = Contact::find($id)->with('user')->first();
$contact->firstname = $request->get('firstname');
$contact->lastname = $request->get('lastname');
$contact->email_address = $request->get('email_address');
$contact->company = $request->get('company');
$contact->description = $request->get('description');
return $contact->save(); //return formatted json
}
According to your implementation of validation, you should change the following part (in Contact):
// check for failure
if ($v->fails())
{
// set errors and return false
// json here not return response it's always boolean true or false
return new JsonResponse(array('error' => true, 'errors' => $v->messages()));
}
To something like this:
if ($v->fails()) {
$this->errors = $v->errors();
return false;
}
Then, from the Controller, try something like this:
// If validation failed
if(!$contact->save()) {
return response()->json([
'error' => true,
'errors' => $contact->errors()
]);
}
// Contact created if reached here...
return response()->json(['error' => false, 'contact' => $contact]);
Also, check the Ajax-Request-Validation and Form-Request-Validation (Easier and Managable).
Note: Don't try to return any kind of HTTP Response from model. Returning the HTTP response is part of your application logic and model should not care about these.
As save() does return boolean so You've to check if it's ok.
1) Change Your Contact model to put errors to model's errors param:
/* if($v->fails()) remove/comment this line
...
} */
$this->errors = $v->errors();
return !$v->fails();
2) In Your controller put this code:
public function update(Request $request, $id) {
$contact = Contact::find($id)->with('user')->first();
if(!$contact) {
return response('Contact not found', 404);
}
$contact->firstname = $request->get('firstname');
$contact->lastname = $request->get('lastname');
$contact->email_address = $request->get('email_address');
$contact->company = $request->get('company');
$contact->description = $request->get('description');
return $contact->save()?
$contact->toJson() : // returns 200 OK status with contact (json)
response($contact->errors, 400); // returns proper 400 Bad Request header with errors (json) in it
}
p.s. it's nice to answer to requester with http status, industry has made all to make life of developer easy, so if it's not 2xx, 3xx status so => response for Your request from client-side app will be treated as error (handler success: function(response) will not catch error here)