I have a string that is set up as Xml. This was a data set which i filled and then returned as string getXml().
I would like to grab all values under Sub-categories and have a alert show displaying each sub category.
I tried something like this but could not come right:
$.parseXML(xml).find('Table').each(function(index){
var SubCategorySystem = $(this).find('SubCategorySystem').text();
var SubCategory = $(this).find('SubCategory').text();
alert(SubCategory);
});
This is how my string looks.
<NewDataSet>
<Table>
<SubCategorySystem>Building</SubCategorySystem>
<SubCategory>Building</SubCategory>
</Table>
<Table>
<SubCategorySystem>Electrical</SubCategorySystem>
<SubCategory>Electrical</SubCategory>
</Table>
<Table>
<SubCategorySystem>Engineering</SubCategorySystem>
<SubCategory>Engineering</SubCategory>
</Table>
<Table>
<SubCategorySystem>Inspection</SubCategorySystem>
<SubCategory>Inspection</SubCategory>
</Table>
<Table>
<SubCategorySystem>Landscaping</SubCategorySystem>
<SubCategory>Landscaping</SubCategory>
</Table>
<Table>
<SubCategorySystem>Mechanical</SubCategorySystem>
<SubCategory>Mechanical</SubCategory>
</Table>
<Table>
<SubCategorySystem>Painting</SubCategorySystem>
<SubCategory>Painting</SubCategory>
</Table>
<Table>
<SubCategorySystem>Plumbing</SubCategorySystem>
<SubCategory>Plumbing</SubCategory>
</Table>
<Table>
<SubCategorySystem>Safety & Security</SubCategorySystem>
<SubCategory>Safety & Security</SubCategory>
</Table>
</NewDataSet>"
Use this function to load the xml
function loadXMLString(txt) {
try {
xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async = "false";
xmlDoc.loadXML(txt);
return (xmlDoc);
}
catch (e) {
try {
parser = new DOMParser();
xmlDoc = parser.parseFromString(txt, "text/xml");
return (xmlDoc);
}
catch (e) {
alert(e.message)
}
}
return (null);
}
and then call the function like this:
var xmlData = loadXMLString(originalxml);
Now you can simply do this:
var data = xmlData.getElementsByTagName('SubCategory');
for(var i=0;i<data.length;i++)
{
alert(data[i].textContent);
}
Check out this fiddle
I think the wrong part is that $.parseXML(xml) creates a XML Document but it does not return it as an object, so you won't be able to use jQuery methods on it.
Wrap it in an object and it should work
$($.parseXML(xml)).find('Table')
you can reference this two functions first
function getExtendedNodeValue(nodeName, xmlNode, i)
{
var node = "";
if(typeof(xmlNode.getElementsByTagName(nodeName)[i]) != "undefined" && xmlNode.getElementsByTagName(nodeName)[i].hasChildNodes())
node = xmlNode.getElementsByTagName(nodeName)[i].firstChild.nodeValue;
return node;
}
function getNodeLength(nodeName, xmlNode){
return xmlNode.getElementsByTagName(nodeName).length;
}
And below you can loop through
var len = getNodeLength("Table",xml);
var SubCategorySystem = "";
var SubCategory = "";
for(i=0;i<len;i++)
{
SubCategorySystem = getExtendedNodeValue("SubCategorySystem",xml,i);
SubCategory = getExtendedNodeValue("SubCategory",xml,i);
console.log(SubCategorySystem + " == " + SubCategory);
}
You can find this FIDDLE
Related
I have a table that need to be hidden on page load and then shown after login
So i figured out how to remove the table on login but don't have a clue how to return it
<table class="showAfter">
<tr>
<th></th>
</tr>
</table>
function restart(){
var removeTable = document.querySelector('.showAfter');
while (removeTable.hasChildNodes()) {
removeTable.removeChild(removeTable.firstChild);
}
}
function restore(){
var addTable = document.querySelector('.showAfter');
while (!addTable.hasChildNodes()) {
append?
}
}
Thanks for the help
Here's a super cheap way to do the same.
<table class="showAfter">
<tr>
<th></th>
</tr>
</table>
var savedTable = "": // establish var on the window scope so both functions can access it.
function restart(){
var removeTable = document.querySelector('.showAfter');
savedTable = removeTable.innerHTML;
removeTable.innerHTML = "";
// while (removeTable.hasChildNodes()) {
// removeTable.removeChild(removeTable.firstChild);
// }
}
function restore(){
var addTable = document.querySelector('.showAfter');
addTable.innerHTML += savedTable;
savedTable = "";
// while (!addTable.hasChildNodes()) {
// append?
// }
}
Given an html like this:
<tr>
<th style="padding-right:1em">Location</th>
<td>
<span class="location">Lower reaches of the Geum River, Korea</span>
</td>
</tr>
How do I get Geum_River and Korea?
This is what I am doing at the moment:
countryLinks = doSelect("Location").siblings('td').find('a').attr('href');
function doSelect(text) {
return $wikiDOM.find(".infobox th").filter(function() {
return $(this).text() === text;
});
}
function countryList() {
let pattern = new RegExp('\/wiki\/');
string = countryLinks;
countryListLinks = string.replace(pattern, '');
console.log(countryListLinks);
}
if (doSelect('Location').length > 0 && doSelect('Date').length > 0) {
countryList();
};
I am splitting /wiki/ from the string and it works but I am only getting the first one Geum_River while I would expect all of the <a>s href.
You were only selecting first <a> element .href, .attr() returns a single value. Also second condition at if && doSelect('Date').length > 0 is false given HTML at Question.
You can use .map() and .get() to return an array of <a> element .href values, then pass countryList function to Array.prototype.forEach() to iterate .href values.
The RegExp should also be adjusted to replace all characters up to and including "wiki" '^.+\/wiki\/'.
function doSelect(text) {
return $(".infobox th").filter(function() {
return $(this).text() === text;
});
}
countryLinks = doSelect("Location").siblings('td')
.find('a').map(function(i, el) {return el.href}).get(); // .attr('href');
// we can pass this function to `.forEach()` or `.map()`
function countryList(string) {
let pattern = new RegExp('^.+\/wiki\/'); // adjust `RegExp`
// string = countryLinks;
countryListLinks = string.replace(pattern, '');
console.log(countryListLinks);
}
// the second condition is `false` given HTML at Question
if (doSelect('Location').length > 0 /* && doSelect('Date').length > 0 */) {
countryLinks.forEach(countryList);
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="infobox">
<tr>
<th style="padding-right:1em">Location</th>
<td>
<span class="location">Lower reaches of the Geum River, Korea</span>
</td>
</tr>
</table>
Your main issue is when you call countryLinks = doSelect("Location").siblings('td').find('a').attr('href'); specifically, when you call the last bit .attr('href'); which the docs state this of
Description: Get the value of an attribute for the first element in the set of matched elements.
So basically, you're getting a collection of the links then reducing that collection to just the first element and return it's href attribute.
Here is how I would do this using .map() instead:
var $wikiDOM = $('.some-container');
var links = $.map($wikiDOM.find('td a'),function(link, i){
return (link.href || '').replace(/^.*[\\\/]/, '');
});
console.log(links);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="some-container">
<table>
<tr>
<th style="padding-right:1em">Location</th>
<td>
<span class="location">Lower reaches of the Geum River, Korea</span>
</td>
</tr>
</table>
</div>
you can use jQuery each() to get all the hrefs in a array and then display then one by one using for loop.
Here is the code:
var hrefs = new Array();
jQuery('.location').find('a').each(function() {
hrefs.push(jQuery(this).attr('href'));
});
function countryList() {
let pattern = new RegExp('\/wiki\/');
for(var i=0; i < hrefs.length ; i++){
string = hrefs[i];
var countryListLinks = string.replace(pattern, '');
alert(countryListLinks);
}
}
countryList();
Complete Code, should look somthing like this:
function doSelect(text) {
return $wikiDOM.find(".infobox th").filter(function() {
return $(this).text() === text;
});
}
var hrefs = new Array();
jQuery('.location').find('a').each(function() {
hrefs.push(jQuery(this).attr('href'));
});
function countryList() {
let pattern = new RegExp('\/wiki\/');
for(var i=0; i < hrefs.length ; i++){
string = hrefs[i];
var countryListLinks = string.replace(pattern, '');
console.log(countryListLinks);
}
}
if (doSelect('Location').length > 0 && doSelect('Date').length > 0) {
countryList();
};
var hrefs = new Array();
jQuery('.location').find('a').each(function() {
hrefs.push(jQuery(this).attr('href'));
});
function countryList() {
let pattern = new RegExp('\/wiki\/');
for(var i=0; i < hrefs.length ; i++){
string = hrefs[i];
var countryListLinks = string.replace(pattern, '');
alert(countryListLinks);
}
}
countryList();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<tr>
<th style="padding-right:1em">Location</th>
<td>
<span class="location">Lower reaches of the Geum River, Korea</span>
</td>
</tr>
First of all, I'm going to pop an id onto your span element so that I can locate it easily in my script.
<span id="locations"
Next, I'm going to drop your implementation, and instead, iterate through the child elements of the span with id="locations". Next, I'll get the substring of the href of these elements that we want, and push them to an array.
var locations = document.getElementById("locations").getElementsByTagName('a');
var rawLocations = [];
for (i in locations) {
if (locations[i].href) {
var lastIndex = locations[i].href.lastIndexOf('/') + 1;
rawLocations.push(locations[i].href.substring(lastIndex));
}
}
Now, console.log(rawLocations); gives us what we want:
(2) ["Geum_River", "Korea"]
This was not as easy as I thought:-)
But here we go:
// cache the element, you could do QuerySelectorAll and iterate through the
// node list, but let's keep it simple
var ts = document.querySelector('a');
// This is caching the href attribute from the link
var garbage = ts.href;
// here you take the link and run the native string method
// to find the lastIndexOf, this is great if you suck at regex like myself
var n = garbage.lastIndexOf('/');
Here we extract only the part after lastIndexOf and cache it in "result"
var result = garbage.substring(n + 1);
alert(result);
I'm trying to a way to get the first number value present inside a table (and respective tbody), but it needs to be able to find the value the first number, and ignores all the tags it comes accross until it reaches the number value.
<table id="TableID">
<thead></thead>
<tbody>
<tr></tr>
<tr>
<td></td>
<td>
<div>
<div>
<span>
4031007
</span>
</div>
<div>
<span>
whatever
</span>
</div>
</div>
</td>
<td></td>
</tr>
</tbody>
</table>
in the above example, we would try to find 4031007, which is inside a <span>, but it could've been a <div> or something else. I need this without using JQuery. Any help?
You could do it the plain old way: make a recursive function that will return text of the first node which has a text content:
function findFirstNumber(node) {
// If this is a text node, return its contents. Trim it because there is
// whitespace between the elements that should be ignored
if (node.nodeType == Node.TEXT_NODE)
return node.textContent.trim();
// Iterate over all child nodes and finde the first one that has text in it
for (var child = node.firstChild; child; child = child.nextSibling) {
var content = firstText(child);
if (content && isNumber(content))
return content;
}
// No text found
return '';
}
function isNumber(value) {
return !!isNaN(value);
}
console.log(findFirstNumber(document.getElementById('TableID')));
I used the mdn page about Node to find out how to do this.
see fiddle (open your console)
How about a fancy find function that accepts regular expressions.
function findRegExp(start, reg, mod) {
if (! (reg && start)) return this;
return [].slice.call(start.querySelectorAll('*')).filter(function(elem) {
if (typeof reg == 'string')
reg = new RegExp(reg, mod ? mod : '');
var clone = elem.cloneNode(true),
child = clone.children;
for (var i=child.length; i--;)
clone.removeChild(child[i]);
var txt = clone.textContent.trim();
return reg.test(txt);
});
}
to be used like
var elems = findRegExp(document.getElementById('TableID'), /^\d+$/);
FIDDLE
and the jQuery version
$.fn.findRegExp = function(reg, mod) {
if (!reg) return this;
return this.find('*').addBack().filter(function() {
if (typeof reg == 'string')
reg = new RegExp(reg, mod ? mod : '');
var c = $(this).clone();
c.children().remove();
var txt = $.trim(c.text());
return reg.test(txt);
});
}
Then you can search for an element containing only numbers
$('#TableID').findRegExp(/^\d+$/);
FIDDLE
We have a situation as mentioned below:
There is a set of data for a search panel, it's called in several pages with different types of components and placement of it. There can be combo boxes, radio buttons, input boxes and buttons.
Knockout has a feature of template binding in which we can have the flexibility to show numerous panels on condition using a template in the html mapped to MOdel.
Below is the code and pattern:
HTML:
<div id="content-wrapper">
<div class="spacer"></div>
<div>
<table class="data-table">
<thead>
<tr>
<th colspan="4"> Search </th>
</tr>
</thead>
<tbody data-bind="foreach: preSearchData" >
<tr>
<!-- ko template: { name: 'label_' + templateName()} -->
<!-- /ko -->
</tr>
</tbody>
</table>
</div>
</div>
<script type="text/html" id="label_Combo">
<td>It is a Combo </td>
</script>
<script type="text/html" id="label_Number">
<td>
It is a Number
</td>
</script>
MODEL:
Models.Components = function(data) {
var self = this;
self.number = data.number;
self.labelCd = data.labelCd;
self.xmlTag = data.xmlTag;
self.Type = new Cobalt.Models.Type(data.Type);
};
Models.Type = function(data) {
var self = this;
self.component = data.component;
self.records = data.records;
self.minLength = data.minLength;
self.maxLength = data.maxLength;
self.defaultValue = data.defaultValue;
self.targetAction = data.targetAction;
};
Models.ComponentType = function (paymentTypeCode, data, actionId) {
var ret;
self.templateName(data.component);
if (!data || (actionId === Cobalt.Constant.Dashboard.copyProfile))
data = {};
if (paymentTypeCode == Cobalt.Constant.Dashboard.creditCard)
ret = new Cobalt.Models.CreditCardPaymentType(data.cardHolderName, data.cardNumber, data.cardExpireDate);
else if (paymentTypeCode == Cobalt.Constant.Dashboard.dd)
ret = new Cobalt.Models.DDPaymentType(data.pinNumber);
else if (Cobalt.Utilities.startsWith(paymentTypeCode, Cobalt.Constant.Dashboard.yahooWallet)) {
if (!data && paymentTypeCode.indexOf('~') > -1) {
data.payCode = paymentTypeCode.substr(paymentTypeCode.indexOf('~') + 1, paymentTypeCode.lastIndexOf('~'));
data.billingAgentId = paymentTypeCode.substr(paymentTypeCode.lastIndexOf('~') + 1);
}
ret = new Cobalt.Models.WalletPaymentType(data.payCode, data.billingAgentId);
}
else if (paymentTypeCode == Cobalt.Constant.Dashboard.ajl) {
ret = new Cobalt.Models.DDPaymentType(data.pinNumber);
}
else
ret = data || {};
return ret;
};
Models.POCModel = function () {
var self = this;
self.templateName = ko.observable();
self.preSearchData = ko.observableArray([]);
self.getResultData = function () {
var data = Cobalt.Data.getResultData();
var componentList = data.componentList;
self.preSearchData(componentList);
};
};
Above code gives me a error saying:
Ajax error: parsererror ( Error: Unable to parse bindings. Message: ReferenceError: templateName is not defined; Bindings value: template:
{ name: 'label_' + templateName()} ) cobalt.init.js:66
This is not a direct answer to your question, but it shows an alternate way of doing this using the ViewModel type to find the view (Template)
http://jsfiddle.net/nmLsL/2
Each type of editor is a ViewModel
MyApp.Editors.BoolViewModel = function(data) {
this.checked = data;
};
MyApp.Editors.BoolViewModel.can = function(data) {
return typeof data === "boolean";
};
And it has a can function that determins if it can edit the value
I then usea library called Knockout.BindingConventions to find the template connected to the ViewModel
https://github.com/AndersMalmgren/Knockout.BindingConventions/wiki/Template-convention
Your foreach binding creates a child binding context, which doesn't include templateName since that's part of the parent. Replace it with
<!-- ko template: { name: 'label_' + $parent.templateName()} -->
I want to extract data from an html table like
<table>
<tr>
<th> Header1 </th>
<th> Header2 </th>
<th> Header3 </th>
</tr>
<tr>
<td> Value 1,1 </td>
<td> Value 2,1 </td>
<td> Value 3,1 </td>
</tr>
... rows ...
</table>
and get arrays:
an array for the headers
a 2d array for the column values (or an array for each column)
How can I do this using jQuery?
I don't care to serialize it, or put it into a JSON object because I want to use it to render a chart.
related General design question:
at the moment I have something like
1. ajax query returns html table
2. use jQuery to get values from html table
3. render chart
does it make more sense to throw a JSON object back from the ajax query and then render a table and a chart from there?
demo updated http://jsfiddle.net/ish1301/cnsnk/
var header = Array();
$("table tr th").each(function(i, v){
header[i] = $(this).text();
})
alert(header);
var data = Array();
$("table tr").each(function(i, v){
data[i] = Array();
$(this).children('td').each(function(ii, vv){
data[i][ii] = $(this).text();
});
})
alert(data);
Something like this?
$(function() {
var headers = $("span",$("#tblVersions")).map(function() {
return this.innerHTML;
}).get();
var rows = $("tbody tr",$("#tblVersions")).map(function() {
return [$("td:eq(0) input:checkbox:checked",this).map(function() {
return this.innerHTML;
}).get()];
}).get();
alert(rows);
});
yet another way of doing it
var headers = jQuery('th').map(function(i,e) { return e.innerHTML;}).get();
var datas = []
jQuery.each(jQuery('tr:gt(0)'), function(i,e ) {
datas.push(jQuery('td', e).map(function(i,e) {
return e.innerHTML;
}).get()
);
});
Something along the lines of:
var thArray = new Array();
var contentArray = new Array();
$('th').each(function(index) {
thArray[index] = $(this).html();
})
$('tr').each(function(indexParent) {
contentArray['row'+indexParent] = new Array();
$(this).children().each(function(indexChild) {
contentArray['row'+indexParent]['col'+indexChild] = $(this).html();
});
});
This gives you two arrays, thArray which is an array of your headings and contentArray which is a 2d array containing rows and columns: contentArray['row1']['col0'] returns " Value 1,1"
Actually, contentArray contains the th's as well... referenced 'row0'
does it make more sense to throw a JSON object back from the ajax query and then render a table and a chart from there?
Yes, absolutely. Return JSON in response to your AJAX request, then you can render the table using something like jQuery Templates and use the same underlying data to generate your chart as well.
Here's a modification of Jerome Wagner's answer that uses recursive maps instead of a map inside an 'each':
http://jsbin.com/oveva3/383/edit
var headers = $("th",$("#meme")).map(function() {
return this.innerHTML;
}).get();
var rows = $("tbody tr",$("#meme")).map(function() {
return [$("td",this).map(function() {
return this.innerHTML;
}).get()];
}).get();
I'm tinkering with the same thing over here, but I prefer iterating through all tables and writing the header and body arrays into properties of each table, so here's my modification to the original answer:
$(function() {
$("table").each(function(){
var $table = $(this),
$headerCells = $("thead th", $(this)),
$rows = $("tbody tr", $(this));
var headers = [],
rows = [];
$headerCells.each(function(k,v) {
headers[headers.length] = $(this).text();
$table.prop("headAry", headers);
});
$rows.each(function(row,v) {
$(this).find("td").each(function(cell,v) {
if (typeof rows[cell] === 'undefined') rows[cell] = [];
rows[cell][row] = $(this).text();
$table.prop("bodAry", rows);
});
});
console.log($(this).prop('headAry'));
console.log($(this).prop('bodAry'));
});
});
JSbin
Use this line of code:
var arrays = [];
$('table').eq(0).find('tr').each((r,row) => arrays.push($(row).find('td,th').map((c,cell) => $(cell).text()).toArray()))
I would think it would make more sense to get a json array back from the ajax call and generate your table/chart from that. With jquery templates this isn't hard at all.