overriding tr onclick - javascript

I've got the following code in a django template:
{% for item in items %}
<tr onclick="{% url collection:viewitem item_id=item.id %}">
<td>{{ item.name }}</td>
<td>{{ item.date }}</td>
<td>
<button onclick="{% url collection:edititem item_id=item.id %}" type="button">Edit</button>
<button onclick="{% url collection:removeitem item_id=item.id %}" type="button">Remove</button>
</td>
</tr>
{% endfor %}
However, the button onclick events don't work, because the tr onclick seems to override it. How can I prevent this from happening?

please try the following:
<html>
<body>
<table >
<tr onclick="alert('tr');">
<td><input type="button" onclick="event.cancelBubble=true;alert('input');"/></td>
</tr>
<table>
</body>
</html>
The event.cancelBubble=true will suppress the tr click event

Using event.stopPropagation() will do the trick!

An other approach:
Create a separate row for the button so it wont inherit the tr onclick event of the main row. Something like this:
<tr onclick="doSomething()">
<td rowspan="2">A</td>
<td rowspan="2">B</td>
<td rowspan="2">C</td>
</tr>
<tr>
<td><button type="button">Click</button></td>
</tr>

Related

Use a same JQuery function for multiple elements

I am currently learning web development using Flask. I am stuck at a place where I want to use a jquery function to return the value from an input tag in for that corresponding row.
Here;s my HTML:
enter code here
{% extends "base.html" %} {% block title %} Menu item {% endblock %} {% block content %}
<div class="container">
<div class="row">
<table class="table table-striped table-inverse table-responsive">
<thead class="thead-inverse">
<tr>
<th>Item Name</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
<tbody>
<form>
{% for item in menu_category %}
<tr>
<td scope="row">{{item.item_Name}}</td>
<td>{{item.item_Price}}</td>
<td>
<input type="hidden" class="form-control test" name="item_id{{ loop.index0 }}" id="itemID" placeholder="" value="{{ item.item_Id }}">
<a name="add_to_cart" id="add_to_cart" class="btn btn-primary clsAddToCart" href="#" role="button">Add to Cart</a>
</td>
</tr>
{% endfor %}
</form>
</tbody>
</table>
</div>
<p id=result>cart: </p>
</div>
{% endblock %}
Here's my Jquery function:
<script>
$(function() {
$('.clsAddToCart').bind('click', function() {
$.getJSON('{{ url_for("func_add_to_cart") }}', {
productID: $("input[name^='item_id']").val(),
}, function(data) {
$("#result").html(data.result);
});
return false;
});
});
</script>
I just want the function to return the corresponding item id on the button click, but somehow it always returns the first item id only for all.
Much Thanks!
The jQuery documentation for the val method explains this on the very first line:
Get the current value of the first element in the set of matched elements or set the value of every matched element.
(the emphasis is mine to show the relevant part for your question).
For each "add to cart" button to work on the corresponding input, you can use $(this) to get hold of the specific button clicked on, and then use, for example, the prev method (since in your HTML the input is the immediately preceding sibling - there are slightly more sophisticated things you could do to make this more robust to changes in your HTML, but I'll let you figure those out if you need them):
$(function() {
$('.clsAddToCart').bind('click', function() {
$.getJSON('{{ url_for("func_add_to_cart") }}', {
productID: $(this).prev().val(),
}, function(data) {
$("#result").html(data.result);
});
return false;
});
});
You are setting all input elements the same id ('itemID'). Should be like: 'item{{ item.item_Id }}'. May be this can solve your problem.
Your jQuery function should be like :
<script>
$(function() {
$('.clsAddToCart').bind('click', function() {
$.getJSON('{{ url_for("func_add_to_cart") }}', {
productID: $(this).closest('input').val(), //<==
}, function(data) {
$("#result").html(data.result);
});
return false;
});
});
</script>
In order to get the value of the correct input element you have to make use of the context of the click event. The this keyword refers to the element that was click. Therefore you can use that to target the correct input element using relative positioning to this. Per your structure any of the following should be fine as a replacement for $("input[name^='item_id']").val():
$(this).siblings().val(); //OR
$(this).closest('td').find('input').val(); //OR
$(this).parent().children('input').val(); //AND SO ON AND SO FORTH
Please remember that:
.bind() is deprecated as of v3, so use .on()
Keep all your id attributes unique and, no need to have them if you don't need them.
$(function() {
$('.clsAddToCart').on('click', function() {
console.log( $(this).siblings().val() );
/*$.getJSON('{{ url_for("func_add_to_cart") }}', {
productID: $("input[name^='item_id']").val(),
}, function(data) {
$("#result").html(data.result);
});
return false;*/
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="row">
<table class="table table-striped table-inverse table-responsive">
<thead class="thead-inverse">
<tr>
<th>Item Name</th>
<th>Amount</th>
<th></th>
</tr>
</thead>
<tbody>
<form>
<!--{% for item in menu_category %}-->
<tr>
<td scope="row">Item Name 1</td>
<td>100</td>
<td>
<input type="hidden" class="form-control test" name="item_id-1" id="itemID1" placeholder="" value="id1">
<a name="add_to_cart" id="add_to_cart" class="btn btn-primary clsAddToCart" href="#" role="button">Add to Cart</a>
</td>
</tr>
<tr>
<td scope="row">Item Name 2</td>
<td>200</td>
<td>
<input type="hidden" class="form-control test" name="item_id-1" id="itemID2" placeholder="" value="id2">
<a name="add_to_cart" id="add_to_cart" class="btn btn-primary clsAddToCart" href="#" role="button">Add to Cart</a>
</td>
</tr>
<tr>
<td scope="row">Item Name 3</td>
<td>300</td>
<td>
<input type="hidden" class="form-control test" name="item_id-1" id="itemID3" placeholder="" value="id3">
<a name="add_to_cart" id="add_to_cart" class="btn btn-primary clsAddToCart" href="#" role="button">Add to Cart</a>
</td>
</tr>
<tr>
<td scope="row">Item Name 4</td>
<td>50</td>
<td>
<input type="hidden" class="form-control test" name="item_id-1" id="itemID4" placeholder="" value="id4">
<a name="add_to_cart" id="add_to_cart" class="btn btn-primary clsAddToCart" href="#" role="button">Add to Cart</a>
</td>
</tr>
<!--{% endfor %}-->
</form>
</tbody>
</table>
</div>
<p id=result>cart: </p>
</div>

DataTables not sorting properly

I am using DataTables for my project but its sorting function does not work properly. I have tried every single solutions in here but none of them worked for me as well as it does not show the error in the console. I think in my code there is a jQuery conflict. How can I solve this issue? any help?
<table id="dtBasicExample" class="table table-bordered table-hover contact-list" cellspacing="0"
width="100%">
<thead>
<tr>
{# <th scope="col"><input type="checkbox"></th>#}
<th scope="col">Name</th>
<th scope="col">Company Name</th>
<th scope="col">Email</th>
<th scope="col">Phone Number</th>
</tr>
</thead>
{% for contact in contacts %}
<tbody>
<tr data-id="{{ contact.id }}" class="clickable-row"
data-href="{% url 'contact-detail' contact.id %}"
style="cursor: pointer; ">
{# <th scope="row"><input type="checkbox" id="check"></th>#}
<td>{{ contact.client_name }}</td>
<td>{{ contact.client_company_name }}</td>
<td>{{ contact.email }}</td>
<td>{{ contact.work_phone }}</td>
</tr>
</tbody>
{% endfor %}
</table>
{% csrf_token %}
$('#dtBasicExample').DataTable();
$('.dataTables_length').addClass('bs-select');
as you can see it is a material bootstrap design datatables. In the example shown it works but when i add to my project it does not.
Your html table is "not valid" (It is valid if you want to create multiple table into an parent table). This can make some issue with Datatable. I think sorting is done, but you do not see it, because it sort by tbody tag and there is one line sorted by tbody. The tbody tags are not sorted only the tr inside
Try to remove the tbody into your loop and export it outside the for loop.
<tbody>
{% for contact in contacts %}
// ...
{% endfor %}
</tbody>
Note: cellspacing="0" is an old version of html. You can replace it by the css property border-spacing

Select and store element from HTML table/JSON parsed object array

I have an HTML table displaying the titles and sources of news articles. The news articles come from a JSON object. I can't figure out how to make it save the specific article you click the 'submit' button next to (=extract the appropriate element from a JSON array). I'd want to return/save it to some sort of output that I can then store in SQL. Please help?
The table looks like this:
<thead>
<tr>
<th>Article</th>
<th>News Source</th>
</tr>
</thead>
<tbody>
{% for article in articles.articles %}
<tr>
<div id = {{ article.title }}>
<td><a href = {{ article.url }}>{{ article.title }}</a></td>
<td>{{ article.source.name }}</td>
</div>
<td><form method="post"><button class="btn btn-primary" type="submit">Save to profile</button></form></td>
</tr>
{% endfor %}
</tbody>
</table>

Detect table cell change on user edit

I'm trying to detect html table cell change on user input. When I click on table cell I can type text in it, but my .change function is not triggered. However on page load when data are populated from database, for every table cell change change function is fired. I can not figure why. Can you help.
My code below:
<div id="table" class="table-editable">
<table id="myTable" style="width:100%" class="table">
<tr>
<th>Id</th>
<th>Link</th>
<th>Naslov</th>
<th>Lokacija</th>
<th>Cijena</th>
<th>Telefon</th>
<th>Posjet</th>
<th>Opis</th>
<th>Prednosti</th>
<th>Nedostaci</th>
<th>Slike</th>
<th>Select</th>
{% for entry in entries %}
</tr>
<tr>
<td>{{ forloop.counter }}</td>
<td><a id="linkHouse_{{ forloop.counter }}" href="{{ entry.link }}">Link na oglas</a></td>
<td contenteditable="true">{{ entry.header }}</td>
<td contenteditable="true">{{ entry.location }}</td>
<td id="priceHouse_{{ forloop.counter }}" contenteditable="true">{{ entry.price }}</td>
<td id="contactHouse_{{ forloop.counter }}" contenteditable="true">{{ entry.contacts }}</td>
<td id="visitedHouse_{{ forloop.counter }}" contenteditable="true">{{ entry.visited }}</td>
<td id="descriptionHouse_{{ forloop.counter }}" contenteditable="true">{% for line in entry.description.splitlines %} {{line}}<br> {% endfor %}</td>
<td id="prosHouse_{{ forloop.counter }}" contenteditable="true" >{% for line in entry.pros.splitlines %} {{line}}<br> {% endfor %}</td>
<td id="consHouse_{{ forloop.counter }}"contenteditable="true">{% for line in entry.cons.splitlines %} {{line}}<br> {% endfor %}</td>
<td >
<a class="fancybox" target="_blank" data-fancybox="images" href="{% static "Pic/img_fjords_wide.jpg" %}"><img src="{% static "Pic/img_fjords_wide.jpg" %}" alt="" style="width:150px"></a>
<a class="hide fancybox" target="_blank" data-fancybox="images" href="{% static "Pic/img_lights_wide.jpg" %}"><img src="{% static "Pic/img_lights_wide.jpg" %}" alt=""></a>
<a class="hide fancybox" target="_blank" data-fancybox="images" href="{% static "Pic/img_mountains_wide.jpg" %}"><img src="{% static "Pic/img_mountains_wide.jpg" %}" alt=""></a>
</td>
<td style="text-align: center; vertical-align: middle;">
<button id="delHouse_{{ forloop.counter }}" onclick="delHouse(this.id)">Delete</button>
<!--<input type="checkbox" name="delete{{ forloop.counter }}">-->
</td>
</tr>
{% endfor %}
</table>
</div>
$(document).ready(function(){
$( "#myTable td" )
.change(function () {
console.log("petar");
var data = this.innerHTML;
console.log("value="+data);
})
.change();
});
Use Javascript's input method.
Or the blur method.
<div contenteditable oninput="console.log(this.innerHTML)">Change me (input)!</div>
<div contenteditable onblur="console.log(this.innerHTML)">Change me (blur)!</div>
IE 6 & 8 and Opera Mini are not supported & IE 9 partial support, but either than that, it works!
If you want global support, check out this thread.
So your code would look like:
$(document).ready(function(){
$( "#myTable td" )
.input(function () {
console.log("petar");
var data = this.innerHTML;
console.log("value="+data);
})
.input();
});

Place Click event on a table row but exclude one the columns

I have a table where the rows are clickable. when you click on them the row beneth them containing a hidden div is expanded, exposing a nested table of related data. That works the way I had intended.
The problem is that the last column of the table has an edit button. when the edit button is pressed the row is expanded right before it redirects to edit page. This looks very sloppy. is there any way to remove the event from that column only?
Here is my code. This is a Django Template BTW.
HTML
<table id="exp" class="feedtable table table-hover table-bordered ">
<thead>
<tr>
<th>Scales</th><th>Type</th><th>Edit</th>
</tr>
</thead>
<tbody>
{% for scale in scales %}
<tr>
<td><p class="scalet">{{scale}}<p></td><td>{{scale.calc_type}}</td><td><a href="{% url 'questions:edit_feedback' scale.pk %}" class="btn btn-default">Edit</td>
</tr>
<tr>
<td colspan="3">
<div id="{{scale.pk}}div">
<table id="{{scale.pk}}table" class="feedtable table-hover table-bordered">
{% for question in questions %}
{% if question.scale == scale%}
<tr>
<td>{{question | safe}}</td><td><a class='btn btn-default' href="{% url 'questions:edit_question' question.pk %}">Edit</td>
</tr>
{% endif %}
{% endfor %}
</table>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
JQuery
$(function() {
$("td[colspan=3]").find("div").hide();
$("tr").click(function(event) {
console.log("hit")
var $target = $(event.target);
$target.closest("tr").next().find("div").slideToggle();
});
});
you can use event.target object and class,
e.g.)
if a column has "a specific class(or attribute)", you can remove the event
$(document).ready(
function(){
$("tr").click(function(event){
console.log($(event.target).hasClass("except"));
});
}
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td class="except">except</td>
<td>data</td>
</tr>
</table>

Categories