(symfony2) how to persist an entity using ajax - javascript

i'm coding a simple forum, and i want that the user add the message without refreshing the page, i dont know about ajax , i tried to make things work but when i click on the submit button nothing happens, any help please ??
here is my cotroller :
$request = $this->get('request');
$entityManager = $this->getDoctrine()->getManager();
$msga = new Msg();
$form = $this->get('form.factory')->create(new MsgType());
$form->handleRequest($request);
if ($form->isValid())
{
if($request->isXmlHttpRequest())
{
$msga->setContenu($form->get('contenu')->getData());
$msga->setDateEcriture($date);
$msga->setNbvote(0);
$msga->setUser($user);
$msga->setForum($forum);
$entityManager->persist($msga);
$entityManager->flush();
return $this->render('otaotaBundle:Forum:forum.html.twig', array(
'forum'=>$forum,
'msg'=>$msg,
'msgUF' =>$msgByUser,
'id' => $forum->getIdForum(),
'form' => $form->createView(),
'action' => "add",
));
}
}
and the view:
{% extends "::base.html.twig" %}
{% block body %}
<form action="{{path("show_forum", {id: id} )}}" method="post" novalidate>
Date de création :
<h7>{{forum.datedebforum|date("Y-m-d")}}</h7><br/><br/>
{{forum.description}}<br/><br/><br/>
<table>
{% for m in msg %}
<tr>
<td>
{{m.dateEcriture|date("Y-m-d")}}<br/>
{{m.nbVote}}
{{m.contenu}}
<br/><br/>
</td>
<td>
{% for ms in msgUF %}
{%if ms.idMsg == m.idMsg %}
<a class="link" href="{{ path('delete_msg',{id: ms.idMsg}) }}">supprimer</a>
{% endif %}
{% endfor %}
</td>
</tr>
{% endfor %}
</table>
<br/>
{% if is_granted('IS_AUTHENTICATED_REMEMBERED') %}
{{ form_widget(form._token) }}
<textarea name="textarea" id="contenu"></textarea>
<input type="submit" value="Repondre" />
<script>
$(document).ready(function() {
$('form').submit(function(event) {
// prevents the browser from "following" the link
event.preventDefault();
var $url = $("form").attr("action");// + '.json';
var $value = $('#contenu').val();
$.ajax({
type: "POST",
url: $url,
data: $value
});
});
});
</script>
{% endif %}
</form>
{%endblock%}
i want that the message shows up after the submitting without refreshing

Related

Django/ Javascript : Custom the visual of adropdown menu a form.ChoiceFiled

I have an app with a form that is split in several steps with FormWizard.Some fields are multichoice fields with thousands of choices. I want to improve the presentation of the dropdown menu. I would like to replace it by a kind of fixed list with a scrollbar, like that few data is always displayed and the user sees it wihout clicking on the dropdown to show it.
However I do not know how to do that, if it is with Javascript or CSS. I create the form wiht django and I call it.
Anyone can help me or show me an example ?
forms.py
class ClientForm1(forms.Form):
client = forms.ChoiceField(label="Client :")
def __init__(self, uuid_contrat, *args, **kwargs) :
super(ClientForm1, self).__init__(*args, **kwargs)
id_contrat = Entity.objects.all().filter(uuid=uuid_contrat).values_list('id', flat=True)[0]
client_choices = Toriiclients.objects.filter(idcustomer=id_contrat).order_by('-id').values_list('id', 'prenom')
self.fields['client'].choices = client_choices
class SaletypeForm2(forms.Form):
saletype = forms.ChoiceField(label="Client :")
information =forms.CharField(max_length=1000)
def __init__(self, uuid_contrat, *args, **kwargs) :
super(SaletypeForm2, self).__init__(*args, **kwargs)
id_contrat = Entity.objects.all().filter(uuid=uuid_contrat).values_list('id', flat=True)[0]
client_choices = ToriiLstAffairetype.objects.filter(idcustomer=id_contrat).order_by('-id').values_list('short_desc', 'short_desc')
self.fields['saletype'].choices = client_choices
views.py
from django.shortcuts import render
from .forms import ClientForm1, SaletypeForm2
from formtools.wizard.views import SessionWizardView
class FormWizardView(SessionWizardView):
template_name = "sales/formwiz.html"
form_list = [ClientForm1, SaletypeForm2]
def get_context_data(self, form, **kwargs):
context = super(FormWizardView, self).get_context_data(form, **kwargs)
uuid_contrat = self.kwargs['uuid_contrat']
id_contrat = Entity.objects.all().filter(uuid=uuid_contrat).values_list('id', flat=True)[0]
context['last_clients_created'] = Toriiclients.objects.filter(idcustomer=id_contrat).order_by('-id')[:10]
return context
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
def get_form_kwargs(self, step,) :
uuid_contrat = self.kwargs['uuid_contrat']
kwargs = super(FormWizardView, self).get_form_kwargs(step)
kwargs["uuid_contrat"] = uuid_contrat
return kwargs
html
{% extends "layout.html" %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block head %}
{{ wizard.form.media }}
{% endblock %}
{% block content %}
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
{% if wizard.steps.step1 == 1 %}
{% endif %}
<form action="" method="post">{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
</table>
{% if wizard.steps.prev %}
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button>
<button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button>
{% endif %}
<input type="submit" value="{% trans "submit" %}"/>
</form>

How to use same JavaScript function in multiples Dropdownlists

I have multiple dropdown list added dynamically, and they get their own id, I have a function where I call OnChange event to pass some value based on selected in Dropdown list, but at the moment i am just doing this with the first select.
JS:
$("#id_detallepedido_set-0-producto").change(function () {
producto_id = $(this).val();
var url = '/control/price/'+producto_id;
$.ajax({
type: "GET",
url: url,
data: {
'producto': producto_id
},
success: function (data) {
console.log('Funciono!');
console.log(data);
$("#id_detallepedido_set-0-precio").val(data);
},
error: function(data) {
alert('error' + data);
//console.log(data);
}
});
});
"id_detallepedido_set-0-producto" is the id for the first Dropdownlist, and "id_detallepedido_set-0-precio" is the id for the field I pass the value based on selected value, there is anyway to use this function in every dropdown list added dynamically?
And I'm adding those dropdown list with Django Form here:
Html:
<table class="table" id="tPedidos">
{{ detalle.management_form }}
{% for form in detalle.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="formset_row-{{ formset.prefix }}">
{% for field in form.visible_fields %}
<td>
{# Include the hidden fields in the form #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Instead of handling dropdown change event using id, you can handle it using class. so it will execute for all dropdown.
But as you said your dropdown is added dynamically, you need to create click event globally.
let say you have 3 dropdown, then just add class = "mydropdownclass". and add class = "mytextfield" to your text control.
<table>
<tr>
<td>
<select id="t1" class="mydropdownclass">
<option value="1">101</option>
<option value="2">102</option>
</select>
</td>
<td>
<input type="text" class="test" />
</td>
<td>
<input type="text" class="mytextfield" />
</td>
</tr>
<tr>
<td>
<select id="t2" class="mydropdownclass">
<option value="1">101</option>
<option value="2">102</option>
</select>
</td>
<td>
<input type="text" class="test" />
</td>
<td>
<input type="text" class="mytextfield" />
</td>
</tr>
</table>
<script>
$(document).on("change", ".mydropdownclass" , function() {
producto_id = $(this).val();
var controlId = $(this).attr('id');
//Updat textbox value
$(this).closest("tr").find('.mytextfield').val($(this).val());
var url = '/control/price/'+producto_id;
$.ajax({
type: "GET",
url: url,
data: {
'producto': producto_id
},
success: function (data) {
console.log('Funciono!');
console.log(data);
$("#"+controlId).val(data);
},
error: function(data) {
alert('error' + data);
//console.log(data);
}
});
});
</script>
you can check updated code [link]
https://jsfiddle.net/hubs3m0n/
If elements are added dynamically you can attach an event to document like this.
$(document).on('change', '[write common selector here]', function callback() {})
make a static class which will be same for every element and do in that way
$(".commonClass").change(function () {
producto_id = $(this).val();
var url = '/control/price/'+producto_id;
$.ajax({
type: "GET",
url: url,
data: {
'producto': producto_id
},
success: function (data) {
console.log('Funciono!');
console.log(data);
$("#id_detallepedido_set-0-precio").val(data);
},
error: function(data) {
alert('error' + data);
//console.log(data);
}
});
});

Javascript does not work in the second page of a data table

Actually I'm working with the following datatable:
Data Table code:
<table aria-describedby="dataTable_info" cellspacing="0" class="table table-hover dataTable" id="dataTable" role="grid" style="width:100%;" width="100%">
<thead>
<tr>
<th>{{'fsaGeneralPlan.table.Auditors'|trans({}, 'FSABundle')}}</th>
<th>{{'fsaGeneralPlan.table.Audits'|trans({}, 'FSABundle')}}</th>
<th>{{'fsaGeneralPlan.table.Areas'|trans({}, 'FSABundle')}}</th>
</tr>
</thead>
<tbody>
{% for audit in auditsByArea %}
{% set myArray = audit.Audits|split(',') %}
{% set AuditsStatus = audit.AuditsStatus|split(',') %}
<tr>
<td>{{ audit.Auditor }}</td>
<td>
{# {% set long = numberOfAudits|length + 2 %} #}
{# <h1>{{ long }}</h1> #}
{% for i in 0..3 %}
{% set e = i + 1 %}
<a title="{{ AuditsStatus[i] }}" class="btn btn-outline-primary btn-sm auditButton {{ AuditsStatus[i] }}" data-id="Audit{{ myArray[i] }}" data-area="{{ audit.area_name }}" data-status="{{ AuditsStatus[i] }}" id="auditButton{{ myArray[i] }}" name="auditButton">{{'w' ~ e }}</a>
{# <input class ="auditButton {{ AuditsStatus[i] }} mx-2" value="{{'W' ~ i }}" href="" data-id="Audit{{ myArray[i] }}" data-area="{{ audit.area_name }}" data-status="{{ AuditsStatus[i] }}" id="auditButton{{ myArray[i] }}" name="auditButton" type='text' readonly ></input> #}
{% endfor %}
</td>
<td>{{ audit.area_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
And I have this Javascript to change the class of the buttons in the datatable once that the page is loaded:
<script type="text/javascript">
$(document).ready(function(){
$(".auditButton.Submitted").removeClass('btn-outline-primary');
$(".auditButton.Submitted").addClass('btn-outline-success');
$(".auditButton.Expired").addClass('btn-outline-danger');
$(".auditButton.Capturable").addClass('btn-outline-warning');
});
It works correctly but just in the first page of the datatable, it does not work in the other pages.
Any idea or subject of how to fix it or what is wrong?
You need to listen to the draw event for your table.
Why?
Your current setup works fine for the first page, because those elements are all rendered when $(document).ready() fires. However, the other pages are rendered after the document is ready.
Try:
const table = $('#dataTable').DataTable();
// Event listener for DT 1.10+
table.on('draw', function() {
$(".auditButton.Submitted").removeClass('btn-outline-primary');
$(".auditButton.Submitted").addClass('btn-outline-success');
$(".auditButton.Expired").addClass('btn-outline-danger');
$(".auditButton.Capturable").addClass('btn-outline-warning');
});
Doing this, you can also remove the same block of code from `$(document).
You can also place all this inside the draw callback for your datatable if you'd prefer:
const table = $('#dataTable').DataTable({
drawCallback: function(settings) {
// changes in here
}
});

jQuery datetimepicker- unable to select date from next year

I am working on a Python/ Django project, and one of the forms on a webpage has a datetimepicker field on which the user can select a date/ time from the drop-down that appears when the field is selected.
The problem that I currently have is that although the calendar displays a full month at a time, and the user can move through months/ years at a time by selecting next/ previous month, or choosing the year from a drop down inside the calendar, if they move to a month beyond the end of this year, then none of the dates are available for selection.
Having Google'd datetimepicker, it seems that this is a jQuery function, and I want to make sure that there is no value for its maxDate attribute- I've looked through jquery.datetimepicker.full.js, and although it's referenced there, it doesn't see to be given a value at all... so I can't see why this field is not allowing me to select a date beyond the end of this year... anyone have any ideas?
The view that is rendering this page is:
def concept(request, project_id):
project = Project.objects.prefetch_related('budget_versions').get(id=project_id)
deposit = Deposit.objects.get_or_create(project=project)[0]
presentations = project.budget_versions.select_related('meeting').prefetch_related('budget_items', 'cci_items', 'presenters').filter(version_number__isnull=False).annotate(vn=F('version_number') * -1).order_by('presentation_date', 'created', '-vn')
end_details = EndDetails.objects.get_or_create(project=project)[0]
presentation_formset = BudgetPresentationFormset(prefix="presentations", instance=project, queryset=presentations)
drawing_formset = DrawingUploadFormset(prefix="drawings", queryset=Drawing.objects.filter(budget__in=presentations).order_by('budget__presentation_date', 'budget__created'))
context = {
'project': project,
'presentations': presentations,
'presentation_formset': presentation_formset,
'drawing_formset': drawing_formset,
'deposit_form': DepositInfoForm(instance=deposit),
'ended_form': EndDetailsForm(instance=end_details),
'budget_notes_form': BudgetNotesForm(instance=project.budget_overview),
}
return render(request, 'projects/concept.html', context)
and the Django that is displaying the form on which the 'date' field is displayed is:
{% if not forloop.last and presentation_form.instance.budget_items.count %}
<tr class="split-rows">
<td colspan="3">Exc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_exc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_exc_vat|money:'£'}}{% endif %}</td>
<td colspan="3">Inc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_inc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_inc_vat|money:'£'}}{% endif %}</td>
</tr>
{% endif %}
<tr>
{% for hidden in presentation_form.hidden_fields %}
<td class="hidden">{{ hidden }}</td>
{% endfor %}
</tr>
{% for field in presentation_form.visible_fields %}
<tr class="split-rows">
{% if not field.name == 'pdf_package_dep' %}
<td colspan="6"><label>{{field.label}}</label></td>
{% endif %}
</tr>
<tr class="split-rows">
<td colspan="6">
{% if not field.name == 'pdf_package_dep' %}
{% if field.name == 'presentation_date' %}
{% with presentation_form.instance.meeting as meeting %}
{% include "projects/includes/meeting_bit.html" with employee=request.user.employee meeting=meeting UID=presentation_form.instance.id %}
{% endwith %}
{# <a class="ical_trigger button" data-view-url="{% url 'events:add_to_cal' %}" {% if not field.value %}style="display:none"{% endif %}>Add to calendar</a> #}
{% else %}
{{field}}
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
Edit
It would appear that what's actually displaying the calendar is the HTML file included by the line:
{% include "projects/includes/meeting_bit.html" with employee=request.user.employee meeting=meeting UID=presentation_form.instance.id %}
The meeting_bit.html file has the following code:
{% if meeting and meeting.event_creator and meeting.event_creator != employee %}
<table>
<tr>
<td>
{{meeting.date|date:"d/m/Y H:i"}}<br>
</td>
<td rowspan="2"><a class="change_event_organiser" data-view-url="{% url 'events:change_event_creator' meeting.id %}" class="button">Edit</a></td>
</tr>
<tr>
<td class="text-sm">
Organised by {{meeting.event_creator}}
</td>
</tr>
</table>
{% else %}
<div id="cal_{{field.name}}_{{UID}}">
{{field}}
<a class="ical_trigger button" data-view-url="{% url 'events:add_to_cal' %}" {% if not field.value %}style="display:none"{% endif %}>
{% if meeting.event_id %}Update calendar event{% else %}Add to calendar{% endif %}
</a>
</div>
{% endif %}
I can see when I 'inspect' the date field of the form in the browser, that it is in a div which has an ID in the format cal_{{field.name}}_{{UID}}, so I know that this is where the calendar is initialised/ displayed... But I can't see anything that is restricting the available options for selection to dates from this year only... why can't I select a date from next year, or any other year in the future?

Jquery datatable First load as html then paginate through ajax

I am working on an already written code base. I have to implement ajax pagination to a table. Right now we are using jquery datatable. When the page is opened they content is loaded as html thought jinja templating.
<table id="dataGrid" class="display">
<thead>
<tr>
{% if app_ctx.sub_nav == 'mine' or app_ctx.category == 'members' %}
<th class="no_sort mid"><input type="checkbox" value="" name="" id="dataGrid_check_all" /></th>
{% endif %}
{% if app_ctx.root == 'lab' %}
<th></th>
{% endif %}
<th>Access</th>
{% for field_title in field_titles() %}
<th>{{field_title}}</th>
{% endfor %}
</tr>
</thead>
<tfoot>
<tr>
{% if app_ctx.sub_nav == 'mine' or app_ctx.category == 'members' %}
<th></th>
{% endif %}
{% if app_ctx.root == 'lab' %}
<th></th>
{% endif %}
<th>Access</th>
{% for field_title in field_titles() %}
<th>{{field_title}}</th>
{% endfor %}
</tr>
</tfoot>
<tbody>
{% for item in items %}
<tr>
{% if app_ctx.sub_nav == 'mine' or app_ctx.category == 'members' %}
<td><input type="checkbox" class="item-ids" value="{{ item.id }}" /></td>
{% endif %}
{% if app_ctx.root == 'lab' %}
<td><a target="_blank" href="{{ '%s/%s' % ( app_ctx.url_for('details'), item.id) }}">More...</a></td>
{% endif %}
<td>{% if app_ctx.sub_nav != 'mine' %}<input name="item_ids" type=hidden value="{{ item.id }}">{% endif %}
<div style="width: 65px; display: block; overflow: auto;">{{ acl_display(item) }}</div></td>
{% for field_value in field_values(app_ctx, item) %}
{{field_value|safe}}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
What i need to do is, I just want to load first ten records as html and then load rest of the pages through Ajax request. Please tell how can this be achieved.
current js code
var table = $("{{ selector }}");
var dataTableInitOptions = {
"sPaginationType": "full_numbers",
"bJQueryUI": true,
"aaSorting": {% if app_ctx and app_ctx.category == 'files' and app_ctx.sub_nav == 'mine' %}[[ 7, "desc" ]]{% else %}[[ 1, "desc" ]]{% endif %},
"oLanguage":{
"sSearch":"Search all columns:"
},
"bStateSave": true {# save search and sorting state in cookies #}
};
{% if init_options %}
var additionalOptions = ({{ init_options|safe }});
for (var i in additionalOptions) {
dataTableInitOptions[i] = additionalOptions[i];
}
{% endif %}
if (table.width() > 900) {
dataTableInitOptions.sScrollX = 920;
dataTableInitOptions.bScrollCollapse = true;
//dataTableInitOptions.sScrollXInner = table.width();
}
dataTableInitOptions.fnInitComplete = function() {
{% if filters and filters_placed_in_table %}{{ filters.render_filters_js() }}{% endif %}
{# sort by Uploaded #}
{% if app_ctx and app_ctx.category == 'files' %}
{% if app_ctx.sub_nav == 'mine' %}
this.fnSort( [[7,'desc']] );
{% else %}
this.fnSort( [[6,'desc']] );
{% endif %}
{% endif %}
//move footer column filters to the top
if ($('.dataTables_scroll').length) {
var scrollParts = $('.dataTables_scroll').children();
var footer = scrollParts[2],
body = scrollParts[1];
scrollParts[1] = footer;
scrollParts[2] = body;
$('.dataTables_scroll').append(scrollParts);
} else {
//no scroll
//append empty row to the header and move footer in place of that row
$(this).css({position:'relative'});
var footer = $('tfoot tr', $(this)).children(),
colNum = footer.length,
header = $('thead tr:first', $(this)).children();
var widths = header.map(function(){return $(this).width()});
$('tfoot', $(this)).css({'position':'absolute', 'top': $('thead', $(this)).height() + 'px', 'left':'0', 'right':'0'});
$('thead', $(this)).append($('<tr></tr>').css({'height':$('tfoot', $(this)).height() + 12 + 'px'}));
footer.each(function(i, el) { $(el).width(widths[i] + 2) });
}
};
$("{{ selector }}").dataTable(dataTableInitOptions).columnFilter();

Categories

Resources