jQuery intermittent .on('click') - javascript

I'm building a web app using django and jQuery and on one of the pages the $(document).com('click'... event fires very intermittently. I have a list of items in a checkout queue, and an option to delete each item. If I go from top to the bottom of the list, the click events mostly fire (but not always). If I start from the bottom, sometimes they fire, sometimes not. Some need 2 clicks, some need 6+ clicks before registering.
Onto the code. This is the html django generates from the template:
<div class="container">
<table id="cart" class="table table-hover table-condensed">
<thead>
<tr>
<th style="width:70%">Product</th>
<th style="width:10%" class="text-center">Seller</th>
<th style="width:10%">Price</th>
<th style="width:10%"></th>
</tr>
</thead>
<tbody>
<tr id="product-3653672818">
<td data-th="Product">
<div class="row">
<div class="col-sm-3 hidden-xs"><img src="xyz.com/img.jpg" style="width: 121px; height: 88px;"></div>
<div class="col-sm-9">
<h4 class="nomargin">Product Name</h4>
<p>Product Description</p>
</div>
</div>
</td>
<td data-th="Seller" class="text-center">ONLINE</td>
<td data-th="Price">3.00</td>
<td class="actions" data-th="">
<button class="btn btn-danger btn-sm"><i class="fa fa-trash-o DeleteItem" id="3653672818"></i></button>
</td>
</tr>
<tr id="product-3653492642">
<td data-th="Product">
<div class="row">
<div class="col-sm-3 hidden-xs"><img src="xyz.com/img.jpg" style="width: 121px; height: 88px;"></div>
<div class="col-sm-9">
<h4 class="nomargin">Product #2 Title</h4>
<p>Product #2 Description</p>
</div>
</div>
</td>
<td data-th="Seller" class="text-center">ONLINE</td>
<td data-th="Price">4.00</td>
<td class="actions" data-th="">
<button class="btn btn-danger btn-sm"><i class="fa fa-trash-o DeleteItem" id="3653492642"></i></button>
</td>
</tr>
</div>
And this is my jQuery:
$(document).on('click','.DeleteItem',function(event){
event.preventDefault();
var thisID = $(this).attr("id");
var data = { Action: "delete", itemid: thisID};
var pr = "#product-"+thisID;
$(pr).fadeOut(500, function() { $(pr).remove(); });
$.ajax({
url: "/cart/",
type: "POST",
data: data,
beforeSend: function (xhr, settings) {
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
},
// handle a successful response
success: function (json) {
if (json.result == "OK") {
console.log(json);
console.log("success");
} else {
console.log(json);
console.log("failure");
}
},
// handle a non-successful response
error: function (xhr, errmsg, err) {
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
});

Ok, Just in case anybody else encounters this situation, I eventually worked out what was going on here.
The way I defined the button in the template was the culprit:
<button class="btn btn-danger btn-sm"><i class="fa fa-trash-o DeleteItem" id="3653672818"></i></button>
My jQuery was firing on $(document).on('click','.DeleteItem' which was a class defined in the "i" html element, rather than the main button class. The "fa-trash-o" class is a small trash can icon which only takes up about 1/3 of the button area.
So what would happen is if you clicked smack bang in the middle of the button (directly on the trash can), everything would work. But if you clicked elsewhere on the button, nothing happened. ie. Sometimes it works, sometimes it doesn't.
The fix was to move the "DeleteItem" class definition to the button:
<button class="btn btn-danger btn-sm DeleteItem" id="3653672818"><i class="fa fa-trash-o" ></i></button>

Related

reload page asynchronously after success ajax

i'm trying to add a new entered value to a table after success method runs using ajax , i've used ModelForm . i want to add the new entry to the table body row ! , i've tried alot , but still i cant figure it out ! i most appreciate your helps
class MainGroup(models.Model):
admin = models.ForeignKey(User,on_delete=models.CASCADE)
main_type = models.CharField(max_length=40,unique=True)
date = models.DateTimeField(auto_now_add=True)
my views.py
#login_required
def create_maingroup(request):
lists = MainGroup.objects.all().order_by('-pk')
form = MainGroupForm()
if request.is_ajax() and request.method == 'POST':
form = MainGroupForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.admin = request.user
obj.save()
return JsonResponse({'success':'success'})
else:
return JsonResponse({'sucess':False,'error_msg':form.errors,'error_code':'invalid'})
context = {
'form':form,'lists':lists
}
return render(request,'products/create_maingroup.html',context)
const form = document.getElementById('main_form')
form.addEventListener("submit",submitHandler);
function submitHandler(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '{% url 'products:create-maingroup' %}',
data : $('#main_form').serialize(),
dataType: 'json',
success: successFunction,
});
}
function successFunction(data) {
console.log(data.success=='success')
if (data.success=='success') {
form.reset();
obj = $('#main_form').serialize();
//i have to append new entred values here
//but i dont know how to get inputs and set the admin
//name who created the post !
alertify.success("added")
}
else if(data.error_code=='invalid'){
for(var key in data.error_msg){
if(key == 'main_type'){
document.getElementById('main_error').removeAttribute('hidden')
document.getElementById('main_error').innerHTML = data.error_msg[key][0]
}
}
}
}
my html page
<div class="col-md-12">
<div class="card card-info">
<div class="card-header">
<div class="card-tools">
<button type="button" class="btn btn-tool" data-toggle="collapse" data-target="#main_form" aria-expanded="false" aria-controls="main_form">
<i class="fas fa-minus"></i>
</button>
</div>
<h3 class="text-center">add new data</h3>
</div>
<!-- /.card-header -->
<!-- form start -->
<form id="main_form" role="form" method="POST">{% csrf_token %}
<div class="card-body">
<div class="form-group row">
<label for="mainGroup" class="col-sm-2 control-label">name</label>
<div class="col-sm-10">
{{form.main_type | attr:'id:mainGroup'}}
<p id="main_error" class="alert alert-danger" aria-disabled="true" hidden></p>
</div>
</div>
</div>
<div class="card-footer">
<button type="submit" class="btn btn-success">add</button>
</div>
</form>
</div>
</div>
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="text-center">list of names</h3>
</div>
<div class="card-body table-responsive">
<table id="maingroupid" class="table table-bordered table-striped text-center">
<thead>
<tr>
<th>#</th>
<th>admin</th>
<th>name</th>
<th>date</th>
<th>actions</th>
</tr>
</thead>
<tbody id="tableData">
{% for i in lists %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{i.admin}}</td>
<td>{{i.main_type}}</td>
<td>{{i.date | date:'d-m-Y h:i A'}}</td>
<td align="center">
<button class="btn btn-info bg-info" onclick="editMain({{i.id}})" data-toggle="modal" data-target="#myModal"><i class="far fa-edit"></i></button>
<button class="btn btn-danger bg-danger" onclick="deleteMain({{i.id}})"><i class="far fa-trash"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</tfoot>
</table>
</div>
</div>
</div>
is it possible without refreshing the page and display the new data please ? i need it so much
You could return the new table once edited
context = {} # whatever your context is
return render(request, 'path/to/table/template.html', context=context)
template.html is the table element of your template
<thead>
<tr>
<th>#</th>
<th>admin</th>
<th>name</th>
<th>date</th>
<th>actions</th>
</tr>
</thead>
<tbody id="tableData">
{% for i in lists %}
<tr>
<td>{{forloop.counter}}</td>
<td>{{i.admin}}</td>
<td>{{i.main_type}}</td>
<td>{{i.date | date:'d-m-Y h:i A'}}</td>
<td align="center">
<button class="btn btn-info bg-info" onclick="editMain({{i.id}})" data-toggle="modal" data-target="#myModal"><i class="far fa-edit"></i></button>
<button class="btn btn-danger bg-danger" onclick="deleteMain({{i.id}})"><i class="far fa-trash"></i></button>
</td>
</tr>
{% endfor %}
</tbody>
</tfoot>
Then on success within ajax use
success: function (data, status) {
$('#maingroupid`).html(data);
}

Thymeleaf pass data from html id to thymeleaf variable

I've a problem with below code. I need to pass a variable from html id to thymeleaf variable.
<table class="responsive-table highlight bordered">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Surname</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr th:each="worker: ${workersList}">
<td th:text="${worker.id}"></td>
<td th:text="${worker.name}"></td>
<td th:text="${worker.surname}"></td>
<td th:text="${worker.email}"></td>
<td>
<a href="#deleteModal" class="btn tooltipped modal-trigger" th:attr="data-id=${worker.id}, data-name=${worker.name +' '+ worker.surname}"
data-position="top" data-delay="50" data-tooltip="Delete"><i class="material-icons">delete</i></a>
</td>
</tr>
<!-- Delete Modal -->
<div id="deleteModal" class="modal modal-fixed-footer">
<div class="modal-content">
<p id="modal-name"></p>
<p id="modal-id"></p>
</div>
<div class="modal-footer">
<a th:href="#{'/delete/'+${modal-id} }" class="modal-action modal-close waves-effect waves-red btn-flat">Yes</a>
</div>
</div>
</tbody>
</table>
<script th:inline="javascript">
$('#deleteModal').modal({
ready: function(modal, trigger) {
var button = $(trigger);
var id = button.data('id');
$('#modal-id').html(id);
}
});
</script>
It won't work. I've to pass it using js because this id's are changeable depends on worker I click. This works, but It can't pass an id to th:href Thanks for help!
They way you have it done, you need to use Javascript to update the ID, as your modal is outside the loop. I would do something like this:
<div class="modal-footer">
<a id="idModalLink" href="#" class="modal-action modal-close waves-effect waves-red btn-flat">Yes</a>
</div>
And in your javascript code:
$('#deleteModal').modal({
ready: function(modal, trigger) {
var button = $(trigger);
var id = button.data('id');
$('#modal-id').html(id);
$('#idModalLink').attr("href", "/delete/" + id);
}
});

How to append entry in the same page using angularJS, without using array to store previous entry

This is my html file, that get data from controller. Controller get new data every time from API once i press the load button by increasing the offset value.
<div class="container" ng-app="myApp" ng-controller="myctrl">
<div class="row row-gap" ng-repeat="data in data">
<div class="media-left media-middle">
<a href="#">
<img class="media-object rounded" ng-src="{{data.thumbnail}}">
</a>
</div>
<div class="media-body" >
<table class="table table-striped">
<tr>
<td class="col-md-3"> <span class="glyphicon glyphicon-share-alt" aria-hidden="true">Name</span></td>
<td class="col-md-9">{{data.title}}</td>
</tr>
<tr>
<td class="col-md-3"> <span class="glyphicon glyphicon-map-marker" aria-hidden="true"></span> Place </td>
<td class="col-md-9"> Star{{data.placeName}} </td>
</tr>
<tr>
<td class="col-md-3"> <span class="glyphicon glyphicon-time" aria-hidden="true"></span> Submitted On </td>
<td class="col-md-9">{{data.createdOn |date }}</td>
</tr>
</table>
<img ng-src="{{data.author.icon}}";alt="{{data.author.name}}";height=30px; width=30px >
</div>
</div>
<button type="button" ng-click="loadMore(count=count+1)" class="btn btn-default">load More</button>
</div>
The container code is as follow. I am aware that i am using the same data variable to store the subsequent query result.
I just want that whenever i click on load more button, data get append in the same page without effecting the previous values.
var myApp=angular.module('myApp',[]);
myApp.controller('myctrl',function ($scope, $http) {
$http({
method: 'GET',
url: 'API?max=10&offset=0&format=json'
}).then(function (datacontent){
$scope.data=datacontent.data.model.observationInstanceList;
console.log(show);
},function (error){
//console.log(error);
});
$scope.count=0;
$scope.loadMore=function(value) {
value=value*10;
$http({
method: 'GET',
url: 'http://API?max=10&offset='+value+'&format=json'
}).then(function (dataco){
$scope.data=dataco.data.model.observationInstanceList;
},function (error){
//console.log(error);
});
}
});
I need answer in such a way, the array size doesnot increase much.
Try this, but only works if dataco.data.model.observationInstanceList is an array.
$scope.data = $scope.data.length ? $scope.data.concat(dataco.data.model.observationInstanceList) : dataco.data.model.observationInstanceList;
Change your code as below
$scope.count=0;
$scope.loadMore=function(value) {
value=value*10;
$http({
method: 'GET',
url: 'http://API?max=10&offset='+value+'&format=json'
}).then(function (dataco){
$scope.data = $scope.data.length ? $scope.data.concat(dataco.data.model.observationInstanceList) : dataco.data.model.observationInstanceList;
},function (error){
//console.log(error);
});
}

How do I display a array of objects on a bootstrap media component?

I have a ajax call that take in an array[30] of object with details inside like title etc. What I want to do is display these objects on a media list and each time the user put a new string into a input bar the media list will be updated and will return the reults. below is the html I use to retrieve the data and create a GET request dynamically.
<div class="container">
<div style="background: rgba(60, 255, 60, 0.2);" class="jumbotron">
<h1>Meal Manager</h1>
<p class="lead">A simple recipe app that provides ingerdiants fast.</p>
<div class="input-group">
<input type="text" value="chicken" id="sbar" class="form-control" aria-label="...">
<div class="input-group-btn">
<button type="button" class="btn btn-default" id="button" title="Search Database">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-default btn" title="Sort by reviews" >
<span class="glyphicon glyphicon-star" aria-hidden="true"></span>
</button>
<button type="button" class="btn btn-default btn" title="Sort by trending" >
<span class="glyphicon glyphicon-hand-up" aria-hidden="true"></span>
</button>
</div>
</div>
<table id="location" class="table table-striped">
<tr>
<th>Step</th>
<th><span class="glyphicon glyphicon-cutlery" aria-hidden="true"></span> Ingredients</th>
</tr>
</table>
Now below Is where I will be making the contents of the table then returning them to the html page. The ajax returns the correct data to the callback fucntion but how to I display these on a media component? http://v4-alpha.getbootstrap.com/layout/media-object/
function callback(response) {
// Here you can do what ever you want with the response object.
console.log(response[responseCnt].title);
console.log(response[responseCnt+1].title);
console.log(response[responseCnt+2].title);
console.log(response[responseCnt+3].title);
console.log(response[responseCnt+4].title);
}
$(document).ready(function(){
$("button").click(function(){
var word = document.getElementById("sbar").value;
$.ajax({
url: 'https://community-food2fork.p.mashape.com/search?key=0ee5a01caf7f7c3512b54978628f1a4e&page=4&q=' + word, // The URL to the API. You can get this in the API page of the API you intend to consume
type: 'GET', // The HTTP Method, can be GET POST PUT DELETE etc
data: {}, // Additional parameters here
dataType: 'json',
success: function(data) { search = JSON.parse(JSON.stringify(data.recipes));
callback(search);
},
error: function(err) { alert(err); },
beforeSend: function(xhr) {
xhr.setRequestHeader("X-Mashape-Authorization", "gH609jhjxAmshYY4KnIDmad2zgXGp194YDUjsnHCTiPdd7m2Qg"); // Enter here your Mashape key
}
});
});
});
Now heres what I want to do, I need to fill the html below with the details oh the returned json object inside callback, how to I do this?
<div class="media" id="sresults">
<div class="media-left">
<a href="#">
<img class="media-object" src="..." >
</a>
</div>
<div class="media-body">
<h4 class="media-heading">Media heading</h4>
...
</div>
</div>

Include template in angular-datatables not rendering

I am using angular-datatables plugin to add datatables to my project. In this, I have a column Actions where I want to add some buttons. For this, I am using ng-template which is defined on the same page. The problem is that the template does not always render. It sometimes shows the button, and sometimes it does not. It never shows the buttons after I make a search.
controller
$scope.dtOptions = DTOptionsBuilder.newOptions().withOption('ajax', {
url: '/api/department',
type: 'GET'
})
.withDataProp('data')
.withOption('processing', true)
.withOption('serverSide', true)
.withPaginationType('full_numbers')
.withOption('createdRow', function (row, data, dataIndex) {
// Recompiling so we can bind Angular directive to the DT
$compile(angular.element(row).contents())($scope);
})
.withBootstrap();
$scope.dtColumns = [
DTColumnBuilder.newColumn('id').withTitle('ID'),
DTColumnBuilder.newColumn('name').withTitle('Name'),
DTColumnBuilder.newColumn('actions').withTitle('Actions').withOption("searchable", false)
];
view
<script type="text/ng-template" id="actions.html">
<button class="btn btn-primary btn-xs" ng-click="edit()"><i class="fa fa-edit"></i> Edit</button>
<button class="btn btn-danger btn-xs" ng-click="delete()"><i class="fa fa-trash"></i> Delete</button>
</script>
<div class="hbox hbox-auto-xs hbox-auto-sm" ng-controller="DepartmentsController">
<div class="bg-light lter b-b wrapper-md">
<h1 class="m-n font-thin h3">Departments</h1>
</div>
<div class="wrapper-md">
<div class="panel panel-default">
<div class="panel-body">
<div class="row">
<div class="col-xs-6">
<button class="btn m-b-md btn-md btn-primary " ui-sref="manager.departments.create">
<i class="fa fa-plus"></i> <span class="hidden-sm hidden-xs">Add Department</span></button>
</div>
</div>
<div class="row">
<div class="col-sm-12 m-b-xs">
<table datatable="" dt-options="dtOptions" dt-columns="dtColumns" class="table table-striped b-t b-b">
<thead>
<tr>
<th style="width:20%">ID</th>
<th style="width:60%">Name</th>
<th style="width:20%">Actions</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
controller on server side in Laravel
public function index() {
$departments = Department::company($this->company->id)
->select("departments.id", "departments.name");
return \Datatables::of($departments)
->add_column("actions", function($row) {
return '<div ng-include src="\'actions.html\'"></div>';
})
->make(true);
}
I belive this is some syncronization issue. But, I am not getting anywhere.
Do you really get any successfully inserted templates? The only way I can get $compile(angular.element(row).contents())($scope) to work is when the <table> is prebuilt or rendered by ng-repeat.
Here delayed injected HTML from a jQuery AJAX needs to be replaced with a ng-template including bindings, I think $scope.$apply() is the only way around :
.withOption('createdRow', function (row, data, dataIndex) {
$scope.$apply($compile(angular.element(row).contents())($scope))
})
Works for me -> http://plnkr.co/edit/UqZKhpgMx7aHCXdaNkiN?p=preview
Silly me. The same can be done in a simple $timeout.
$timeout(function() {
$compile(angular.element(row).contents())($scope)
})
http://plnkr.co/edit/5OTeHHUgkIurd6Z3DCkP?p=preview

Categories

Resources