I am creating eisenhover matrix and I want a button to refresh a data in grid, but I have no idea how to pass parameters/variables with ajax.
/**
* #Route("/articles/list", name="articles_list")
*/
public function showArticlesAction(bool $important = false, bool $urgent = false){
$articles = $this->returnAllArticles();
return $this->render(
'articles/list.html.twig',
array('articles' => $articles,
'important' => $important,
'urgent' => $urgent)
);
}
and script
function refreshFunctionName()
{
$.ajax({
type: "POST",
url: "{{ path('articles_list') }}",
data: {'important': true, 'urgent': true},
cache: false,
success: function(data){
$('#list').html(data);
},
error: function(){},
complete: function(){}
});
}
the showArticlesAction always takes default data if I try to use it with ajax, works fine with:
{{ render(controller(
'AppBundle:Articles:showArticles',
{ 'important': true,
'urgent': true}
)) }}
You need to define those parameters in the Route definition:
/**
* #Route("/articles/list/{important}/{urgent}", name="articles_list")
*/
and you GET method in AJAX call or get those parameters from POST table
/**
* #Route("/articles/list", name="articles_list")
*/
public function showArticlesAction(Request $request){
$articles = $this->returnAllArticles();
$important = $request->request->get('important');
$urgent = $request->request->get('urgent');
return $this->render(
'articles/list.html.twig',
array('articles' => $articles,
'important' => $important,
'urgent' => $urgent)
);
}
Related
I'm trying to make a tabs nav with a central block that contains a Symfony form.
When I click into a link in a tab navs, I reload the block with form and data.
But the issue is how to pass formView object from the first twig to the AJAX twig response view?
My controller
/**
* #Route("/change-tab/{tabId}", name="change_tab")
* #param Request $request
* #return Response
*/
public function changeTab(Request $request, $tabId): Response
{
$firstElement = $this->getDoctrine()->getRepository(Element::class)->findOneBy([
'cart'=>$tabId,
]);
return $this->render('partials/_bloc-cart.html.twig',[
'firstElement '=> $firstElement ,
//'form' => $request->getContent()
]);
}
My twig view
<div class="row p-2">
<div class="col-md-12 px-0" id="bloc-form">
{{ include('partials/_form.html.twig') }}
</div>
</div>
And the ajax JS :
$(document).on('click', '.linkToChange', function () {
$('.linkToChange.active').removeClass('active');
$(this).addClass('active');
let formPlan = $('#bloc-form').data('form');
$.ajax({
type: "POST",
data : formPlan,
url: "/ajax/change-tab/" + $(this).data('cart'),
success : function (datas) {
$('#bloc-form').html(datas);
}
});
});
You have different ways to do it, if you use the Form Component, you can do something like this:
public function changeTab(Request $request, $tabId): Response
{
$firstElement = $this->getDoctrine()->getRepository(Element::class)->findOneBy([
'cart'=>$tabId,
]);
$form = $this->createForm(ElementType::class, $firstElement);
$form->handleRequest($request);
// Save if form is submitted and valid
return $this->render('partials/_bloc-cart.html.twig',[
'firstElement '=> $firstElement ,
'form' => $form->createView()
]);
}
You can try:
/**
* #Route("/change-tab", name="change_tab", method="{POST}")
* #param Request $request
* #return Response
*/
public function changeTab(Request $request)
{
$tabId = $request->get('tab_id');
$firstElement = $this->getDoctrine()->getRepository(Element::class)->findOneBy([
'cart'=>$tabId,
]);
$html = $this->render('partials/_bloc-cart.html.twig',[
'firstElement '=> $firstElement ,
//'form' => $request->getContent()
]);
return $this->json(['html' => $html]);
}
Jquery:
$.ajax({
type: "POST",
data : formPlan,
url: "{{ url('change-tab') }}",
dataType: 'json',
data: {
'tab_id' : $(this).data('cart'),
}
success : function (data) {
$('#bloc-form').remove();
$('#bloc-form').html(data.html);
}
});
I'm trying to use the same blade to return a response from ajax.
In my first controller function I return a view with data:
public function index()
{
$data = (object) array(
'title' => trans('web.blog_title'),
'description' => trans('web.blog_header_info'),
);
$posts = \DB::table('blogs')->paginate(3);
return view('web.blog')->with('data', $data)->with('posts', $posts);
}
But now I'm doing a search with ajax and I want to use the same blade template for the response.
My second function that should render my response is:
public function getLocalNews($restaurant_id) {
$data = (object) array(
'title' => trans('web.blog_title'),
'description' => trans('web.blog_header_info'),
);
$news = Blog::query()->where('restaurant_id', '=', $restaurant_id)->paginate(3);
return view('web.blog')->with('data', $data)->with('posts', $news);
}
but it doesn't do anything...
ajax:
$("#submit_btn_blog_res").on("click", function(e){
e.preventDefault();
var form = $('#searchRestaurant');
$(this).find('input').removeClass('is-invalid');
$(this).find('.error').html('');
$.ajax({
url: "blog/getLocalNews/" + $(".suggest-element").attr('id'),
data: form.serializeArray(),
type: 'GET',
dataType: form.data('type'),
success: function(data){
console.log(data);
$(".post-article").remove();
},
error: function(jqXHR){
var response = JSON.parse(jqXHR.responseText);
if (response.errors.name) {
$(form).find('input[name="name"]').addClass('is-invalid');
$(form).find('.name-error').html(response.errors.name);
} else if (response.errors.email) {
$(form).find('input[name="email"]').addClass('is-invalid');
$(form).find('.email-error').html(response.errors.email);
} else if (response.errors.phone) {
$(form).find('input[name="phone"]').addClass('is-invalid');
$(form).find('.phone-error').html(response.errors.phone);
} else if (response.errors.comments) {
$(form).find('input[name="comments"]').addClass('is-invalid');
$(form).find('.comments-error').html(response.errors.comments);
} else if (response.errors.gRecaptchaResponse) {
$(form).find('input[name="g-recaptcha-response"]').addClass('is-invalid');
$(form).find('.g-recaptcha-response-error').html(response.errors.gRecaptchaResponse);
}
}
});
}); //submit search form restaurant
You should pass your response with a content-type of application/json. Hopefully, laravel has a function as response() which do this for you.
public function getLocalNews($restaurant_id){
$data = (object) array(
'title' => trans('web.blog_title'),
'description' => trans('web.blog_header_info'),
);
$news = Blog::query()->where('restaurant_id', '=', $restaurant_id)->get();
$response_data = ['data'=>$data, 'posts'=>$news];
return response()->json($response_data, 200);
}
As said in laravel helpers functions doc First parameter of response() receives the data that you want to be included in the body. If you pass an array, it will be converted to json, and the second parameter is the http status code of the response.
Notice: If you want to send your results with pagination. You can use laravel api resource.
Update: Use your ajax to add new received data to your html.
success: function(response){
console.log(response);
$('#desired-element-for-data').html('');
$.each(response.data, function(item){
html1 += '<p>item</p>';
});
$('#desired-element-for-posts').html('');
$.each(response.posts, function(item){
html2 += '<p>item</p>';
});
$('#desired-element-for-data').html(html1);
$('#desired-element-for-posts').html(html2);
$(".post-article").remove();
},
I'm using AJAX to request client names from my DB using autocomplete() inside an input #descricao. It requests a route that I created inside Symfony 4 (/acao).
The problem is that I'm trying to set a parameter (/acao?parametro=clientname) but I'm get an error:
Could not resolve argument $parametro of
"App\Controller\DefaultController::filter()", maybe you forgot to
register the controller as a service or missed tagging it with the
"controller.service_arguments"?
I tried to change my routes.yaml:
acao:
path: /acao
controller: App\Controller\DefaultController::filter
methods: GET
but it didn't work.
script.js:
$( "#descricao" ).autocomplete({
source: function( parametro, response ) {
$.ajax({
url: '/acao',
dataType: "json",
data: {
parametro: $('#descricao').val()
},
success: function(data) {
response(data);
}
});
}
});
DefaultController:
/**
* #param string $parametro
* #return JsonResponse
* #Route("/acao", name="acao", methods="GET")
*/
public function filter(string $parametro){
$em = $this->getDoctrine()->getManager()->getRepository(Clients::class)
->createQueryBuilder('c')
->andWhere('c.name_fantasy ilike :parametro')
->setParameter('parametro','%'.$parametro.'%')
->getQuery()
->getArrayResult();
return new JsonResponse($em);
}
What am I doing wrong?
ANSWER:
I managed to make it work using POST and changing table name c.name_fantasy to values:
Controller:
/**
* #param Request $request
* #return JsonResponse
* #Route("/acao", name="acao", methods="POST")
*/
public function filter(Request $request){
$q = strtoupper(trim($request->request->get('parametro')));
$em = $this->getDoctrine()->getManager()->getRepository(Clients::class)
->createQueryBuilder('c')->select('c.name_fantasy AS value')
->andWhere('c.name_fantasy like :parametro')
->setParameter('parametro', '%'.$q.'%')
->getQuery()
->getArrayResult();
return new JsonResponse($em);
}
AJAX:
$( "#descricao" ).autocomplete({
source: function( parametro, response ) {
$.ajax({
url: '/acao',
dataType: 'json',
method: 'POST',
data: {
parametro: $('#descricao').val()
},
success: function(data) {
if (data.length > 0) {
response(data);
}
else {
data = '';
response(data)
}
},
});
}
});
Firstly, you dont need use routes.yaml for routing, if you use the Route Component:
Symfony\Component\Routing\Annotation\Route
So just delete that stuff from routes.yaml.
EDITED:
/**
* #param Request $request
* #return JsonResponse
* #Route("/acao", name="acao", methods="GET", options={"expose"=true})
*/
public function filter(Request $request)
{
//you should strip and trim the parameter, like (just basic):
$clientName = strip_tags(
trim($request->query->get('parametro'))
);
// ...
}
Where Request is Symfony\Component\HttpFoundation\Request <-- you need add to the use statements!
If this not working for you, with your original ajax (what in your question), try on this way:
// ...
let formData = new FormData();
formData.append("parametro", $('#descricao').val());
$.ajax({
url: '/acao',
// ...
data : formData,
// ...
JUST A TIP:
I recommend, use the symfony/bundles/FOSJsRoutingBundle. You can link your routes in js like this:
import Routing from '../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router';
import Routes from '../../public/assets/js/fos_js_routes.json';
Routing.setRoutingData(Routes);
// ...
$.ajax({
//acao is your route name and you route in this case:
url: Routing.generate("acao"),
Dump the latest added routes, with this command:
php bin/console fos:js-routing:dump --format=json --target=public/assets/js/fos_js_routes.json
...
There is my form:
$form = ActiveForm::begin([
'id' => 'user-create-form',
'enableAjaxValidation' => true,
'enableClientValidation' => false,
'validationUrl' => Url::toRoute(Yii::$app->controller->id . '/validation'),
'validateOnType' => true,
]);
JS-script is registered on this form and performed Russian to English transliteration according to some rules on .keyup() event. Transliteration result is added to samname field.
There is validation rule in UserCreateForm model:
public function rules()
{
return [
[['samname'], 'validateUserExist'],
];
}
public function validateUserExist()
{
$check = Yii::$app->CustomComponents->checkUserExist($this->samname);
if ($check) {
$errorMessage = 'User exists: ' . $check;
$this->addError('samname', $errorMessage);
}
}
Function checkUserExist() checks existing of created name and returns an error in matching case.
There is action on controller:
public function actionValidation()
{
$model = new UserCreateForm();
if (\Yii::$app->request->isAjax && $model->load(\Yii::$app->request->post())) {
\Yii::$app->response->format = Response::FORMAT_JSON;
echo json_encode(ActiveForm::validate($model));
\Yii::$app->end();
}
}
It works great, validation is performed, matching case returns an error...
But!
It's required that JS-script is run again and added next letter to the name on error (JS-script provides this functionality). How to run JS-script again after validator was return an error?
#yafater Thanks for help! I find solution.
$('form').on('afterValidateAttribute', function (event, attribute, message) {
if (attribute.name === 'samname')
{
$.ajax({
url: "url-to-action",
type: "POST",
dataType: "json",
data: $(this).serialize(),
success: function(response) {
if ( typeof(response["form-samname"]) != "undefined" && response["form-samname"] !== null ) {
// code here
}
},
});
return false;
}
});
I often use the patchEntity function to hydrate my entity with form data, and it works fine, even with an ajax request.
But when I tried to insert data from an an ajax request with JSON data, patchEntity failed to retrieve the data.
My ajax request is very simple:
var rate = function (user, rate, success, error) {
$.ajax({
type: "POST",
url: baseUrl + 'rate/add',
data: {
id: this.id,
user: user.id
rate: rate
},
dataType: 'json',
success: success,
error: error
});
});
In my Rate controller, my add function looks like:
public function add()
{
if ($this->request->isAjax()) {
$this->layout = 'ajax';
$rate = $this->Rate->newEntity();
if ($this->request->is('post')) {
$rate = $this->Rate->patchEntity($rate, $this->request->data);
if ($rate->errors()) {
$this->set([
'status' => 500,
'message' => $rate->errors()
]);
} else {
if ($this->rate->save($rate)) {
$this->set([
'status' => 200
]);
} else {
$this->set([
'status' => 500,
'message' => $rate->errors()
]);
}
}
return $this->render('/Ajax/result');
}
}
This throw an exception:
Cannot insert row, some of the primary key values are missing. Got (,
, ), expecting (id, user)
I can save my data using this instead of $this->Rate->patchEntity($rate, $this->request->data);
$rate['id'] = $this->request->data['id'];
$rate['user'] = $this->request->data['user'];
$rate['rate'] = $this->request->data['rate'];
What sort of array do I have to pass to patchEntity function to makes this works?
Thanks to ndm's comment, I've checked the Rate Entity and just removed this part which was automatically generated by bake:
protected $_accessible = [
'rate' => true,
];