jquery data-attribute set not working - javascript

I'm trying to find a 'tr' element with matching data-title value and set data-qty value for that element.
Here's what I tried to do:
var menu_type = data.type;
switch (menu_type) {
case 'breakfast':
var menu_selector = '#breakfast-form';
break;
case 'snacks':
var menu_selector = '#snacks-form';
break;
default:
var menu_selector = '#breakfast-form';
}
for (var key in data.order) {
if (data.order.hasOwnProperty(key)) {
var find_row = $(menu_selector).find('tr[data-title="' + key + '"]').data('qty', data.order[key]);
}
}
console.log(data);
data.order is an array object with {Coffee: "1"}.
And here's my <tr> html:
<div id="breakfast-form">
<table class="orderTable">
<tbody>
<tr data-qty="9" data-title="Coffee">
<td></td>
</tr>
</tbody>
</table>
</div>
Where am I going wrong?

I think this is what you're looking for. You need to use .attr vs .data if you want to assign a data attribute to an element.
var selectors = {
breakfast: '#breakfast-form',
snacks: '#snacks-form'
};
function test(data) {
var menuType = data.type,
cssSelector = selectors[menuType || selectors.breakfast],
menu = $(cssSelector);
for(var key in data.order){
menu.find('tr[data-title="' + key + '"]').attr('data-qty', data.order[key]);
}
}
test({
type: 'breakfast',
order: {
Coffee: "1"
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="breakfast-form">
<table class="orderTable">
<tbody>
<tr data-qty="9" data-title="Coffee">
<td>test</td>
</tr>
</tbody>
</table>
</div>

There is a difference between the data attribute and the data properties.
The HTML markup attribute is used to set the DOM element properties on parse.
And the .data() method accesses the property directly.
From the documentation: «The data- attributes are pulled in the first time the data property is accessed and then are no longer accessed or mutated »
Run the snippet below and inspect the markup.
setInterval(function(){
var count = $("#test").data("count");
console.log(count);
count++;
$("#test").data("count",count);
},1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test" data-count="0">Test div</div>
If you want to "see" your changes in the markup, you have to update the markup attribute using .attr("data-whatever", "new value");.
Inspect the snippet below now.
setInterval(function(){
var count = $("#test").attr("data-count");
console.log(count);
count++;
$("#test").attr("data-count",count);
},1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test" data-count="0">Test div</div>
Note that there is an efficiency price on insisting to "see" the markup updating.

Since you mentioned that data.order is an array of object with {Coffee: "1"}, here the key in for-loop will return the index of the array i.e. 0,1,2...
To fix that, you can do something like this:
for(var index in data.order) {
key = Object.keys(data.order[index])[0];
value = Object.values(data.order[index])[0];
if(data.order.hasOwnProperty(index)){
var find_row = $(menu_selector).find('tr[data-title="'+key+'"]').attr('data-qty', value);
}
}
Also you were using .data instead of .attr

Related

Getting value from cell and his inside element JS

I want to get value like in subject, from cell but that cell have element <a>1</a> and in this element is the value.
I tried something like this:
function filter(gvId) {
var table = document.getElementById(gvId);
for (var c = 1; c < table.rows[2].cells.length; c++) {
for (var r = headerNumber; r < table.rows.length; r++) {
var value = table.rows[r].cells[c].getElementsByClassName("a").innerHTML;
console.log(value); //and it should show me :
//1
//2
//3
//4
}
}
}
<table>
<tbody>
<tr>
<td><a>1</a>
</td>
<td><a>2</a>
</td>
</tr>
<tr>
<td><a>3</a>
</td>
<td><a>4</a>
</td>
</tr>
</tbody>
</table>
Everything works greate without <a> tag inside cell. But now I don't know how to get this value.
In your case, the problem is in a row:
var value = table.rows[r].cells[c].getElementsByClassName("a").innerHTML;
Because you're trying to match an element by class, but not by element tag. Link tag <a> has no className a. Your current code will work fine for: <a class="a">1</a> or <div class="a"></div>.
May be you should try something like querySelector instead? Like:
var value = table.rows[r].cells[c].querySelector('a').innerHTML;
Please, also check the MDN docs about getElementsByClassName and querySelector
UPD: All the code could be simplified:
var contentLinks = table.querySelectorAll('td a');
contentLinks.forEach(function(item) {
var value = item.innerHTML;
console.log(value);
});
Get the text content of an element with .textContent instead of .innerHTML
var value = table.rows[r].cells[c].textContent;
Documentation here and here

Button to change color of <td>

I am trying to make an interactive periodic table of elements. I need to change the background color of more <td> with the classname "nemetale" when a button is clicked. It's not working, I don't know what I am doing wrong.
There is the button
<button onclick="document.getElementsByClassName('.nemetale').style.backgroundColor = 'red';">Nemetale</button>
There is one of the <td>s.
<table class="tabel_periodic">
<!--Randul 1-->
<tr>
<td class="nemetale">
<strong>1</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>1,008</i>
</td>
...
Working fiddle.
getElementsByClassName() : Returns an array-like object of all child elements which have all of the given class names.
The function .getElementsByClassmame() doesn't exist you should use .getElementsByClassName().
Since the .getElementsByClassName() return a list of elements you should return the first element instead using [0] like :
document.getElementsByClassName('nemetale')[0].style.backgroundColor = 'red';
var trs = document.getElementsByClassName('nemetale');
document.getElementById('change_color').addEventListener('click', function() {
for (var i = 0; i < trs.length; i++) {
changeColor(trs[i]);
}
});
function changeColor(tr) {
tr.style.backgroundColor = 'red';
}
<button id="change_color">Nemetale</button>
<table class="tabel_periodic">
<tr>
<td class="nemetale">
<strong>1</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>1,008</i>
</td>
</tr>
<tr>
<td class="nemetale">
<strong>2</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>2,008</i>
</td>
</tr>
<tr>
<td class="nemetale">
<strong>3</strong><br>
<acronym>H</acronym><br>
<em>Hidrogen</em><br>
<i>3,008</i>
</td>
</tr>
</table>
Two things:
Firstly, there is a typo in the function you call. It should be getElementsByClassName().
Secondly, getElementsByClassName() returns a NodeList. This is “like” an Array, but it means you have to select each item from the NodeList.
If there is only one element, you can do
document.getElementsByClassName('nemetale')[0].style.backgroundColor = 'red';
If there is more than one element you will have to loop through the items. I recommend making it a function.
<button onclick="highlight">Nemetale</button>
function highlight() {
var items = document.getElementsByClassName('nemetale');
Array.from(items).forEach(function(item) {
item.style.backgroundColor = 'red';
});
}
If you are using ES6, you can make it a bit shorter as well:
function highlight() {
const items = document.getElementsByClassName('nemetale');
Array.from(items).forEach(item => item.style.backgroundColor = 'red');
}
You have a typo: getElementsByClassmame, this isn't a valid JS method.
Use .querySelector instead:
document.querySelector('.nemetale')
https://jsfiddle.net/d5dg0uw4/
Make it like below by adding function:
<button onclick="changeBackgroundColor()">Nemetale</button>
put this into
<script>
function changeBackgroundColor(){
document.getElementsByClassName('nemetale')[0].style.backgroundColor = 'red';
}
</script>

Finding last occurrence of text

I have the following type of table in html, which is generated dynamically by php :
<tr><td>Kiss the Girls</td><td>2016-01-01</td></tr>
<tr><td>Kiss the Girls</td><td>2016-02-05</td></tr>
<tr><td>Along Came a Spider</td><td>2016-01-07</td></tr>
<tr><td>Along Came a Spider</td><td>2016-01-22</td></tr>
<tr><td>Along Came a Spider</td><td>2016-03-31</td></tr>
I would like to be able to have a dynamic display filter that would allow the user to click a box and hide all but the latest version of the manuscript. So it might look like :
<tr><td>Kiss the Girls</td><td>2016-02-05</td></tr>
<tr><td>Along Came a Spider</td><td>2016-03-31</td></tr>
At this point none of the <tr> or <td> tags have an id or a class, but I could easily add a class to the first column (e.g., <td class='bookTitle'>). There is only one table on the page and php sorts it by date already. I'm open to jQuery or native JavaScript, though I would think this would be easier with jQuery. Seems like it could be done by just grabbing the last row before it changes names, but I'm not sure how to do that. Any thoughts?
According to 'Seems like it could be done by just grabbing the last row before it changes names', this is what I've come out with:
var rows = $("table tr");
if(rows.length > 0){
var last = $(rows[0]).find('td')[0].innerText;
for(var i=1; i<rows.length; i++){
var row = $(rows[i]);
var text = row.find('td')[0].innerText;
if(text === last){
$(rows[i-1]).hide();
}
last = text;
}
}
See the Pen Finding last occurrence of text by Tan Li Hau (#tanhauhau) on CodePen.
Iterate over the tr and store in key value pair where key as td content and value as object, after get the objects from it.
var a = {}; // object for storing dom element object
$('table tr').each(function() {
a[$('td:first', this).text().trim()] = this; // update the dom element object based on the column
});
var $res = $($.map(a, function(v) {
return v; // get objects and convert to jQuery object
}));
console.log($res);
$res.css('color', 'red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr>
<td>Kiss the Girls</td>
<td>2016-01-01</td>
</tr>
<tr>
<td>Kiss the Girls</td>
<td>2016-02-05</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-07</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-22</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-03-31</td>
</tr>
</table>
FYI : If you want to maintain the order then the value with index and object array and set order based on that
You could iterate in reverse and remove everything you've seen before as you go:
function filterPreviousVersions ( ) {
var seen = {};
$( $('tr').get( ).reverse( ) ).each( function ( ) {
var text = $( 'td', this ).first( ).text();
if ( seen[ text ] )
$( this ).remove();
seen[ text ] = true;
} );
}
filterPreviousVersions();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr>
<td>Kiss the Girls</td>
<td>2016-01-01</td>
</tr>
<tr>
<td>Kiss the Girls</td>
<td>2016-02-05</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-07</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-22</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-03-31</td>
</tr>
</table>
If you add ids in increasing order as you add the rows,
You may use this :
var valArray = [];
$('.maindiv').each(function() {
valArray.push(parseInt($(this).attr('id'), 10));
})
valArray.sort(function(a, b) {
return a - b
})
alert("Last row : " + document.getElementById(valArray[valArray.length - 1]).innerHTML); // highest`
alert("Second last : " + document.getElementById(valArray[valArray.length - 2]).innerHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="2" class="maindiv">Contents in row 2</div>
<div id="5" class="maindiv">Contents in row 5</div>
<div id="3" class="maindiv">Contents in row 3</div>
<div id="1" class="maindiv">Contents in row 1</div>
<div class="main">Contents in test row</div>
<div id="4" class="maindiv">Contents in row 4</div>
To put it all together:
Succint: (May have some performance impact for large tables with many duplicate values)
$('tr').each(function(){
$("tr :contains('" + $('td', this).first().html() + "')").last()
.parent().css('color', 'red');
});
Explanation for the succint version:-
$('tr').each(function(){ // for each row of the table
$("tr // find a child inside a tr
:contains('" // that contains the text
+ $('td', this) // present within a td of the row (in line 1)
.first().html() // at the beginning
+ "')") // Using string concat to pass variable to `contains` selector)
.last() // at the end (last occurence of text)
.parent() // invoke `parent()` to select whole row
.css('color', 'red'); // apply css to identify the desired row.
});
Verbose: (Using Set of ECMAScript6 or $.unique() to remove duplicates from the full list of names. This way, when the forEach loop at the end of the code runs, it'll iterate only one per name.)
var uniqueNames = [];
$('tr').each(function(){
uniqueNames.push($('td', this).first().html());
}); // this will return the list of names from the table
// Remove duplicates from the list of names
uniqueNames = new Set(uniqueNames); // OR: uniqueNames = $.unique(uniqueNames);
uniqueNames.forEach(function(el){
$("tr :contains('" + el + "')").last().parent().css('color', 'red');
});

pass value of cell from table row to variable

I am attempting to pass the value of the data-count cell to a variable using either jQuery or Javascript. How can I do it? Here is the HTML:
edit I should have stated that the value of id-offer=186000 is not constant and differs from page to page
<table class="vis" id="own_offers_table">
<tbody>
<tr class="offer_container " id="offer_186000" data-id="186000" data-count="30" data-village="" data-wanted_wood="900" data-wanted_stone="0" data-wanted_iron="0">
Thanks again for any help
var count = $('#offer_186000').data('count');
Setting the value:
$('#offer_186000').data('count', value);
If you can't use it's id
$('#own_offers_table').find('.offer_container').data('count');
For Setting the value:
$('#own_offers_table').find('.offer_container').data('count', value);
Get the tr using getElementById or by the class using querySelector
Get the data- attribute value using dataset
//var count = document.getElementById('offer_186000').dataset.count;
var count = document.querySelector('.offer_container').dataset.count;
alert(count);
<table class="vis" id="own_offers_table">
<tbody>
<tr class="offer_container" id="offer_186000" data-id="186000" data-count="30" data-village="" data-wanted_wood="900" data-wanted_stone="0" data-wanted_iron="0">
</tr>
</tbody>
</table>
For Setting Value(Jquery Command):
$("#offer_186000").attr('data-count').val('30');
For getting value(Jquery Command):
var value = $("#offer_186000").attr('data-count').val();
alert(value);

Sorting <li> tags

I have a a and I would like to sort my list alphabetically (I don't want caps to matter) according to a class named "name". How would I do this?
<ul class="column">
<li>
<table>
<tr>
<td class="name" >Name of Item</td>
</tr>
<tr>
<td>Content</td>
</tr>
<tr>
<td>morecontent</td>
<td>morecontent</td>
</tr>
</table>
</li>
<li>
<table>
<tr>
<td class="name" >Another name of item</td>
</tr>
<tr>
<td>Content</td>
</tr>
<tr>
<td>morecontent</td>
<td>morecontent</td>
</tr>
</table>
</li>
</ul>
Thanks
Using jQuery, this should do it:
function sort() {
$($('ul.column>li').get().reverse()).each(function(outer) {
var sorting = this;
$($('ul.column>li').get().reverse()).each(function(inner) {
if($('td.name', this).text().localeCompare($('td.name', sorting).text()) > 0) {
this.parentNode.insertBefore(sorting.parentNode.removeChild(sorting), this);
}
});
});
}
The above is a little dense though, so if you want to understand what's going on, let's break it down line-by-line:
function sort() {
//get each <li> which is a child of <ul class="column">
//for each element in the results, execute a function
//also, we reversed the order (e.g. start at the bottom and go up
$($('ul.column>li').get().reverse()).each(function(outer) {
//this is the current <li> we're running against
var sorting = this;
//get the same set of elements again in their current state,
//so we can figure out where to put this one
$($('ul.column>li').get().reverse()).each(function(inner) {
//get the inner text of the <td class="name">
//for the item we're trying to replace,
//and for the current item in the inner loop
//use localeCompare to compare the two strings alphabetically
if($('td.name', this).text().localeCompare($('td.name', sorting).text()) > 0) {
//if the one we're trying to sort goes after the current one
//alphabetically, remove it from its current position
//and insert it after the current one
this.parentNode.insertBefore(sorting.parentNode.removeChild(sorting), this);
}
});
});
}
We can make it a little more reusable by passing in the selector for the list and the key:
sort('ul.column>li', 'td.name');
function sort(list, key) {
$($(list).get().reverse()).each(function(outer) {
var sorting = this;
$($(list).get().reverse()).each(function(inner) {
if($(key, this).text().localeCompare($(key, sorting).text()) > 0) {
this.parentNode.insertBefore(sorting.parentNode.removeChild(sorting), this);
}
});
});
}
Do keep in mind this requires jQuery, so you'll need a reference to it in your <head>:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
And this function should be called at some point in the page after the list is written in the HTML.
Mine answer is longer :p but work.
function SortLIs() {
var ColumnUL = $("ul.column");
var Columns = $(ColumnUL).children("li");
var ColumnNames = new Array();
var Columns_byName = new Array();
var Columns_Count = Columns.length;
for(var i = 0; i < Columns_Count; i++) {
var aColumn = Columns[i];
var aTD = $(aColumn).find(".name");
var aTDName = aTD.text();
ColumnNames.push(aTDName);
Columns_byName[aTDName] = aColumn;
$(aColumn).remove();
}
ColumnNames.sort(function(a, b){
return (a > b) - (a < b);
});
for(var i = 0; i < Columns_Count; i++) {
var aName = ColumnNames[i];
ColumnUL.append(Columns_byName[aName]);
}
}
EDIT: I saw you said that you are not good at JS. So here is the bigger picture for you.
(1) Add The following code to the header of the HTML. This will use jQuery library.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
(2) Add the 'sortLIs' code just right after the above code
<script>
<!--
function SortILs() {
...
}
-->
</script>
(3.1) If you want the sorting to begin at the load time. Add this right after the above code.
<script>
<!--
$(document).ready(function(){
SortILs();
});
-->
</script>
(3.2) Otherwise, you call the function from an event.
Hope this helps.
Here's another approach, stealing ideas from the other answers given so far (also requiring jQuery):
function sort(elementSelector, valueSelector, ascending) {
var sign = ascending ? -1 : 1;
var elements = jQuery(elementSelector);
elements.each(function() {
this.sortKey = jQuery(valueSelector, this).text();
});
var sorted = elements.get();
sorted.sort(function(a, b) {
var keyA = a.sortKey;
var keyB = b.sortKey;
return sign * ((keyA < keyB) - (keyA > keyB));
});
elements.parent().append(sorted);
}
sort('.column>li', '.name', true)
Just seconding the jQuery response above, have a look at this tutorial:
http://www.shopdev.co.uk/blog/sortable-lists-using-jquery-ui/
For semantics, you might be better off also placing the classname inside the actual <li> tag.
The use of a table inside a list aside though, you may want to post an example page to help further.

Categories