jQuery 使用ajax提交symfony 3表单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44087779/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
submit symfony 3 form with ajax
提问by coder's den
I'm trying to implement my symfony forms / modal ,with ajax to stop reloading page every time time I submit an add/remove and update action, but the problem that I'm not familiar with ajax and I don't know how to do it. Can anyone help me understand the concept.
我正在尝试实现我的 symfony 表单/模式,每次提交添加/删除和更新操作时,使用 ajax 停止重新加载页面,但问题是我不熟悉 ajax,我不知道如何做吧。谁能帮我理解这个概念。
mY entity :
我的实体:
<?php
namespace EvalBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Department
*
* @ORM\Table(name="department")
* @ORM\Entity(repositoryClass="EvalBundle\Repository\DepartmentRepository")
*/
class Department
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string",unique=true)
*/
private $name;
/**
* One Department has Many Collaborators.
* @ORM\OneToMany(targetEntity="Collaborator", mappedBy="department")
*/
private $collaborators;
/**
* Get id
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
*
* @return Department
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
}
form :
形式 :
<?php
namespace EvalBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class DepartmentType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name');
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'EvalBundle\Entity\Department',
'attr' => array('novalidate' => 'novalidate')
));
}
/**
* {@inheritdoc}
*/
public function getBlockPrefix()
{
return 'evalbundle_department';
}
}
Controller :
控制器 :
<?php
/**
* Created by PhpStorm.
* User: sa7noun
* Date: 5/15/17
* Time: 12:09 PM
*/
namespace EvalBundle\Controller;
use EvalBundle\Entity\Department;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
class DepartmentController extends Controller
{
/**
* Lists all Department entities.
*
* @Route("/department", name="department_index")
* @Method({"GET","POST"} )
*
*/
public function indexAction(Request $request)
{
$department = new Department();
$form = $this->createForm('EvalBundle\Form\DepartmentType', $department);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($department);
$em->flush();
return $this->redirectToRoute('department_index');
}
$em = $this->getDoctrine()->getManager();
$departments = $em->getRepository('EvalBundle:Department')->findAll();
/**
* @var $paginator \Knp\Component\Pager\Paginator
*/
$paginator = $this->get('knp_paginator');
$result = $paginator->paginate(
$departments,
$request->query->getInt('page', 1),
$request->query->getInt('limit', 5)
);
return $this->render('EvalBundle:Department:department.html.twig', array(
'departments' => $result,
'form' => $form->createView(),
));
}
// /**
// * Creates a new Department entity.
// *
// * @Route("/department/new", name="department_new")
// * @Method({ "POST"})
// */
// public function newAction(Request $request)
// {
// $department = new Department();
// $form = $this->createForm('EvalBundle\Form\DepartmentType', $department);
// $form->handleRequest($request);
//
// if ($form->isSubmitted() && $form->isValid()) {
// $em = $this->getDoctrine()->getManager();
// $em->persist($department);
// $em->flush();
//
// return $this->redirectToRoute('department_index');
// }
//
// return $this->render('EvalBundle:Department:department.html.twig', array(
// 'department' => $department,
// 'form' => $form->createView(),
// ));
// }
/**
* Displays a form to edit an existing department entity.
*
* @Route("department/{id}/edit", name="department_edit")
* @Method({"GET", "POST"})
*/
public function editAction(Request $request, Department $department)
{
$deleteForm = $this->createDeleteForm($department);
$editForm = $this->createForm('EvalBundle\Form\DepartmentType', $department);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('department_edit', array('id' => $department->getId()));
}
return $this->render('EvalBundle:Department:edit.html.twig', array(
'department' => $department,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a department entity.
*
* @Route("department/{id}", name="department_delete")
* @Method({"GET","DELETE"})
*/
public function deleteAction(Department $department)
{
// $response = array(
// 'success' => true,
// 'message' => '',
// 'html' => '',
// );
//
// $form = $this->createDeleteForm($department);
// if ($request->getMethod() == 'DELETE'){
// $form->handleRequest($request);
// }
//
if ($department) {
$em = $this->getDoctrine()->getManager();
$em->remove($department);
$em->flush();
}
return $this->redirectToRoute('department_index');
}
/**
* Creates a form to delete a department entity.
*
* @param Department $department The department entity
*
* @return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm(Department $department)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('department_delete', array('id' => $department->getId())))
->setMethod('DELETE')
->getForm();
}
}
View (Index):
查看(索引):
{% extends 'default/superAdminBase.html.twig' %}
{% block body %}
<div class="col-lg-6">
<div class="panel panel-default">
<div class="panel-heading" style="background-color: #0089db">
<h5 style="text-align: center"><b>Départements</b></h5>
</div>
<!-- /.panel-heading -->
<div class="panel-body">
<div class="table-responsive">
<table class="table table-hover table-fixed table-paginated">
<thead>
<tr>
</tr>
</thead>
<tbody>
{% for department in departments %}
<tr>
<td>
<b>{{ department.name }}</b>
<a href="{{ path('department_edit', { 'id': department.id }) }}"
class="btn btn-default btn-circle " style="float: right">
<i class="fa fa-edit"></i>
</a>
<a href="{{ path('department_delete', {'id': department.id}) }}"
class="btn btn-danger btn-circle remove-item"
data-entity-id="{{ department.id }}" style="float: right" data-toggle="modal">
<span class="glyphicon glyphicon-remove"></span>
</a>
<div class="modal fade" id="infos">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">x</button>
<h4 class="modal-title">Confirmation</h4>
</div>
<div class="modal-body">
Etes-vous sur de voultheitroad supprimer ce Département !
</div>
<div class="modal-footer">
<button href=" #" class="btn btn-info delete-item"
data-dismiss="modal">OUI
</button>
<button class="btn btn-info" data-dismiss="modal">NON</button>
</div>
</div>
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- /.table-responsive -->
</div>
<!-- /.panel-body -->
</div>
<div class="navigation text-center">
{{ knp_pagination_render(departments) }}
</div>
<!-- /.panel -->
<div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog" tabindex="-1" id="myModal-1" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
{% if app.session.flashBag.has('success') %}
<div class="aler alert-success">
{% for msg in app.session.flashBag.get('success') %}
{{ msg }}
{% endfor %}
</div>
{% endif %}
<button aria-hidden="true" data-dismiss="modal" class="close" type="button">×</button>
<h4 class="modal-title"> Ajouter un nouveau département</h4>
</div>
<div class="modal-body" id="modal-input">
{{ form_start(form,{'attr': {'class': 'form-horizontal','data-parsley-validate':''}}) }}
{{ form_widget(form.name,{'attr': {'class': 'form-control','placeholder':'Nom de département', 'data-parsley-required':'true', 'data-parsley-required-message':'le nom ne doit pas être vide :D'}}) }}
<br>
<div class="form-group">
<div class="col-lg-offset-8 col-lg-4">
<button type="submit" class="btn btn-block btn-primary"><span
class="glyphicon glyphicon-plus"></span> Créer
</button>
</div>
</div>
{{ form_end(form) }}
</div>
</div>
</div>
</div>
</div>
<a href="#myModal-1" data-toggle="modal" class="btn btn-outline btn-primary "><i class="fa fa-plus"></i>Ajouter un
département</a>
{% block javascript %}
<script src="{{ asset('JS/departmentValidation.js') }}"></script>
{% endblock %}
{% endblo
ck %}
回答by john Smith
i will answer this very basically to let you get an idea !
我会非常基本地回答这个问题,让你有个想法!
so first of all you will have to separate the saving part on the server side, because it will not return a view anymore like your indexAction does. Instead it returns some json data your ajax call on the client side can receive
所以首先你必须在服务器端分离保存部分,因为它不会像你的 indexAction 那样返回一个视图。相反,它返回一些 json 数据,您在客户端的 ajax 调用可以接收
your new controller action may look somelike this:
您的新控制器操作可能如下所示:
/**
* Creates a new Department entity.
*
* @Route("/department/new", name="department_new")
* @Method({ "POST"})
*/
public function newDepartmentAction(Request $request)
{
$department = new Department();
$form = $this->createForm('EvalBundle\Form\DepartmentType', $department);
$form->handleRequest($request);
$status = "error";
$message = "";
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($department);
try {
$em->flush();
$status = "success";
$message = "new department saved";
} catch (\Exception $e) {
$message = $e->getMessage();
}
}else{
$message = "invalid form data";
}
$response = array(
'status' => $status,
'message' => $message
);
return new JsonResponse($response);
// above is just an example of one way using formtypes,
// you can retrieve any parameter you send here like:
// $param = $request->get('param');
}
you can do above whatever you want like paginate over all departments and return them, but you would need a js way to display the returned JSON then, you cant use twig for that because the view is already returned, you definetly want to use any datadriven JS View Model lib with automatic ui refresh.
你可以做任何你想做的事情,比如对所有部门进行分页并返回它们,但是你需要一种 js 方式来显示返回的 JSON,你不能使用 twig 因为视图已经返回,你肯定想使用任何数据驱动具有自动 ui 刷新的 JS 视图模型库。
Next, The client Side - From the client side you will have to send the the correct data to that action
接下来,客户端 - 从客户端,您必须向该操作发送正确的数据
so you have to serialize the formfields to a set of properties and values that you can send to the server. We will first serialize the form to a javascript object.
因此您必须将表单域序列化为一组可以发送到服务器的属性和值。我们首先将表单序列化为一个 javascript 对象。
here you have a function for that that you have to include somewhere after jquery has loaded and before your further code
在这里,您有一个函数,您必须在加载 jquery 之后和进一步代码之前将其包含在某处
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
Next you have to avoid actually submitting the form non-ajax, because clicking on the submit button will lead to submit the form and reload the page, we prevent that behaviour, assuming the form has some unique selector eG. id="newDepartmentForm"
接下来,您必须避免实际提交非 ajax 表单,因为单击提交按钮将导致提交表单并重新加载页面,我们防止这种行为,假设表单有一些独特的选择器 eG。id="newDepartmentForm"
$(document).on("submit", "#newDepartmentForm", function(e){
e.preventDefault();
return false;
});
now lets assume you want to save by clicking on a button with specific id
现在让我们假设您想通过单击具有特定 id 的按钮来保存
$(document).on("click", "#mySubmitButton", function(e){
e.preventDefault();
var form = $("#newDepartmentForm");
// you could make use of html5 form validation here
if(!form[0].checkValidity()){
// To show the native error hints you can fake a click() on the actual submit button
// which must not be the button #mySubmitButton and shall be hidden with display:none;
// example:
// <button type="button" id="#mySubmitButton" class"btn btn-default" > Save </button>
// <button type="submit" id="#myHIDDENSubmitButton" style="display:none;"></button>
//
$("#myHIDDENSubmitButton").click();
return false;
}
// get the serialized properties and values of the form
var form_data = form.serializeObject();
// always makes sense to signal user that something is happening
$('#loadingSpinner').show();
// simple approach avoid submitting multiple times
$('#mySubmitButton').attr("disabled",true);
// the actual request to your newAction
$.ajax({
url: '/department/new',
type: 'POST',
dataType: 'json',
data: form_data,
success:function(data){
// handling the response data from the controller
if(data.status == 'error'){
console.log("[API] ERROR: "+data.message);
}
if(data.status == 'success'){
console.log("[API] SUCCESS: "+data.message);
}
// signal to user the action is done
$('#loadingSpinner').hide();
$('#mySubmitButton').attr("disabled",false);
}
});
});
basically thats it.
基本上就是这样。
if you want to make your site full Ajax-driven, you can request any data from the server like this, for example you may want to load all existing departments first you could just do it like above. But as i mentioned, you would need a JS way to Display your data, terms like single page application, MVVM could be worth a lookup there are a lot of usefull libraries like vue, react, knockout, ember ... etc. if you prefer an easy way, they may not be neccessary depending on the complexity of your model. For your Api you also may dig more into performant serialization, REST, CRUD, authorization and dont repeat yourself. Websockets may also be very interesting.
如果你想让你的网站完全由 Ajax 驱动,你可以像这样从服务器请求任何数据,例如你可能想先加载所有现有部门,你可以像上面那样做。但正如我提到的,你需要一种 JS 方式来显示你的数据,像单页应用程序这样的术语,MVVM 可能值得一看,有很多有用的库,比如 vue、react、knockout、ember 等等。如果你更喜欢简单的方法,根据模型的复杂性,它们可能不是必需的。对于您的 Api,您还可以深入研究高性能序列化、REST、CRUD、授权,不要重复自己。Websockets 也可能非常有趣。