To make sure two arrays are the same in Javascript, this is what I do:
(inserting zeroes where there is missing data in item1)
var viewModel = #Html.Raw(Json.Encode(Model));
var items = viewModel.Date1;
var items2 = viewModel.Date2;
items = items2.map( row =>
//is there a matching row in items?
items.filter( r => r.theString == row.theString).length == 0 ?
//if not, fill with zeros
{theString:0, theCount:0} :
//if there is, return the items' row
items.filter( r => r.theString == row.theString)[0] );
I use that data for the barchart as percentages. I need to display the results in table form with the actual count numbers like this:
<div style="padding-top: 30px">
<table id="table_id" class="display">
<thead>
<tr>
<th>Month</th>
<th>Cancelled</th>
<th>Total</th>
</tr>
</thead>
<tbody>
#using (var e1 = Model.Date1.Reverse().GetEnumerator())
{
using (var e2 = Model.Date2.Reverse().GetEnumerator())
{
while (e1.MoveNext() && e2.MoveNext())
{
var item1 = e1.Current;
var item2 = e2.Current;
<tr>
<td>#item1.theDate.Value.ToString("MMMM-yyyy") </td>
<td>#item1.theCount</td>
<td>#item2.theCount</td>
</tr>
}
}
}
</tbody>
</table>
</div>
Problem is that those arrays haven't been fixed to match eachother, so the data it's displaying is incorrect. The dates (theDate) are not matching the values.
Or could I just use items and items2 from the javascript to make a table?
Something like this should work:
#foreach (var item1 in Model.Date1.Reverse())
{
var item2Count = Model.Date2.Where(i2 => i2.theDate == item1.theDate)
.Select(i2 => i2.theCount)
.FirstOrDefault();
<tr>
<td>#item1.theDate.Value.ToString("MMMM-yyyy") </td>
<td>#item1.theCount</td>
<td>#item2Count</td>
</tr>
}
This has the same n² asymptotic complexity as the JavaScript you posted, so if you had a very large number of items there's a chance you'd see slow performance. This could be resolved by creating a lookup of the Date2 values, like so:
#{
var item2CountsByDate = Model.Date2.ToLookup(i => i.theDate, i => i.theCount);
foreach (var item1 in Model.Date1.Reverse())
{
var item2Count = item2CountsByDate[item1.theDate]
.FirstOrDefault();
<tr>
<td>#item1.theDate.Value.ToString("MMMM-yyyy") </td>
<td>#item1.theCount</td>
<td>#item2Count</td>
</tr>
}
}
Related
first I'm sorry if at some point I express myself badly, English is not my native language. I am developing an application in which the user sends 2 values through a form and in another page I use one of those data (string with comma separated options) to show a specific table and hide the others, and with the second data (Integer) I show one of the rows of that table.
What I already have:
I have the form and send the data through the Query String, I capture that data, I assign a variable to the integer and to the text string I separate it by commas and create an array.
URL Example: app.tables.example/?id=123&ops=option1%2c+option2
//Read parameters sent by form
const param = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop)
});
//Assign integer to a variable
let num = param.id;
//Assign options to a variable
let op = param.ops;
//Separate string with commas
let opsplit = op.split(',');
Up to here everything is perfect, I can print all the variables without any problem, now I need to compare the array with the id of each table, show the one that corresponds and hide the others. (The id of the tables is the same that user passes with the text string).
The tables look something like this:
<div id="option1" class="table-1">
<table width="100%">
<thead>
<tr>
<th align="left">Option1</th>
<th align="left">Integer</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Number</td>
<td align="left">Info</td>
</tr>
<tr>
<td align="left">1</td>
<td align="left">textblock</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">textblock</td>
</tr>
</tbody>
</table>
</div>
//As you can see the id of each table corresponds to what the user chose
<div id="option2" class="table-1">
<table width="100%">
<thead>
<tr>
<th align="left">Option2</th>
<th align="left">Integer</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">Number</td>
<td align="left">Info</td>
</tr>
<tr>
<td align="left">1</td>
<td align="left">textblock</td>
</tr>
<tr>
<td align="left">2</td>
<td align="left">textblock</td>
</tr>
</tbody>
</table>
</div>
The problem:
I'm supposed to use the array elements in a "for" loop and compare them with the id of each table, then show that table and hide others, but I don't know exactly how to do it.
function myFunction() {
var input, filter, table, tr, td, i, y, txtValue;
for (r = 0; r<opsplit.length; r++){
input = opsplit[r];
filter = function(x){
return x.toUpperCase();
};
opsplit = opsplit.map(filter);
}
//When I test this, it does not return any value,
//innerHTML error
for(y = 0; y<opsplit.length; y++){
table = document.getElementById(opsplit[y]).innerHTML;
//I use this section to test, it should show me the row,
//but since the previous loop failed, it does nothing.
// What I really need is to show the whole
// table where this data is located and hide the other tables.
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
}
myFunction();
I am really stuck at the moment and would appreciate any help. What is the correct way to use the string array, and how can I hide the tables that the user does not need?
Ok, thanks to those who took the time to write a comment, but I found the solution, I had to convert the form data to a string and an integer. Then I was able to compare that string to the classes id. I am writing the answer in case anyone finds it useful.
//Read parameters sent by form
const param = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop)
});
//Assign number to a variable
let num = param.id;
//Convert to integer
let numint = parseInt(num);
//Assign options to a variable
let op = param.ops;
//Convert to String
let opstr = op.string();
//Separate string with commas
let opsplitstr = opstr.split(',');
//Assign class to a variable
tableclass = document.getElementsByClassName('table-1');
//Compare table class ids with string array
if (opsplitstr[0] == tableclass[0].id{
}
//We need a loop if we need compare all elements
TLDR: The URL does not send information about the data type, so I had to read it and convert it according to my need.
I have a function which its job its to delete a value selected by the user, it loops through an array of selected values and the data, when it iterates through both it checks if the selected value is equal to any property in the data, if it returns true, I get a new array of data.
When I select one value in the checkbox I do indeed see the correct data being returned, but when I select multiple my function does not work. I have being pondering all day, I will really appreciate any input.
HTML
<div class="ibox-content">
<table class="table table-striped">
<thead>
<tr>
<th>Select</th>
<th class="col-xs-3">Issue Description</th>
<th class="col-xs-3 text-center">Category</th>
<th class="col-xs-3 text-center">Jira</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="issue in wiq.data">
<td><input type="checkbox" checklist-model="wiq.selections" checklist-value="issue.jira"> </td>
<td>{{issue.issue}}</td>
<td class="text-center">{{issue.description}}</td>
<td class="text-center">{{issue.jira}}</td>
</tr>
<pre>{{wiq.selections}}</pre>
</tbody>
</table>
<form>
<button type="button" name="button" class="btn btn-success pull-right" style="margin-top:2em;" ng-click="wiq.acknowledge()">Acknowledge</button>
</form>
</div>
Controller.js
ctrl.selections = []
ctrl.data = [
{issue:"CMDY has issue", description:"issue",jira:"CDVR-173"},
{issue:"SPK has issue", description:"issue",jira:"CDVR-125"}
]
ctrl.acknowledge = function() {
var data = [];
for (var i = 0; i < ctrl.data.length; i++) {
for (var j = 0; j < ctrl.selections.length; j++) {
if (ctrl.selections[j] != ctrl.data[i].jira) {
data.push(ctrl.data[i]);
}
}
}
ctrl.data = data;
console.log(ctrl.data)
};
When you have multiple selection, you loop multiple times, so you call "push" too many times.
try :
function filterData(somedata, selections) {
return somedata.filter(item => (selections.findIndex(o => o === item.jira ) == -1));
};
then
ctrl.acknowledge = function() {
ctrl.data = filterData(ctrl.data,ctrl.selections);
console.log(ctrl.data)
};
Simple one liner will solve your problems, try this:
ctrl.acknowledge = function() {
var data = ctrl.data.filter(val => ctrl.selections.indexOf(val.jira) === -1);
ctrl.data = data;
console.log(ctrl.data)
};
Here's jsfiddle:
http://jsfiddle.net/pegla/xj9gqqxn/7/
I'm a beginner at JavaScript and haven't been able to figure this out...
I need to check each row of a table to see if the string "Business Cards" exists in each row. If EVERY row contains this string, I'll proceed with option A, but if even one row doesn't contain the string, I'll stop checking and proceed with option B.
Here is an idea of what the table looks like in HTML (although the number of rows and products in each row will vary, since they're dynamically generated):
<table class="rgMasterTable" border="0" id="ctl00_cphMainContent_dgShippingItems_ctl00" style="width:100%;table-layout:auto;empty-cells:show;">
<thead>
<tr>
<th scope="col" class="rgHeader" style="text-align:center;">Name</th>
<th scope="col" class="rgHeader" style="text-align:center;">No. of Units</th>
</tr>
</thead>
<tbody>
<tr class="rgRow" id="ctl00_cphMainContent_dgShippingItems_ctl00__0" style="text-align:center;">
<td style="width:250px;">
Business Cards - TEST - CA Back
</td>
<td style="width:100px;">
250 Business Cards
</td>
</tr>
<tr class="rgAltRow" id="ctl00_cphMainContent_dgShippingItems_ctl00__1" style="text-align:center;">
<td style="width:250px;">
Business Cards - Joint Venture - TEST
</td>
<td style="width:100px;">
250 Business Cards
</td>
</tr>
</tbody>
</table>
And here's my attempt at the code. I'm trying to make use of the fact that the tr id will always have the index (eg: "ctl00_cphMainContent_dgShippingItems_ctl00__0" for the first row, "ctl00_cphMainContent_dgShippingItems_ctl00__1" for the second, etc), but maybe there's an easier way to do this?
var businessCardItem = 'Business Cards';
var orderItemCount = $('#ctl00_cphMainContent_dgShippingItems_ctl00 tr').length;
var onlyBusinessCards = true;
for (var i = 0; i <= orderItemCount; i++) {
if($('#ctl00_cphMainContent_dgShippingItems_ctl00__' + i).text().indexOf(businessCardItem) >= 0) {
return onlyBusinessCards;
}
else {
onlyBusinessCards = false;
return onlyBusinessCards;
break;
}
}
if (onlyBusinessCards == true) {
//Option A
}
else {
//Option B
}
Any help would be appreciated! Let me know if any more detail or clarification is needed!
Count how many rows contain "Business Cards" and compare to the number of rows:
Note: only count rows within tbody
var table = $("#ctl00_cphMainContent_dgShippingItems_ctl00");
var rows = $("tbody tr",table).length;
var rowsWithBC = $("tbody tr:contains(Business Cards)",table).length;
if( rows == rowsWithBC ) {
// Option A
} else {
// Option B
}
I have an HTML table and I want to iterate through its rows and create a collection or lets say an "array of objects".
For example:
<table id="tbPermission">
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td>1</td>
<td>Test1</td>
</tr>
</table>
I want to create a collection as below:
var trArray = [];
$('#tbPermission tr').each(function () {
var tdArray = [];
$(this).find('td').each(function () {
// I want to create the array of objects here …
tdArray.push();
});
// Final array
trArray.push(tdArray);
});
The arrays may be like below:
tdArray : {'UserID' : '1', 'UserName' : 'Test1'};
and:
trArray : [
{'UserID' : '1', 'UserName' : 'Test1'},
{'UserID' : '2', 'UserName' : 'Test2'}
]
Try this code
var trArray = [];
$('#tbPermission tr').each(function () {
var tr =$(this).text(); //get current tr's text
var tdArray = [];
$(this).find('td').each(function () {
var td = $(this).text(); //get current td's text
var items = {}; //create an empty object
items[tr] = td; // add elements to object
tdArray.push(items); //push the object to array
});
});
Here, I just created an empty object, filled object with references of tr and td, the added that object to the final array.
adding a working jsfiddle
This solution relies on adding thead and tbody elements which is a good idea anyways since it indicates to the browser that the table actually is a "data" table and not presentational.
jQuery has a .map() function. map is a basic function where you take an array and then replace the values with a the return value of a callback function - which results in a new array.
$([1,4,9]).map(function(){ return Math.sqrt(this) });
// [1, 2, 3]
.toArray converts the array like jQuery object we get into a "true array".
jQuery(function(){
var $table = $("#tbPermission");
var headers = $table.find('thead th').map(function(){
return $(this).text().replace(' ', '');
});
var rows = $table.find('tbody tr').map(function(){
var result = {};
var values = $(this).find('>td').map(function(){
return $(this).text();
});
// use the headers for keys and td values for values
for (var i = 0; i < headers.length; i++) {
result[headers[i]] = values[i];
}
// If you are using Underscore/Lodash you could replace this with
// return _.object(headers, values);
return result;
}).toArray();
// just for demo purposes
$('#test').text(JSON.stringify(rows));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="tbPermission">
<thead>
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Test1</td>
</tr>
</tbody>
</table>
<textarea id="test"></textarea>
If you for whatever reason cannot change the HTML you could use the index of the rows to differentiate between headers and rows of data:
var headers = $table.find('tr:eq(0) th').map(function(){
return $(this).text().replace(' ', '');
});
var rows = $table.find('tr:gt(0)').map(function(){
// ...
});
I would suggest changing your html slightly.
<table id="tbPermission">
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td class="userid">1</td>
<td class="username">Test1</td>
</tr>
</table>
Then in your javascript when you want to get all the elements as an array you could do.
var userIdArray = $('#tbPermission .userid').map(function(userid){ return $(userid).html(); }).toArray();
This will find all elements with a class userid on the table, collect just the values, and .toArray() that result to get a basic javascript array. You can then take that and manipulate it into whatever json structure you want, or you could possibly create your json object inside that map function.
Check the console, you will get an array with the desired objects
var arr = [];
$('#tbPermission tr:not(.header)').each(function() {
var that = $(this);
var id = that.find('td').eq(0).text();
var name = that.find('td').eq(1).text();
var obj = { 'userId': id , 'userName': name };
arr.push(obj);
});
console.log(arr);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table id="tbPermission">
<tr class="header">
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td>1</td>
<td>Test1</td>
</tr>
<tr>
<td>2</td>
<td>Test2</td>
</tr>
</table>
It's a bit tricky based on the given structure. You may have to modify the HTML a bit to map cells to headers, like below.
var myArray = [];
$("#tbPermission").find("td").each(function() {
var $this = $(this), obj = {};
obj[$this.data("column")] = $this.text();
myArray.push(obj);
});
alert ( JSON.stringify(myArray) );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="tbPermission">
<tr>
<th>User ID</th>
<th>User Name</th>
</tr>
<tr>
<td data-column="User ID">1</td>
<td data-column="User Name">Test1</td>
</tr>
</table>
Please give in some time to learn about Array.push() and Objects in Javascript. Hope that helps.
I'm a beginner with code,
I'm trying to run on this table and get the text from each .winner class and push it to an Array, so instead of getting:
["aa","aa","dd"]
I'm getting
["aaaadd","aaaadd","aaaadd"]
$(document).ready(function(){
var arr = [];
var winner = $('.winner').text() ;
for ( i = 0; i < $('table').length ; i++ ) {
arr.push(winner);
}
console.log(arr);
});
HTML:
<table>
<tr>
<td>#</td>
<td class="winner">aa</td>
<td>bb</td>
<td>cc</td>
<td>dd</td>
</tr>
</table>
<table>
<tr>
<td>#</td>
<td class="winner">aa</td>
<td>bb</td>
<td>cc</td>
<td>dd</td>
</tr>
</table>
<table>
<tr>
<td>#</td>
<td class="winner">dd</td>
<td>cc</td>
<td>bb</td>
<td>aa</td>
</tr>
</table>
I guess something is wrong with my for loop
var arr = [];
$('table .winner').each(function () {
arr.push($(this).text());
})
Example
or version without class .winner
$('table').each(function () {
arr.push($(this).find('tr').eq(0).find('td').eq(1).text());
});
Example
$('table .winner') - returns 3 td's with class .winner
$(this).text() - get text from current element.
In your example $('.winner').text() returns text "aaaadd", then you get $('table').length (will be 3) and three times push the same text to arr
The sentence
var winner = $('.winner')
will give you an array of objects, so you need to loop each of them and call text() method for each one.
With this:
var winner = $('.winner').text();
You are getting a combined texts from all the td elements marked as winner (see docs here).
Then, for each table, to push this value to the array:
for ( i = 0; i < $('table').length ; i++ ) {
arr.push(winner);
}
This is actually not necessary.
What you want is probably:
var winners = $('.winner');
for (var i = 0; i < winners.length(); ++i) {
arr.push(winners.eq(i).text());
}