I need to grab certain parts from many tables, save them and finally generate a new table using a jQuery template. But I am having problems collecting the first value.
HTML
<table>
<tr><td colspan="7">atext1 atext2 - stuff 2 - <img src="img/icon_1.gif" class="icon" title="icon1" />12 - <img src="img/icon_2.gif" class="icon" title="icon2" />4 - <span title="long title"><img src="img/icon_3.gif" class="icon" /> stuff 5 </span></td></tr>
<tr><th><span title="title1">th1</span></th><th title="title2">th2</th><th title="title3">th3</th><th title="title4">th4</th><th title="title5">th5</th><th title="title6">th6</th><th title="title7">th7</th></tr>
<tr><td class="own" style="width:10px;"> </td><td>text</td><td><img src="img/icon_4.png" class="icon link" title="icon4" onclick="dothis(118965,[1324,1835,2296,2443,2960,2961,2962,2964,2976,3186,4901,4974]);" /> text</td><td>text</td><td class="right">24 (9)</td><td class="right">827</td><td class="right">11</td></tr>
MORE SIMILAR TRs HERE
</table>
JS
var savedData = [];
tbl = $('#table_1'); // Grab all content within div, which is a whole html table
var data = [];
$('tr', tbl).each(function(i, tr) {
// Begin the process to grab needed parts
if (i == 0) { // first row is special. it is colspan'ed
row = $('td', tr).html().split(' - '); // Splitting seems like the only way to get smaller html parts to work with
var a_href = $(row).find('a').attr('href'); // returns undefined
var a_href = $(row[0]).find('a').attr('href'); // returns undefined
var a_href = $('a', row).attr('href'); // returns undefined
var a_href = $('a', row[0]).attr('href'); // returns undefined
// Grab id only. I thought this would work
data['id'] = $('a', row[0]).attr('href').match(/view=page&id=([0-9]+)/)[1];
// Grab the other parts
} else {
// do stuff for other rows
}
});
savedData.push[data];
1) Why am I getting undefined ? 'row' becomes an array when splitting the inner html
2) I also have at least 1 tr with only th cells. Would it faster those rows where excluded from the .each(), like with a sub selector, or just ignore it (like if ($('td', tr).length > 0) { // do stuff }) ?
3) If I just grab all text() from all td in all tr then using jQuery.map() is about 3-4 times faster than jQuery.each(i,v). Any idea why ?
I can use $('td[colspan], tr) to grab first row, but jQuery.each() is easy to understand and thus to work with
4) When I need to use the collected parts in the template, can I then use savedData[0].id ?
I got my answer here How to extract multiple parts from a html string with jQuery?
Related
I have created a simple program that filters words based on a list from an external txt file with regex inside my js file.
For the most part when I input a list of words from the txt file they are filtered out. However there is one keyword that is causing me trouble.
'black & decker'
I am guessing it has to do with the '&' sign because any new words I put into the txt file with a '&' sign does not filter out for some reason.
Can anyone help me to why words with the & is not filtering out properly? And also check if my regex is written properly for this program(var filtered)?
Any help would be much appreciated. Thank you.
I have a list of words in a txt file here:
baby bullet, baby-bullet, back2life, back-2-life, black & decker, black-decker, black-&-decker, britax, bose, capital brands products, capital-brands-products, dewalt, dyson, ergobaby, ergo-baby, fiskars, ickle bubba, ickle-bubba, kitchen aid, kitchen-aid, longstem, long-stem, magic bullet, magic-bullet, makita tools, makita-tools, milwaukee, monster cable, monster-cable, mustee, nest, nutri____, nutribullet, oxo, party bullet, shark, simplehuman, sony bravia, urban decay, urban-decay, waterpik, weber grill, weber-grill, youthology, teeter
Here is my JS file that filters inputted words based on the txt list
// This grabs the data from the txt file and splits each word by commas
$.get('word-list.txt', function(data) {
pbfFilterWords = data.split(', ');
pbfFilterWords.forEach(function(word){
pbfWordList = word;
});
// This defines a global variable so the filter button has a list of words to filter with
var pbfWordList = pbfFilterWords;
//This will allow the list of words to filter with regex
var pbfRegEx = pbfFilterWords;
var filtered = (function(){
var filtered = [], i = pbfRegEx.length;
while (i--) {
if (/w*[\s|\w|\b+]*\w*/.test(pbfRegEx[i])) {
filtered.push(pbfRegEx[i]);
}
}
return filtered;
})();
console.log(filtered.join());
// Function for filter button
$('.pbf-link-container[contenteditable]').html;
$('#pbf-filter').click(function(){
var $pbfOutput = $('.pbf-link-container[contenteditable]').html();
// Array of words for filter
var pbfFilterWords = pbfWordList;
// Output to new DIV and remove specified keywords from pbfFilterWords
$('.pbf-link-output').html($pbfOutput);
// To make pbfFilterWords not case sensitive
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).html().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
// Function to output the filtered words
$.each(pbfFilterWords , function(i , filtered){
$('.pbf-link-output > div:contains("'+filtered+'")').remove();
});
});
});
Here is my html:
<div id="pbf-container">
.....
<div class="pbf-link-container" contenteditable="true">
<div><br/></div>
</div>
<div class="pbf-button-control">
<button id="pbf-filter"> Filter </button>
</div>
<div class="pbf-filter-header">
<h3> Filtered Links </h3>
</div>
<div class="pbf-link-output">
</div>
</div>
Your pseudo selector implementation takes html version of inner contents of the div tag, so it converts & to & and you don't have a match.
You can see yourself:
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
// console.log value of current element here
console.log($(elem).html().toUpperCase()); // logs string with &
return $(elem).html().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
use $(elem).text() to get text version of inner content of a div.
Essentially the problem is that I am getting duplicate results in my DataTable.
In my application, the user will enter a value and that value will return an array of objects from the database and those records will then populate in the DataTable. Currently the issue that I am having is that all the records that are in the table are all the same.
There should be 100 different records in the DataTable, instead there is 100 of the exact same record. I am not seeing any examples that show how to iterate though an array of objects from a database, in a way that in can be handled by the DataTable.
I should be able to use rows.add() but that does not have anything displaying in the table and the other option I saw was rows().every() which does not have an example similar to what I am doing.
Any references, resources or insight will be very helpful. Thanks!
User Input:
<p> Year: <input id="YearNbrId" type="text" th:field="*{YearNbr}" /> </p>
Button:
<input type="button" value="Locate" id="goToDetails" />
JavaScript Snippet:
$(document).ready(function() {
var table = $('#Orders').DataTable();
$('#goToDetails').on('click', function() {
var YearNbr = $('#YearNbrId').val();
var url = './eData/locate?YearNbr=' + YearNbr;
$.get(url, function(result) {
console.log(result);
for (var i = 0; i < result.length; i++) {
var myOrder = result[i];
table.row.add([
null, // place holder
myOrder.yearNbr,
myOrder.orderNm,
'<input>', // user input
myOrder.model,
new Date(myOrder.Date).toJSON().slice(0, 10),
myOrder.srcCode,
null,
'<input>'
]).draw(false)
.nodes()
.to$();
}
});
});
});
You might want to check out the JQuery .each function. You probably need to do something like: $(result).each(function(i,obj) {//code here}); Where i is the position in the array and obj is the current record in result.
I have a table (called mytbl - see below) consisting of 100 rows. From this table, I want to take only the first five rows (assume a user presses "Show Top Five")
This is what I have tried, however, the alert gives me 'empty'
var $updatedtable = $("#mytbl");
$updatedtable.empty();
for ( var i = 0; i < 5; i++ )
{
$updatedtable.append(document.getElementById("mytbl").rows.item(i).innerHTML)
}
alert($updatedtable);
$updatedtable.appendTo( $( "#rbl" ) );
This was the code used to create the html page
<div class="tab-pane" id="rbl">
<div id="rbldiv">
<div class="bs-example voffset-10px">
<form>
<div class="form-group">
<label for="inputText" style="float:left;margin-right:5px;">Show top </label>
<div class="col-xs-1">
<input type="text" class="form-control input-normal" id="ben-count-set" placeholder="100">
</div>
<label for="inputText"> beneficiaries by cost increase</label>
</div>
</form>
</div>
<table id="mytbl" class="table table-striped table-hover"></table>
</div>
</div>
Also, if, after I successfully manage to get the top five and appendTo rbl which has mytbl, won't this get overwritten? If later the user wants to See Top 30, aren't the values gone? How can I take care of this?
EDIT:
I was able to get the display of the top rows thanks to charlietfl and Tatermelon. But my rows get sliced off, and I haven't completely understood how to handle a case where user selects top 10 first and then top 11.
This is what I have tried.
In the function where I'm making the (entire) table for the first time, I saved the table as follows
function makeTable() {
//code to make table rbltbl
//code to make table rbltbl
//code to make table rbltbl
//code to make table rbltbl
//below line saves the table to $rows, so I can use it inside the click function below
$rows = $('#rbltbl tr').clone();
}
This is my function. Assume 'ben-count-set' is the number of values, the user wants to see. I think I should change var $table to read from $rows instead of rbltbl. But $rows gives empty here.
$("#ben-count-submit").click(function (event) {
event.preventDefault();
console.log("clicked on the update button");
var reqcount = document.getElementById('ben-count-set').value;
var $table = $("#rbltbl");
var $mystring = '#rbltbl tr:gt('+parseInt(reqcount)+')';
$($mystring).remove();
console.log($mystring);
$table.appendTo( $( "#rbl" ) );
}
Please advise.
If you want an array of the first 5 rows can get it right in a jQuery object using several different selectors
$('#mytbl tr:lt(5)');
You can can cache all the rows into a variable and still have access to them later regardless of what you do to the table...just clone them
var $rows = $('#mytbl tr').clone();
Want to remove all but top 5
$('#mytbl tr:gt(4)').remove();
then change out for another selection of rows clone the clone, filter them and insert
$('#mytbl').html( $rows.clone().slice(5, 10) );
If you are using jquery, then you can use the :lt selector:
var $firstRows = $('#mytbl').find('tr:lt(5)');
Then, you can clone them to append in your new table so that they will not be removed from your original table:
$( "#rbl" ).append($firstRows.clone());
I need to access title value from some img elements but these elements are deeply implemented in a div tree and after that into some tables.
Let me explain why I need them:
I use a portal where I have information regarding circuits from a network. This portal contains some locations with a few rows (2-3 usually -> circuits for that location). Each row starts with an img element and it can have a few values on title attribute. If the title value is != "No alarms" then I have to take all data from that row and I want to show them via a pop up notification on the bottom right corner near clock.
Below you have a screenshot for how are the html elements organized (for all locations).
http://imageshack.com/a/img661/962/ErjQOt.png
Below you have a screenshot for how is a location organized:
http://imageshack.com/a/img661/7453/QAP5oM.png
If title attribute == "Warning", for example, I have to take the data from the next td's in the same table. Each td has another div without id. Firsts 2 td's on each table have another element inside div: img on first one and a href on the second one.
I'm drawing the tree to show you exactly how are the html elements organized.
<table class="x-grid3-row-table">
<tbody>
<tr>
<td> <!--first td, this contains div->img-->
<div class="x-grid3-cell-inner x-grid3-col-0">
<img .... title="No alarms">
</div>
</td>
<td> <!--second td, this contains div->a href-->
<div class="x-grid3-cell-inner x-grid3-col-1">
<a href...>
</div>
</td>
<td> <!--3rd td, this contains div->string:Text1-->
<div class="x-grid3-cell-inner x-grid3-col-2">Text1</div>
</td>
<td> <!--4th td, this contains div->string:Text2-->
<div class="x-grid3-cell-inner x-grid3-col-2">Text2</div>
</td>
...
</tr>
</table>
Location-1 has 3 circuits, this means 3 tables. The above table is inserted in a div (div class="x-grid3-row x-grid3-row-first" from screenshot2). There are 2 more tables after this one on another div's (div class="x-grid3-row x-grid3-row-alt" & div class="x-grid3-row" from screenshot2) and I have to check the title attribute for each table.
Now my question is how to get the title attribute from each table on the same location? and if the title is != "No alarms" how can I get data from the next td's in that table?
Maybe I can use a loop for all 12 locations or maybe I can get them one by one. This is no big deal because there are only 12 locations but the nasty thing is inside each location to get info from each circuit.
I think there should be a syntax like this to reach each html elements and to get the right value.
var title = $('#ext-gen15-gp-location-1-bd table[0] td[0] img').attr('title');
var title = $('#ext-gen15-gp-location-1-bd table[0] td[1] div[0]').attr('innerHTML');
....
var title = $('#ext-gen15-gp-location-1-bd table[1] td[0] img').attr('title');
var title = $('#ext-gen15-gp-location-1-bd table[1] td[1] div[0]').attr('innerHTML');
...
var title = $('#ext-gen15-gp-location-9-bd table[0] td[0] img').attr('title');
var title = $('#ext-gen15-gp-location-9-bd table[0] td[1] div[0]').attr('innerHTML');
...
...and so on. I'm sure that this syntax is not correct but I think there should be a way to get that data.
I hope that now is explained better then the first time.
EDIT
Guys, thank you very much. You help me a lot. Your codes are working.
Anyway, I just want to ask you something else.
After 3 minutes the whole table is refreshing and I can't find a way to reload the function after that. When the content is refreshing, div ext-gen24 remains empty and after that is refilled with the content:
When is refreshing:
<div class="x-grid3-body" style="width: 1877px;" id="ext-gen24"></div>
After refresh is completed
<div class="x-grid3-body" style="width: 1877px;" id="ext-gen24">content</div>
Can you help me with a function you think it should work in this case ?
You'll need loop through multiple stages of the html: groups, tables, and columns:
var groups = $('.x-grid-group-body'); //hopefully all the '#ext-gen15-gp-location-X-bd' div have 'x-grid-group-body' as the class
groups.each(function () {
var tables = $(this).find('table');
tables.each(function () {
var columns = $(this).find('td');
var image = $(columns[0]).find('img');
var title = image.attr('title');
if (title !== 'No alarms') {
var allInnerHtml = '';
for (var i = 1; i < columns.length; i++) {
allInnerHtml += $(columns[i]).find('div').html() + '\n';
}
alert(allInnerHtml);
}
else {
//just to show that titles with 'No alarm' are skipped
alert('skipped');
}
});
});
See updated JSFiddle
Hope that helps! =)
If your Div tree has classes in the same format is now you can use something like this.
var title = $('.x-panel-bwrap').find('img').attr('title');
Or if the div class dependency is not confirmed, then assuming that img tag will always have a class name starting with 'tick', you can use this.
var title = $('img *[class^="tick"]').attr('title');
EDIT
Now that you have explained your problem more clearly, i've included a fiddle with the solution you need. Now you will have to expand it to suit your code more closely.
For example if you want to log each location separately, start looping through the locations first and then find tables inside them.
Basically you can use Jquery .find and .each to go through your comeplete html and do whetever you want.
var tableList = $('.x-grid3-row-table');
tableList.each(function() {
var imgTitle = $(this).find('img').attr('title');
alert(imgTitle);
if (imgTitle == 'Warning') {
infoTd = $(this).find('td:nth-child(3)');
text = infoTd.find('div').text();
alert(text);
}
});
FIDDLE
I'm completely stumped. Granted, in java script i'm like that kid trying to jam a square peg into a round hole.
My high level objective: The admins want the ability to edit text surrounding some text boxes, as well as the ability to add and remove 'paragraph'. The reporters and users want the values that are in the textboxes to be used in comparisons, etc (which is the original functionality).
My Solution: This project uses a pretty messy value - attribute table (called an EAV?), which now has fields with associated fields and is self referencing. I decided to leverage this to minimize changes to the database, so the admin essentially creates a string, denotes the places a text box belongs using '{}', and assigns a name to the attribute into text boxes that appear directly below the paragraph.
My Problem: Textboxes generate fine, as soon as the admin stops typing the "{}" count is checked client side, and the correct number of textboxes are added/removed in rows below. However, when the "change" mode (and thereby save the new string) I also want to save the attribute names they selected. I can't seem to get the actual value out of the input. The java script below sends null to elementList. Closer inspection indicates that var fieldNames is getting two elements of "undefined" so it makes sense that I'm getting null. Its also apparent that Its hitting something, becuase the number aligns with there being two 'nameField' rows.
DOM (Hemed down to the essentials)
<tr data-editMode="TextMode" data-ordinal="0">
....
<td>
<a class="changeMode">
<tr class="nameField">
<td colspan='4'>
<input type="text" value="Testing">
<tr class="nameField">
....
Javascript
function getAssociatedTr(row) {
var associatedRows = [];
associatedRows.push(row);
row = row.next('tr');
var hasAnother = true;
while (hasAnother == true) {
if (row != null && row.hasClass("nameField")) {
associatedRows.push(row);
row = row.next('tr');
} else {
hasAnother = false;
}
}
return associatedRows;
}
$(".changeMode").live("click", function () {
var options = $(this).data("options");
var theRow = $(this).closest('tr');
var rows = getAssociatedTr(theRow);
var fieldNames = new Array();
rows.splice(0, 1);
for (var index = 0; index < rows.length; index++) {
{
fieldNames.push(rows[index].next('.nameField').val());
}
}
$(".modal-header", c.rowsModal).html("<h3>Changing edit mode" + options.table + "</h3>");
c.rowsModal.modal("show");
$.ajax({
type: "POST",
traditional: true,
data: { "Name": options.table, "Ordinal": options.row, "EditMode": options.editMode, "ElementNames": fieldNames },
url: "/contracts/changeeditmode/" + c.id.val(),
success: function (data) {
theRow.replaceWith(data);
$.validator.unobtrusive.parse("#supplementForm");
c.rowsModal.modal("hide");
for (j = rows.length - 1 ; j >= 0; j--) {
rows[j].remove();
}
}
});
});
Server side
public ActionResult ChangeEditMode(long id, AddTrackedRowViewModel model,
string editMode, List<string> elementNames)
{
}
As a side note, I'm open to constructive criticism on the JavaScript.
EDIT
I have updated the line to
fieldNames.push(rows[index].nextAll('input').first().val());
But still getting undefined.
SOLUTION
fieldNames.push(rows[index].find("input[type=text]").val());
In this line:
fieldNames.push(rows[index].next('.nameField').val());
you are using the selector ".nameField", but this get a "tr" element, if you want the textbox you need this:
fieldNames.push(rows[index].next('.valid').val());
or using other selector that give you the textbox.