I am trying to put a generic form submit function.
For some reason the form submit action is not being captured at all by jQuery.
I am using the following:
$('form').submit(function( event ) {
alert("Form submit through ajax");
event.preventDefault();
});
I never get the alert and the form goes for a normal post submission which invariably fails as the back-end is a python django class based view that is specifically handling the ajax requests. I am new to jQuery.
$(document).ready(function(){
$.ajaxSetup(
{type:'POST'});
$('.nav_menu').click(function(){
var hostname = window.location.origin;
alert("hostname = " + hostname + $(this).attr("id"));
$.ajax({
type: 'GET',
url: hostname + $(this).attr("id"),
data: {},
success: function(data){
var page = data['page'];
$('#view_area').empty();
$('#view_area').append(page);
}
});
});
/*$('form').submit(function(){
alert("Form submit in ajax");
//$(this).ajaxSubmit();
return false;
});*/
$('form').submit(function( event ) {
event.preventDefault(); // <-- important
alert("Form submit through ajax");
/*$(this).ajaxSubmit({
target: '#output'
});*/
});
$(':submit').click(function(){
alert(":submit = Form submit through AJax");
});
});
That is the full jQuery file.
The following is my html from where the form is present.
<table>
<thead>
<tr>
<th></th>
<th>ID</th>
<th>Name</th>
<th>D.O.B</th>
<th>Marital Status</th>
<th>Mobile</th>
<th>Alt Mobile</th>
<th>Alt Contact</th>
<th>Office Number</th>
<th>Primary Address</th>
<th>Permanent Address</th>
<th>Secondary Address</th>
</tr>
</thead>
<tbody>
{% for e in entry_all %}
<tr><th><form action="" method="post">{% csrf_token %}
<label for="id_emp_id"></label> <input id="id_emp_id" maxlength="50" name="emp_id" type="hidden" value="{{ e.emp_id }}" />
<input type="submit" value="Remove">
</form>
</th>
<th>{{ e.emp_id }}</th>
<td>{{ e.name }}</td>
<td>{{ e.dob }}</td>
<td>{{ e.marital_stat }}</td>
<td>{{ e.cell_no }}</td>
<td>{{ e.cell2_no }}</td>
<td>{{ e.alt_no }}</td>
<td>{{ e.off_ll }}</td>
<td>{{ e.prim_addr }}</td>
<td>{{ e.perm_addr }}</td>
<td>{{ e.sec_addr }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<hr/>
I was originally using a cdn to load a jquery. For some reason this is not working all the time for me. So I decided to serve it statically. Strangely, cdn links have no issue on my team mates system. No code change.
EDITED
Code below should work as expected.
In jQuery, there's a preventDefault method which you can call to prevent the default action of an event. For forms, the default action is to either "GET" or "POST" data to or from the script or page provided in the form's action parameter.
If you want to prevent the default action of your form (stop it from submitting and following the action url), you need to call preventDefault first and foremost somewhere in your handler code.
Here's an example:
$("#myform").on("submit", function(e) {
e.preventDefault();
alert("Now I can run...");
// do AJAX call
$.ajax({
type : "POST",
url : "your-script.py",
data : { foo : "bar" }
})
.done(function(results) {
// done with post
// parse data returned from Python
// available in results parameter
});
});
If your handler is not running at all, you're likely not referencing your form correctly.
Related
Sorry to bother, I'm having a trouble passing and ID to my AJAX function.
I wanted to pass the ID of the selected table row to my AJAX function and use it for my query in my controller
this is the code for my table row
<div class="container">
<h2 style="margin-top: 12px;" class="alert alert-success">Details</h2><br>
<div class="row">
<div class="col-12">
<table class="table table-bordered" id="">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Email</th>
<td colspan="2">Action</td>
</tr>
</thead>
<tbody id="users-crud">
#foreach($merchants as $merchant)
<tr id="user_id_{{ $merchant->id }}">
<td>{{ $merchant->id}}</td>
<td>{{ $merchant->first_name }}</td>
<td>{{ $merchant->email }}</td>
<td><a id="getData" onClick="getData({{$merchant->id}})" class="btn btn-info">Show</a>
</td>
</tr>
#endforeach
</tbody>
</table>
{{ $merchants->links() }}
</div>
</div>
</div>
upon click show ID should pass it to my AJAX function,
this is the code of the script
<script type=text/javascript>
$(document).ready(function() {
});
function getData(id){
$('#myModal').modal('show');
$.ajax({ //create an ajax request to display.php
type: "GET",
url: "getproducts/",
// dataType: 'json',
data: {id: id}, // This will be {id: "1234"}
success: function (data) {
$("#id").html(data.id);
$("#first_name").text(data.first_name);
}
});
};
</script>
And ID will be use for my query in my controller, this is my controller's code, note that the number 1 in my where query is hard coded, I wanted to put the ID that I get from the selected table
public function getproducts()
{
$merchants = DB::table('merchants')
->select('merchants.*', 'product.product_name as product_names')
->join('product','product.id','=','merchants.id')
// THE NUMBER 1 IS HARD CODED
->where('merchants.id', 1)
->paginate(8);
return response()->json($test, 200);
}
Every method in a Laravel Controller can have arguments "injected" into them, including the Request $request variable. Add this to the top of your Controller after your namespace declaration:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
Then modify your method:
public function getproducts(Request $request) {
...
}
Then, instead of hard-coding the value 1, you pull it from your $request object:
->where('merchants.id', $request->input('id'))
The full documentation can be seen here:
https://laravel.com/docs/9.x/requests#accessing-the-request
Your code seems fine to me. What is the issue you are facing? But you can improve code by bit more.
<td><a id="getData" onClick="getData({{$merchant->id}})" class="btn btn-info">Show</a>
Instead you can use a global class. Also using same HTML id in a class is not good practice.
<td><a class="merchant_info" data-id="{{$merchant->id}}" class="btn btn-info">Show</a>
Now need modification to jQuery code
<script type=text/javascript>
$(document).ready(function() {
$('.merchant_info').click(function(e){
e.preventDefault();
var dataId = $(this).attr("data-id");
// Now do the Ajax Call etc
});
});
</script>
I have flask sending data to html. Now, first time it does that its by render_template('page1.html', data=data) which populates the main table. Now when i click on any row of main table, i want to call flask again by url_for(entrypoint) and then again i will do render_template('page1.html', data=data2) for the 2nd table. But how to differentiate between them? i mean how will html know which data is coming for whom? please advice. I am novice in javascript and html. I am planning to keep the main table and secondary table under different forms. please advice if thats good decision or not.
Inside my html(page1.html), I have written
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
function getId(element) {
var row_index=element.rowIndex;
$.ajax({
url: '/get_details',
data: document.getElementById("table1").rows[row_index].cells[5].innerHTML),
type: 'POST',
success: function(response){
console.log(response);
},
error: function(error){
console.log(error);
}
});
This is the code in html for table1 and table2(table2 not done yet)
<section id="boxes" style="margin-top:-5%; margin-bottom:0%; position:absolute; z-index:1;">
<div class="box" style="margin-left:30px; margin-top:20px; z-index:1;">
<table id="table1">
<tr>
<th>NO</th>
<th> SUBJECT NAME</th>
<th>ASSIGNED TO</th>
<th>CREATED</th>
<th>DISEASES</th>
<th>SUBJECT ID</th>
<th>STATUS</th>
</tr>
{% for row in data %}
<tr onclick="getId(this)">
<td> {{ row[0] }}</td>
<td> {{ row[1] }}</td>
<td> {{ row[2] }}</td>
<td> {{ row[3] }}</td>
<td> {{ row[4] }}</td>
<td> {{ row[5] }}</td>
<td> {{ row[6] }}</td>
</tr>
{% endfor %}
</table>
</div>
<div class="box-two">
</div>
Inside my app.py
here is the flask code for the entry point:
#app.route('/get_details', methods=['POST'])
def get_details_user(patientid):
print(patientid)
This is the code for the entrypoint for the records which populates table1 as of now:
#app.route('/records')
#login_required
def records():
if current_user.priviledge:
data = get_records_by_userid(None)
else:
data = get_records_by_userid(current_user.id)
list_data = []
for row in data:
list_data.append([])
for col, val in row.items():
list_data[-1].append(val)
return render_template('records.html', data=list_data)
I don't see this in my flask code being triggered. Something wrong in my ajax code?? Also, how do I get the data from flask to this same html file for the second table?
Thanks a lot,
Sudip
Update: The error was coming due to ajax function syntax. Went with extra ')' in data in ajax...oops, thats bad
Add this to the JAvascript code:
$.ajax(function() {
headers = {'X-CSRFToken' : $('#csrf_token').val() },
...
});
This is the token the allows AJac to be validated
Essentially, I am trying to do the same thing as the writer of this and this
was trying to do.
Which is to dynamically update the values of an html template in a django template via an ajax call.
Both of them managed to fix their issue, however, I am unable to do so after 1.5 days.
index.html
{% extends 'app/base.html' %}
{%load staticfiles %}
{% block body_block %}
<div class="container" >
{% if elements %}
<table id="_appendHere" class="table table-bordered">
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>User</th>
<th>Date</th>
</tr>
{% for e in elements %}
<tr>
<td>{{e.A}}</td>
<td>{{e.B}}</td>
<td>{{ e.C }}</td>
<td>{{ e.D }}</td>
<td>{{ e.User }}</td>
<td>{{ e.Date }}</td>
</tr>
{% endfor %}
</table>
{% else %}
No data to display! <br/>
{% endif %}
</div>
{% endblock %}
<script>
var append_increment = 0;
setInterval(function() {
$.ajax({
type: "GET",
url: "{% url 'get_more_tables' %}", // URL to your view that serves new info
data: {'append_increment': append_increment}
})
.done(function(response) {
$('#_appendHere').append(response);
append_increment += 10;
});
}, 1000)
</script>
views.py
def index(request):
elements = ElementFile.objects.all().order_by('-upload_date')
context_dict = {'elements':elements}
response = render(request,'app/index.html',context_dict)
return response
def get_more_tables(request):
increment = int(request.GET.get('append_increment'))
increment_to = increment + 10
elements = ElementFile.objects.all().order_by('-upload_date')[increment:increment_to]
return render(request, 'app/get_more_tables.html', {'elements': elements})
get_more_tables.html
{% for e in elements %}
<tr>
<td>{{e.A}}</td>
<td>{{e.B}}</td>
<td>{{ e.C }}</td>
<td>{{ e.D }}</td>
<td>{{ e.User }}</td>
<td>{{ e.Date }}</td>
</tr>
{% endfor %}
urls.py
urlpatterns = [
path('', views.index, name=''),
path('get_more_tables/', views.get_more_tables, name='get_more_tables'),
]
in the javascript part, I tried:
url: "{% url 'get_more_tables' %}", with and without quotes
If I try to access /get_more_tables/
I get the following error:
TypeError at /get_more_tables/
int() argument must be a string, a bytes-like object or a number, not 'NoneType'
So for some reason, I get nothing, the append_increment is the empty dictionary. But why?
I tried altering the code like, but to no avail:
try:
increment = int(request.GET.get('append_increment'))
except:
increment = 0
Expectation: dynamically loading database
Outcome: error or non-dynamic loading (must refresh manually)
Million thanks to everyone who attempts to help with this.
I have a Django project with an Analytic model. This model is a list of analytics. It has a ForeignKeyField and a ManyToMany Field. The end goal is to have the user go to a URL where they can view a list of Analytics in a DataTable, create a new analytic, edit analytics, and delete analytics. Using this tutorial: https://simpleisbetterthancomplex.com/tutorial/2016/11/15/how-to-implement-a-crud-using-ajax-and-json.html, I accomplished all of these objectives in a regular Bootstrap HTML table (i.e. not in a DataTable).
When I attempted to introduce a DataTable to the mix, I discovered that my DataTable was pulling from the HTML/DOM source, so it was not updating unless the page was refreshed. So I then realized that I need to either configure the DataTable to initially pull from HTML/DOM and then pull from AJAX, or I need to initially use Ajax as the source.
It turns out, regular Django does not do a good job of serializing ManyToMany fields, so I opted to use DRF to serialize my Analytic model. This works to a degree: the JSON output looks decent, and the results show up in my DataTable. However, the data is still not updating when an Ajax call is made. In addition, DataTables does not really allow inline buttons for editing/deleting, which is why it was necessary to manually write those buttons into the HTML in the first place.
Question: How do I force a DataTable that is sourcing from HTML/DOM to update its data without refreshing the page when an Ajax CRUD operation is performed?
views.py:
def analytic_list(request):
analytics = Analytic.objects.all().select_related('analyticCategory').prefetch_related('dataSources')
return render(request, 'analytics/analytic_list.html', {'analytics':analytics})
def save_analytic_form(request, form, template_name):
data = dict()
if request.method == 'POST':
if form.is_valid():
form.save()
data['form_is_valid'] = True
analytics = Analytic.objects.all()
data['html_analytic_list'] = render_to_string('analytics/includes/partial_analytic_list.html', {
'analytics': analytics
})
else:
data['form_is_valid'] = False
context = {'form': form}
data['html_form'] = render_to_string(template_name, context, request=request)
return JsonResponse(data)
def analytic_create(request):
if request.method == 'POST':
form = AnalyticForm(request.POST)
else:
form = AnalyticForm()
return save_analytic_form(request, form, 'analytics/includes/partial_analytic_create.html')
def analytic_update(request, pk):
analytic = get_object_or_404(Analytic, pk=pk)
if request.method == 'POST':
form = AnalyticForm(request.POST, instance=analytic)
else:
form = AnalyticForm(instance=analytic)
return save_analytic_form(request, form, 'analytics/includes/partial_analytic_update.html')
def analytic_delete(request, pk):
analytic = get_object_or_404(Analytic, pk=pk)
data = dict()
if request.method == 'POST':
analytic.delete()
data['form_is_valid'] = True # This is just to play along with the existing code
analytics = Analytic.objects.all()
data['html_analytic_list'] = render_to_string('analytics/includes/partial_analytic_list.html', {
'analytics': analytics
})
else:
context = {'analytic': analytic}
data['html_form'] = render_to_string('analytics/includes/partial_analytic_delete.html',
context,
request=request,
)
return JsonResponse(data)
urls.py:
url(r'^dataanalytics/analytics/$', views.analytic_list, name='analytic_list'),
url(r'^dataanalytics/analytics/create/$', views.analytic_create, name='analytic_create'),
url(r'^dataanalytics/analytics/(?P<pk>\d+)/update/$', views.analytic_update, name='analytic_update'),
url(r'^dataanalytics/analytics/(?P<pk>\d+)/delete/$', views.analytic_delete, name='analytic_delete'),
analytic_list.html:
{% block content %}
<!-- BUTTON TO TRIGGER THE ACTION -->
<p>
<button type="button"
class="btn btn-primary js-create-analytic"
data-url="{% url 'analytic_create' %}">
<span class="fa fa-plus"></span>
New analytic
</button>
</p>
<table class="table table-hover table-sm display responsive" width="100%" cellspacing="0" id="analytic-table">
<thead>
<tr>
<th class="all align-top">#</th>
<th class="all align-top">Name</th>
<th class="all align-top">Description</th>
<th class="all align-top">Category</th>
<th class="all align-top">Type</th>
<th class="all align-top">Format</th>
<th class="all align-top">Data Source(s)</th>
<th class="all align-top"></th>
<th class="none">Created By</th>
<th class="none">Created Date</th>
<th class="none">Modified By</th>
<th class="none">Modified Date</th>
</tr>
</thead>
<!-- <tbody>
{% include 'analytics/includes/partial_analytic_list.html' %}
</tbody> -->
</table>
<!-- THE MODAL WE WILL BE USING -->
<div class="modal fade" id="modal-analytic">
<div class="modal-dialog">
<div class="modal-content">
</div>
</div>
{% endblock %}
partial_analytic_list.html:
{% for analytic in analytics %}
<tr>
<td>{{ analytic.id }}</td>
<td>{{ analytic.analytic }}</td>
<td>{{ analytic.analyticDescription }}</td>
<td>{{ analytic.analyticCategory }}</td>
<td>{{ analytic.analyticType }}</td>
<td>{{ analytic.analyticFormat }}</td>
<td>
{% for data_source in analytic.dataSources.all %}
{{ data_source }}
{% endfor %}
</td>
<td>
<button type="button"
class="btn btn-warning btn-sm js-update-analytic"
data-url="{% url 'analytic_update' analytic.id %}">
<span class="fa fa-pencil-alt"></span>
</button>
<button type="button"
class="btn btn-danger btn-sm js-delete-analytic"
data-url="{% url 'analytic_delete' analytic.id %}">
<span class="fa fa-trash-alt"></span>
</button>
</td>
<td>{{ analytic.createdBy }}</td>
<td>{{ analytic.createdDateTime }}</td>
<td>{{ analytic.modifiedBy }}</td>
<td>{{ analytic.modifiedDateTime }}</td>
</tr>
{% empty %}
<tr>
<td colspan="7" class="text-center bg-warning">No analytic</td>
</tr>
{% endfor %}
analytics.js:
$(function () {
/* Functions */
var loadForm = function () {
var btn = $(this);
$.ajax({
url: btn.attr("data-url"),
type: 'get',
dataType: 'json',
beforeSend: function () {
$("#modal-analytic").modal("show");
},
success: function (data) {
$("#modal-analytic .modal-content").html(data.html_form);
}
});
};
var saveForm = function () {
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize(),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#analytic-table tbody").html(data.html_analytic_list);
$("#modal-analytic").modal("hide");
}
else {
$("#modal-analytic .modal-content").html(data.html_form);
}
}
});
return false;
};
/* Binding */
// Create analytic
$(".js-create-analytic").click(loadForm);
$("#modal-analytic").on("submit", ".js-analytic-create-form", saveForm);
// Update analytic
$("#analytic-table").on("click", ".js-update-analytic", loadForm);
$("#modal-analytic").on("submit", ".js-analytic-update-form", saveForm);
// Delete analytic
$("#analytic-table").on("click", ".js-delete-analytic", loadForm);
$("#modal-analytic").on("submit", ".js-analytic-delete-form", saveForm);
var table = $('#analytic-table').DataTable(
{
});
});
I'm going to assume you're talking about JQuery Datatables. You're SO close, just missing a few bits! You need to destroy and reinitialize the table, no need to use .draw(). Do as shown here:
Ajax:
var saveForm = function () {
var form = $(this);
$.ajax({
url: form.attr("action"),
data: form.serialize(),
type: form.attr("method"),
dataType: 'json',
success: function (data) {
if (data.form_is_valid) {
$("#modal-analytic").modal("hide"); //hide it first if you want
$("#analytic-table").DataTable().destroy(); //this will flush DT's cache
$("#analytic-table tbody").html(data.html_analytic_list); // replace the html
$("#analytic-table").DataTable(); // re-initialize the DataTable
}
else {
$("#modal-analytic .modal-content").html(data.html_form);
}
}
});
return false;
};
Nice work and good luck! Late answer, but maybe it will help somebody.
It looks like your table updates are using this:
$("#analytic-table tbody").html(data.html_analytic_list);
You will need to you Datatables APIs to update the Datatables data. Since you are directly updating the HTML Datatables is not aware of the updates. One option is to use something like rows().invalidate() to have Datatables update its data cache after you update with HTML methods.
However a better option is to use rows.add() for multiple rows or row.add() for a single row.
Since it looks like you have tr elements in your data then you can use something like this for one row or multiple rows, respectively:
table.row.add($(data.html_analytic_list)).get(1)).draw();
table.rows.add($(data.html_analytic_list))).draw();
I'm having issues with the xeditable directive. The onbeforesave is not firing, even though the in-place editing works fine on the client side. I can't get any reaction out of either onbeforesave or onaftersave.
I've included angular version 1.5.0 in my project.
I'm setting up the element like this, it's in a table:
<tr ng-repeat="job in jobs">
<td>{{ job._id }}<i ng-click="removeJob(job._id)" class="fa fa-trash-o" aria-hidden="true"></i></td>
<td>{{ job.title }}</td>
<td editable-text="job.description" onbeforesave="alert('hello');">{{ job.description || "empty" }}</td>
</tr>
But I haven't been able to make the alert go off when clicking save.
If you look at the documentation:
One way to submit data on server is to define onbeforesave attribute pointing to some method of scope
The onbeforesave is taking in a scope method, so alert('hello') in this case is trying to call some $scope.alert method that doesn't exist. To make this work try something like
// in your controller
$scope.test = function(data) {
alert(data);
};
// in your template
<tr ng-repeat="job in jobs">
<td>{{ job._id }}<i ng-click="removeJob(job._id)" class="fa fa-trash-o" aria-hidden="true"></i></td>
<td>{{ job.title }}</td>
<td editable-text="job.description" onbeforesave="test($data)">{{ job.description || "empty" }}</td>
</tr>
You have to give e-form as shown below (I just extracted the wrong code snippet only).
Html
<td editable-text="job.description" e-form="tableform"
onbeforesave="checkJob(job)">{{ job.description || "empty" }}</td>
JS
$scope.checkJob= function(data) {
//your logic
};