Symfony and ajax to check each checkbox is checked - php

I'm learning about Ajax and Symfony. Since I made a loop to show all rings from database, I would like to put checkbox on each ring and, want to show only selected ring on the top. So I'm trying to use Ajax so that I don't need to refresh the page. I simply put alert box to check whether it is working before making php controller, but seems it's not working
this is my twig file
'''
{% for ring in rings %}
<div class="row g-0 mb-5">
<div class="text-center ">
<p>Ring Name: {{ ring.ring_name }}</p>
<p>Ring Type: {{ ring.ring_type }}</p>
<p>Ring Shape: {{ ring.ring_shape }}</p>
<p>Ring Size: {{ ring.size }}</p>
<p>Price: {{ ring.price }}</p>
<input type="checkbox" id="select_ring" name="select_ring" value=ring.id >
</div>
<br>
<div class="text-center">
detail
Update Ring
</div>
</div>
{% endfor %}
'''
this is Ajax inside the twig
'''
$('#myCheckbox').click(function() {
var checked = $(this).is(':checked');
$.ajax({
type: "POST",
url: myUrl,
data: { checked : checked },
success: function(data) {
alert('it worked');
},
error: function() {
alert('it broke');
},
complete: function() {
alert('it completed');
}
});
});
'''

What you want to do is just a front end manipulation, you don't need to use ajax for it.
Just define ID to your rings (based on ring id for exemple) and set all your rings as hidden at start.
Then in js/jquery (BTW forget about Jquery, it's lame), just set the selected element visible on click.
Don't forget to put the others element to hidden every time you click on a ring, otherwise the previous rings will stay visible.

Related

Refresh table after request Ajax is success

I am beginner with Ajax. I try refresh a table when user select an option in form-select filter. I use Symfony and Twig.
I get the new datas in the Json format in my console when i select a new filter, but the table does'nt show with the new datas. I failed to find the solution when my request ajax is success.
My Select filter :
{{ form_start(form) }}
<div class="container-fluid">
<div class="row">
<div class="col-fluid">
{{ form_row(form.isAttending) }}
</div>
<button type="submit" class="btn btn-outline-success mb-2">{{ button_label|default('Envoyer') }}</button>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-1-fluid">
{{ form_row(form.active) }}
</div>
</div>
</div>
{{ form_end(form) }}
In my Controller :
/**
* #Route("/ajax", methods={"GET", "POST"})
*/
public function testAjax(Request $request)
{
if (!$request->isXmlHttpRequest()) {
return new JsonResponse(array(
'status' => 'Error',
'message' => 'Error'),
400);
}
if($request->request->has('isAttending')) {
$preSelect = $request->request->get('isAttending');
return new JsonResponse(
$this->queryFollowingFilter($preSelect),
200);
}
}
In my Template :
<script>
$(document).on('change', '#campagnes_tel_isAttending', function () {
$('#flash').remove();
let $field = $(this)
let $preselect = $('#campagnes_tel_isAttending')
let $form = $field.closest('form')
let data = {}
data['isAttending'] = $field.val()
console.log(data)
$.ajax({
type: "POST",
url: "/campagnestel/ajax",
data: data,
dataType: "json",
success: function(response) {
console.log(response);
}
});
});
</script>
Any ideas ?
According to your question and comments your problem is not Symfony, not Ajax and also not Twig related. You get the correct data and you just do not know how to manipulate the DOM. DOM manipulation is a basic capability of JavaScript.
Here you can learn how to manipulate the DOM: https://www.w3schools.com/js/js_htmldom.asp
And here you can learn how to easily can manipulate it with jQuery which you are obviously using: https://www.w3schools.com/js/js_jquery_dom.asp
Sample:
$('#my-table').append(response.myWhatever);

Laravel ajax passing data to php

I have a special problem.
I am making an Ajax request to get data from the db without updating.
The response I get should be outputted in a advanced way like this:
#foreach ($tasks as $task)
<div class="pr-1">
<div onclick="openComponent('modal-task', {{ $task->id }});setGlobalIndex({{ $task->id }});" title="{{ $task->title }}" class="calendar-task hover:opacity-75 cursor-pointer" style="background-color: #{{ $task->color }};">#{{ $task->id }} {{ ucfirst(substr($task->title, 0, 23)) }}</div>
</div>
<div id="modal-task_{{ $task->id }}" class="hidden">
<div class="display">
<div class="top">
<div class="title">Opgave #{{ $task->id }} <div class="inline-block text-blue-600 underline text-sm">Se hele opgaven</div>
</div>
<div onclick="closeComponent('modal-task', {{ $task->id }})" class="close-button"><i class="fas fa-times-circle text-gray-700"></i>
</div>
</div>
#include('component.task')
</div>
#endforeach
Right now I get the correct response from the Ajax request.
color: "e53e3e"
company_id: 1
created_date: "2020-11-13"
created_time: "00:00:00"
description: null
id: 8
status_1: null
status_2: null
status_3: null
title: "Overskrift"
But how do I output it like that, with the include also and it should appear many times (its a calendar system that gets tasks from each days)
The Ajax request POST 2 dates (from and to) till a laravel controller which returns the tasks that have the date in between.
<script>
var datePeriodRow = "<?php echo $datePeriodRow; ?>";
var _token = $('input[name=_token]').val();
$.ajax({
url: "/task/get",
type:"POST",
data:{
datePeriodRow:datePeriodRow,
_token: _token
},
success:function(response){
if(response) {
console.log(response);
}
},
});
</script>
What you can do in your "/task/get" endpoint method is to return a view that returns a rendered html. then set the rendered response with javascript in a div element instead of that foreach loop.
So place the foreach code part in an include/partial like partial/tasks.blade.php and in your endpoint method:
/** route: /task/get **/
public function yourTasksMethod(){
//your code that retrieves your tasks
return view('partial.tasks')->with('tasks', $tasks)->render();
}
Keep in mind to clear/empty the div before you make another request to the task/get endpoint.

Vue2 Laravel component in list

I am building a Laravel app and trying to use vue.js (without much success!). I'm not understanding the way components work with ajax data. Almost all examples I've found showing this functionality define the data for the component at the app level, not the component level.
I'm trying to dynamically define my data in the component itself, and always get the error that Property or method tasks is not defined on the instance but referenced during render. Here's the component, which is meant to just call out to an endpoint to pull basic "to do" tasks:
Vue.component('tasks', {
data: function() {
return {
tasks: []
}
},
mounted() {
this.getTasks();
},
methods: {
getTasks() {
axios.get('/tasks').then(function (response) {
this.tasks = response.data;
console.dir(this.tasks);
})
.catch(function (error) {
console.log(error);
});
}
},
template: `
<div class="card">
<div class="card-title">{{ task.name }}</div>
<div class="card-body">
<div class="service-desc">{{ task.description }}</div>
<div class="task-notes"><input class="form-control" v-model="task.notes" placeholder="Notes"></div>
<div class="task-active"><input type="checkbox" checked data-toggle="toggle" data-size="sm" v-model="task.active" v-on:click="$emit('disable')"></div>
</div>
</div>
`
});
the component is called from within the blade template using:
<tasks v-for="task in tasks" :key="task.id"></tasks>
tasks is declared in the data function, so I'm not sure why vue is telling me it's not defined?
When you define a data property on a component it's only available within that component and its template. Your v-for directive is in the parent scope (i.e outside of the component where tasks is defined).
The simplest solution here is probably to move the container element inside the component, and iterate over the tasks there:
<div>
<div class="card" v-for="task in tasks" :key="task.id">
<div class="card-title">{{ task.name }}</div>
<div class="card-body">
<div class="service-desc">{{ task.description }}</div>
<div class="task-notes"><input class="form-control" v-model="task.notes" placeholder="Notes"></div>
<div class="task-active"><input type="checkbox" checked data-toggle="toggle" data-size="sm" v-model="task.active" v-on:click="$emit('disable')"></div>
</div>
</div>
</div>
Note: you can't use v-for a template's root element, which is why you'd move the container element into the template.
An alternative is break this into two components (e.g. TaskList and TaskItem) where the parent component is responsible for fetching the tasks from the API. The child component can just receive a single task as a prop and render it to the UI.
TaskList
Vue.component('task-list', {
data: function() {
return {
tasks: []
}
},
mounted() {
this.getTasks();
},
methods: {
getTasks() {
axios.get('/tasks').then(response => {
this.tasks = response.data;
console.dir(this.tasks);
})
.catch(error => {
console.log(error);
});
}
},
template: `
<div class="container">
<task-item
v-for="task in tasks"
:key="task.id"
:task="task"
/>
</div>
`
});
TaskItem
Vue.component('tasks', {
props: {
task: {
required: true
}
},
template: `
<div class="card">
<div class="card-title">{{ task.name }}</div>
<div class="card-body">
<div class="service-desc">{{ task.description }}</div>
<div class="task-notes"><input class="form-control" v-model="task.notes" placeholder="Notes"></div>
<div class="task-active"><input type="checkbox" checked data-toggle="toggle" data-size="sm" v-model="task.active" v-on:click="$emit('disable')"></div>
</div>
</div>
`
});
The advantage of this is that it separates the responsibility of the components a little better. You could add logic to the TaskList component to handle displaying a loading spinner and/or error messages for the API call, while TaskItem only has to concern itself with displaying a single task.

How to pass a variable in JavaScript if in view it's empty?

So, I created a report system, but in the last step, I have a little problem...In JavaScript I'm using a variable from database for Ajax, but when a post has no comments, I'm getting Undefined variable: key.
Here is my script
if (isset($key)){
$('#yourFormIdComment{{$key+1}}').submit(function(e){
e.preventDefault();
var data = $(this).serialize();
$.ajax({
method:'POST',
url:'/career_report_comment',
data:data,
success: function (result) {
// do something with result
}
});
});
}
Here is my view with variable
#foreach($opinionComment as $key => $comments)
<div class="news-v3 bg-color-white">
<h4 style="font-size: 13px">
{{ $comments->user->username }}</h4>
<p>{{ $comments->comments }}</p>
<ul class="post-shares post-shares-lg">
<li #if ($key === 0) class="active" #endif style="float: right;left: 20px;bottom: 30px"><a data-toggle="modal" data-target="#exampleModalComment{{$key+1}}" href="javascript:void(0)" ><i class="rounded-x icon-flag"></i></a></li>
</ul>
</div>
#endforeach
My question is...how can I pass the variable {{$key+1}}from script even if a post has no reviews/comments?Because this is happening only when I have comments on a post.
Andrew i after talking in the comments and checking your code i might have found a solution to your problem.
You get a error:
Undefined variable: key
You get that error because the key isnt defined.
if (isset($key)){
$('#yourFormIdComment{{$key+1}}').submit(function(e){
e.preventDefault();
var data = $(this).serialize();
$.ajax({
method:'POST',
url:'/career_report_comment',
data:data,
success: function (result) {
// do something with result
}
});
});
}
In the first part of your code you use the variable $key, but the key is defined within the foreach in the second part of your code. That's why you get the error.

render a twig template on condition

In my page show.html.twig i have this block
<div class="col-md-9 col-sm-9 user-wrapper">
<div class="description">
{{ render(controller('FLYBookingsBundle:Post:new')) }}
</div>
</div>
As you can see there is a render that render the page new.html.twig, i want to render the page product << {{ render(controller('FLYBookingsBundle:Post:product')) }} >> in the div description only if the user click on the link My Product List . how do i do that with twig ?
Here is the solution I used to "pop-up" a form for sending an e-mail to an entity based on a button appearing with that entity.
You will need to install jquery if not already installed. There are many possible ways to do this. Use your pal Google & "symfony install jquery" to find one. You may also want to find a good javascript debugger for your browser. I use the Firebug add-on in Firefox.
Template with link (edited for brevity). The returned e-mail form appears in <div id="dialog"></div>:
<div id="dialog"></div>
{% for opp in opportunities %}
<div class="row">
<div class="col-md-9">
<ul class="list-unstyled">
...
<li><a href="#" value="{{ opp.id }}" id="emailOrganization" class="btn btn-xs btn-info" >E-mail {{ opp.orgName }}</a>
</ul>
</div>
</div>
{% endfor %}
Javascript:
$(document).on("click", "#emailOrganization", function () {
var where = $(location).attr('pathname');
var id = $(this).attr("value");
//replaces URI ending in 'search' with 'oppForm/' + id (of organization)
var url = where.replace('search', 'oppForm/' + id);
$.get(url, function (data) {
//creates dialog box containing e-mail form
$('#dialog').dialog();
$('#dialog').dialog({
modal: true,
buttons: [
{
text: "Send",
id: "send",
class: "btn-xs btn-primary",
click: function () {
var formData = $("form").serialize();
$.post(url, formData, function (response) {
if (response.indexOf("Email sent") >= 0) {
$("#send").hide();
}
$('#dialog').html(response);
})
}
},
{
text: 'Close',
id: "close",
class: "btn-xs btn-primary",
click: function () {
$(this).dialog("close");
}
}
],
resizable: true,
});
$('#dialog').dialog("widget").find(".ui-dialog-titlebar").hide();
$('#dialog').html(data);
});
});
Controller (edited for brevity)
/**
* #Route("/oppForm/{id}", name="opp_form")
* #Template("default/oppEmail.html.twig")
*/
public function oppFormAction(Request $request, $id)
{
...
$form = $this->createForm(new OpportunityEmailType($oppName, $orgName, $email, $id));
$form->handleRequest($request);
if ($request->getMethod() == 'POST') {
if ($form->isValid()) {
...
}
$response = new Response("Email sent: " . count($to));
return $response;
}
}
return [
'form' => $form->createView(),
'id' => $id,
];
}
Template:
<form role="form" action="{{ path('opp_form', {'id': id}) }}" method="post" name="opp_email">
{# hidden submit button allows functional test; also tested with codeception #}
<div style="visibility: hidden;"><input type="submit" value="Mail"></div>
{{ form_widget(form._token) }}
{{ form_row(form.id) }}
{{ form_row(form.to) }}
{{ form_row(form.from) }}
{{ form_row(form.subject) }}
{{ form_row(form.message) }}
</form>

Categories