HTML input fields contents keep disappearing - javascript

I am building a webpage to monitor my stocks and mark some comments for each stock.
I got the volume and the price of each of the stocks from an api I built and wrote some code to put them into a table.
The table has some other fields as well:
Name, Price, Volume, Comments, Target Price
The comments and target prices contain input fields which I can type in some notes for each stock.
However, my code builds a new table every 10s to update the stock prices and volume, and after each sort action which is triggered by pressing the corresponding heading I want to sort by. After this, my inputs fields contents will disappear. Is there a way to keep these contents intact after an update or a sorting is triggered?
<script
src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<table class="table table-striped" style="float: left; width: 60%">
<tr class="bg-primary">
<th data-column="name" data-order="dsc">Name &#9650</th>
<th data-column="price" data-order="dsc">price &#9650</th>
<th data-column="volume" data-order="dsc">Volume &#9650</th>
<th data-column="targetPrice" data-order="dsc">Target Price &#9650</th>
<th data-column="comments" data-order="dsc">Comments &#9650</th>
<th data-column="submit" data-order="dsc">Send &#9650</th>
</tr>
<tbody id="myTable">
</tbody>
</table>
<script>
var myArray = []
var sortOrder = 'name'
var sortColumn = 'dsc'
setInterval(function() {
$.ajax({
method:'GET',
url:'http://127.0.0.1:5000',
success:function(response){
myArray = response.data
if(sortOrder == 'dsc'){
myArray = myArray.sort((a,b) => a[sortColumn] > b[sortColumn] ? 1 : -1)
}else{
myArray = myArray.sort((a,b) => a[sortColumn] < b[sortColumn] ? 1 : -1)
}
buildTable(searchTable(myArray))
}
})
}, 10000)
function buildTable(data){
var table = document.getElementById('myTable')
table.innerHTML = ""
for (var i = 0; i < data.length; i++){
var row = `<tr>
<td>${data[i].name}</td>
<td>${data[i].price}</td>
<td>${data[i].volume}</td>
<td><input type="number" name="${data[i].symbol}_targetPrice" style='width:60px;'></td>
<td><input type="number" name="${data[i].symbol}_comments" style='width:60px;'></td>
<td><input type="submit"></td>
</tr>`
table.innerHTML += row
}
}
</script>
The submit button is to send back the name, target price and comments as a dictionary back to the server, which I'm still figuring out how to do, however, the problem of the field contents disappearing is a much larger problem. Thanks in advance.

I think that your problem is in the UX more than in the code.
Re-building the HTML containing input elements every 10 seconds is a bad idea because:
You're going to lose focus of the input that you're typing in.
It's going to be overridden with the new data. (the problem you're facing)
It's confusing that inputs that you don't change get updated automatically.
To me it makes more sense to have a table with all the data (but no inputs), that can be updated every 10s. And an edit button that when is clicked shows a form with the inputs that won't update while you're typing.

Related

How to assign unique id to checkboxes which correspond to its row number (update: or item ID) under Bootstrap 4?

I'm designing a table to display transaction history for baby items for a javascript course. How to assign each checkbox with unique id composed of number sequence corresponding to row number?
The wireframe is shown below.
Each row is numbered in sequence, starting from 1 to the end of the table row.
In the rightmost column, with the help of Bootstrap 4, I put a toggle checkbox, so that the user can manually choose whether to list his / her item for sale ('listing') or end the sales ('ended').
I've been told that each checkbox id has to be unique, so I intend to name the input-id of each one 'toogle1', 'toogle2', etc, according to their respective row number.
My question is: how to auto-generate the id number?
I did a similar exercise for the row number, with the following code:
HTML:
<table id="table" data-toggle="table" data-height="800" data-pagination="true" data-page-size="3">
<thead>
<tr>
<th data-field="seq-number" data-width="100" data-width-unit="px">Number</th>
</tr>
</thead>
</table>
JavaScript:
var table = document.getElementsByTagName('table')[0],
rows = table.getElementsByTagName('tr'),
text = 'textContent' in document ? 'textContent' : 'innerText';
for (var i = 1, rowlength = rows.length; i < rowlength; i++) {rows[i].children[0][text]= i;
}
On the other hand, my code for the table and checkbox is as follows:
<table id="table" data-toggle="table" data-height="800" data-pagination="true" data-page-size="3">
<thead>
<tr>
<th data-field="status" data-width="200" data-width-unit="px">Status</th>
</tr>
</thead>
<tr>
<td>
<input type="checkbox" id="toggle1" data-width="100">
<script>
$(function () {
$('#toggle1').bootstrapToggle({
on: 'Listing',
off: 'Ended'
});
})
</script>
</td>
</tr>
I expect the input id (ie. toggle1, toggle2,..., toggle999) can be generated and assigned automatically, corresponding to the row number.
I expect the end result with id = "'toggle' + i".
Thank you very much for your help.
Update: #cengiz sevimli reminds me that it might better to assign status checkbox id with item ID, since it is 'more unique' than row numbers. But how to create the id, say a product of user id #000001 with timestamp - 000001-201910301600, for example?
Let me say that you don't really need to assign a unique id to any checkbox, you could pick any information you need directly from the html in the selected row.
Anyway, if you would like to have an id for the selected items (just these will be submitted with your form), you could set the id to each input in the table (not the selectAll):
$(".cb input").each(
(index, el) => {
// If the checkbox is not the "Select All"
if($(el).attr("name") === "btSelectItem") {
// Choose an ID
let newId = $(el).closest("tr").find(".number").text();
// Set it to the current checkbox
$(el).prop("id", newId);
}
}
)
In order to simplify the selection of the checkboxes in your table, you could add a class to the checkbox column (ie: class="cb"):
<th data-field="cb" data-checkbox="true" class="cb" />
So as you can see above, you could attach a listener to the event change to the input under the elements with class="cb".
See the following complete example, please:
var $table = $('#table');
var mydata =
[
{
number: 1,
id: "Item 1",
name: "Name 1"
},
{
number: 2,
id: "Item 2",
name: "Name 2"
},
{
number: 3,
id: "Item 3",
name: "Name 3"
}
];
$(function () {
$('.table').bootstrapTable({
data: mydata
});
$(".cb input").each(
(index, el) => {
if($(el).attr("name") === "btSelectItem") {
let newId = $(el).closest("tr").find(".number").text();
$(el).prop("id", newId);
}
}
).change(
function() {
let selected = $(this);
if(selected.attr("name") === "btSelectItem") {
console.log("Selected: ", selected.prop("id"));
}
}
);
});
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.1/bootstrap-table.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.10.1/bootstrap-table.min.js"></script>
<div class="container">
<div class="row">
<div class="col-12">
<table class="table table-bordered">
<thead>
<tr>
<th data-field="cb" data-checkbox="true" class="cb" />
<th data-field="number" class="number">Number</th>
<th data-field="id">Item ID</th>
<th data-field="name">Item Name</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
I hope it helps you, bye.
Using class names is more appropriate in this case. When you create a class in CSS, you can add this class to any HTML tag you want. This way you can increase your code's readablitiy, reusability and flexibility. But if you are asking a code snippet in JS that generates a unique id see the code below:
// Generate unique IDs for use as pseudo-private/protected names.
// Similar in concept to
// <http://wiki.ecmascript.org/doku.php?id=strawman:names>.
//
// The goals of this function are twofold:
//
// * Provide a way to generate a string guaranteed to be unique when compared
// to other strings generated by this function.
// * Make the string complex enough that it is highly unlikely to be
// accidentally duplicated by hand (this is key if you're using `ID`
// as a private/protected name on an object).
//
// Use:
//
// var privateName = ID();
// var o = { 'public': 'foo' };
// o[privateName] = 'bar';
var ID = function () {
// Math.random should be unique because of its seeding algorithm.
// Convert it to base 36 (numbers + letters), and grab the first 9 characters
// after the decimal.
return '_' + Math.random().toString(36).substr(2, 9);
};
source: gordonbrander

How to loop over a elements that are members of a class to get data and turn that data into an object?

I have an odd case where I need to loop with Javascript over HTML elements with class name ui-selected to grab the data associated with that class and insert the grabbed data into an object's attributes for further data manipulation. The whole goal of this ideally is so when some clicks on several different rows on a HTML table they can download the selected rows into a CSV file.
My train of thought was that I need to create an object with arrays as attributes and loop over my class name, get the data, insert the data into an array and then insert that array as an object's attribute. I hope this isn't a completely flawed way of thinking and makes sense. My issue is that I am not really sure on how to do this. I am familiar with looping over 2D arrays, but not something like this where it would require multiple looping if I understand correctly.
Here is what I have so far using jQuery, but I will probably try to opt out of jQuery:
$('#downloadBtn').click(function() {
$('.ui-selected').each(function(index, value) {
$(value).find('td').slice(0,2).each(function(i, v) {
var tdText = $(v).text();
if([0,1].indexOf(i) > -1) {
copyText += tdText + ',';
if([0,1].indexOf(i) == 1) {
copyText += '\n';
}
}
});
});
console.log("CopyText : " + copyText)
});
Basically an easy way to think of what I am trying to accomplish is I need a functionality where I can select multiple rows within a HTML table, and when I click download it should grab only the "selected" rows and turn them into a CSV file to then be downloaded.
Here is basically what the table would look like in HTML (I am using the DataTable library from jQuery):
<table id="icpTable" class="cell-border " width="95%" align="center" style="margin-top: 20px;">
<thead>
<tr>
<th>
<strong>Customer Name</strong>
</th>
<th style="width: 20%">
<strong>Tester Note</strong>
</th>
<th>
<strong>Crucible No.</strong>
</th>
<th>
<strong>Dry Weight</strong>
</th>
<th>
<strong>Wet Weight</strong>
</th>
<th>
<strong>Moisture</strong>
</th>
<th>
<strong>Corrected WW</strong>
</th>
<th>
<strong>Volume</strong>
</th>
<th>
<strong>Dilution</strong>
</th>
</tr>
</thead>
<tbody>
<tr>
<td>Example Customer Inc.</td>
<td>SL-001-01-01</td>
<td>123~01~01</td>
<td>1.0000</td>
<td>1.1233</td>
<td></td>
<td>1.012</td>
<td>0.02</td>
<td>0.0001</td>
</tr>
<tr>
<td>Example Customer2 Inc.</td>
<td>SL-002-01-01</td>
<td>124~01~01</td>
<td>1.0000</td>
<td>1.1233</td>
<td></td>
<td>1.012</td>
<td>0.02</td>
<td>0.0001</td>
</tr>
</tbody>
</table>
I really only need tow columns from the table. Tester Note and Customer Name respectively. So the CSV would be something like this:
2018-18-10, 'Sample','Standard', 'test', (Customer Name),(Tester Note), 0.2,'','Tester','A1'
Edit:
I've been playing with this and this is what I have so far:
$('.ui-selected').each(function(index, value) {
var row = table.insertRow(-1);
$(value).find('td').each(function(i, v) {
var tdText = $(v).text();
console.log(tdText)
});
});
So this at least gets me the individual pieces of data. Now I just need to grab the first and second piece only and assign that to a variable.
Here is what I get in my console.log:
Example corp.
Example-066-1-S2
1~1~1
1.0003
1.0150
0.9993
100
100.0686
$('#downloadBtn').click(function() {
let csv = "Customer Name, Tester Note\n";
let elementarray = document.getElementsByClassName('ui-selected');
for (i = 0; elementarray.length > i;i++) {
var dataTags = elementarray[i].getElementsByTagName('td');
var dataArr = [];
dataArr.push(dataTags[0].innerText.trim());
dataArr.push(dataTags[1].innerText.trim());
csv += dataArr.join(', ') + "\n";
}
var a = document.createElement("a");
a.href = "data:text/csv;charset=utf-8,"+ encodeURI(csv);
a.download = "data.csv";
a.click();
});
Here try this.
Here is the output i get.

Protractor - How to get all cells from one column and sum them when the Grid has id="0-0" for rows-Columns

I am validating a drill down process in the portal i am testing, for this my script is doing:
Read the value from the first row of a table and click at this value (there is a link for certain cells that perform the drill down to the detail page)
To click at this particular cell I am using it's ID:
<table id="transHistTable" class="table table-hover table-bordered table-striped dataTable no-footer" style="width: 100%" role="grid" aria-describedby="transHistTable_info">
<thead>
<tbody>
<tr role="row" class="odd">
<td id="0-0" class="ng-scope">31 Jul 2018</td>
<td id="0-1" class="ng-scope">RandomText0</td>
<td id="0-2" class="ng-scope">RandomText1</td>
<td id="0-3" class="ng-scope">EmptyValue</td>
<td id="0-4" class="ng-scope">Value I Click And Save it</td>
So for this table I am clicking directly to the row 0 column 4 since my data and my filters will always bring only one row, but then, comes my problem....
When the drill down is performed I never know how many rows I will have since it depends of user operations.
I need to perform a validation to compare the sum of all the values from the table displayed after the drill down with the value captured from table "transHistTable" row 0 column 4
This is the values I get after performing the Drill Down:
<table id="transHistDetailTable" class="table table-hover table-bordered table-striped dataTable no-footer" style="width: 100%" role="grid" aria-describedby="transHistDetailTable_info">
<thead>
</thead>
<tbody><tr role="row" class="odd">
<td id="0-0" class="ng-scope">Site</td>
<td id="0-1" class="ng-scope">Date</td>
<td id="0-2" class="ng-scope">Time</td>
<td id="0-3" class="ng-scope">I</td>
<td id="0-4" class="ng-scope">value 1</td>
<td id="0-5" class="ng-scope">value 2</td>
<td id="0-6" class="ng-scope">value 3</td>
<td id="0-7" class="ng-scope">12</td>
</tr></tbody>
</table>
So what I would like to do is reading all the rows (could be 0,1,2,3,4,5...) saving the value that is stored in Column 7 then after this is done, perform a sum and then comparing with the value I have saved from the first table.
My code is this one:
var rowstransHistDetail = element(by.id('transHistDetailTable')).all(by.tagName("tr"));
rowstransHistDetail.count().then(function(rcount){
//In case only 1 row is displayed
if (rcount < 3)
{
element(by.id('0-7')).getText().then(function(valueQty){
expect(valueQty).toEqual(600)
})
}
else
{
var tempValue
for (i=0; i < rcount; i++)
{
element(by.id(i+'-7')).getText().then(function(valueQty){
tempValue = Number(tempValue) + Number(valueQty)
})
}
expect(tempValue).toEqual(600);
}
});
But when I execute this, gives me a undefined value
Any ideas how to solve this please?
Thank you!!!!
It seems that you are incrementing a value in a loop before execution.
See here: https://stackoverflow.com/a/6867907/6331748
Should bee i++ instead of ++i in a loop.
Drop me a line if I'm wrong.
===========================
Edited:
Here's some code from my side:
var expectedCells = element.all(by.css('#transHistDetailTable tr td:nth-of-type(5)'));
var currentSum = 0;
expectedCells.each((eachCell) => {
eachCell.getText().then((cellText) => {
currentSum += Number(cellText);
});
}).then(() => {
expect(currentSum).toEqual(600);
});
Sorry, but wasn't able to test it. I only want to share a main idea and elaborate it.
expectedCells are all id=n-4 cells. We go through all elements and get text from them, change to the number type and add to current value. Aftermath we do an assertion.
It also looks that if statement is not necessarily.
Let me know how it works.
Two options for your issue:
1) using element.all().reduce()
let total = element
.all(by.css('#transHistDetailTable > tbody > tr > td:nth-child(8)'))
.reduce(function(acc, item){
return item.getText().then(function(txt) {
return acc + txt.trim() * 1;
});
}, 0);
expect(total).toEqual(600);
2) using element.all().getText() and Array.reduce
let total = element
.all(by.css('#transHistDetailTable > tbody > tr > td:nth-child(8)'))
.getText(function(txts){ //txts is a string Array
return txts.reduce(function(acc, cur){
return acc + cur * 1;
}, 0);
});
expect(total).toEqual(600);

How do I get specific values from checked rows in MVC razor view?

Ok, so I have this partial view (part of an MVC application) which just displays data from a view in the database.
#model IEnumerable<TransportPlanner.Models.TRANSPORT_PLANNER_VIEW>
<table>
<tr>
<th>#Html.CheckBox("HeaderCheck")</th>
<th>#Html.DisplayNameFor(model => model.Status)</th>
....
<th>#Html.DisplayNameFor(model => model.Volume)</th>
<th>#Html.DisplayNameFor(model => model.Weight)</th>
....
</tr>
#foreach (var item in Model) {
<tr>
<th>#Html.CheckBox("RowCheck")</th>
<td>#Html.DisplayFor(modelItem => item.Status)</td>
....
<td>#Html.DisplayFor(modelItem => item.Volume)</td>
<td>#Html.DisplayFor(modelItem => item.Weight)</td>
....
</tr>
}
</table>
I want to be able to find a way in which I can get the values for the Volume and Weight fields of only the checked rows (after checking them), and add them to get the total (which is displayed but not stored).
For example, once I get the results displayed on screen, and I check 3 rows (having the values of 'weight' as 5, 10 and 15), then value displayed should be '30' (sum of the weights). Similarly, if I remove the checkbox for the row having weight as '5', then the value displayed should be '25'.
My front end skills are almost non-existent, and I have scourged over the internet for nearly 12 hours but not found a way to do it. I know that I need to either use JavaScript (or some flavour of it like JQuery) or Ajax (if I need the values updates dynamically as I check/uncheck them).
What is the best way to achieve this, without updating my model? I don't have the luxury of time because I am the only developer at my workplace, and this is the first step of a huge task I need to complete in 3 weeks.
Your #Html.CheckBox("RowCheck") is generating invalid html (duplicate id attributes). Replace it with
<input type="checkbox" class="checkbox" />
Then add class names to the <td> elements for Volume and Weight
<td class="volume">#Html.DisplayFor(modelItem => item.Volume)</td>
<td class="weight">#Html.DisplayFor(modelItem => item.Weight)</td>
And assuming you want to display the totals in the table footer, add the following html to the <table> element (note you should also use the <thead> and <tbody> in your table
<table>
....
<tfoot>
<tr>
<td></td>
....
<td id="totalvolume"><td>
<td id="totalweight"><td>
....
</tr>
</tfoot>
</table>
Then you can use javascript/jquery to handle the change event of the checkboxes, and sum the values in each row. Using jquery:
$('.checkbox').change(function() {
var totalVolume = 0;
var totalWeight = 0;
var selected = $('.checkbox:checked'); // get the selected checkboxes
$.each(selected, function(index, item) { // loop through the selected checkboxes
var row = $(this).closest('tr'); // get the containing tr element
totalVolume += Number(row.find('.volume').text());
totalWeight += Number(row.find('.weight').text());
})
// display the totals
$('#totalvolume').text(totalVolume);
$('#totalweight').text(totalWeight);
});
Note, the above code assumes the values of properties Volume and Weight are numeric (without any formatting)

How to display dynamically added form elements in a table in a different webpage when the data is saved in local storage using purely javascript?

I'm doing a school project in which I'm creating webpages to allow users to input and then display it on another page. I am only using javascript, html and css for the webpages.
On the Create An Event page is a form. I have saved all the input into local storage but now I am unsure on how to retrieve the data to display in on another page called Event History. Here are my codes:
function saveToStorage() {
var nameofevent=document.getElementById("name").value;
var pList=document.getElementsByName("pos");
var positions=[];
for (i=0; i<pList.length; i++){
positions.push(pList[i].value);
console.log(pList[i].value);
}
//for (i=0; i<positions.length; i++){
//console.log(positions[i].value);
//}
var venue= document.getElementById("venue").value;
var date=document.getElementById("date").value;
var starttime=document.getElementById("timeStart").value;
var endtime=document.getElementById("timeEnd").value;
var contact=document.getElementById("contact").value;
var email=document.getElementById("email").value;
var desc=document.getElementById("desc").value;
var one={"name":nameofevent,"pos":positions,"venue":venue,"date":date,"timeStart":starttime,"timeEnd":endtime,"contact":contact,"email":email,"desc":desc};
localStorage["CreateEvent"]=JSON.stringify(one);
return false;
}
Whenever the user submits the Create An Event form, the data that the user inputs will be displayed in a table in another page. Here are my codes for the table:
<h1>Events Created</h1>
<table border="1px" id="tab">
<thead>
<tr style=" font-size: 30px">
<th id="event">Name of event</th>
<th>Positions</th>
<th id="">Venue</th>
<th>Date</th>
<th>Start Time</th>
<th>End Time</th>
</tr>
</thead>
<tbody>
<tr>
<td>eg. Name</td>
<td>eg. Position1, position2</td>
<td>eg. venue</td>
<td>eg. date</td>
<td>eg. start time</td>
<td>eg. end time</td>
</tr>
</tbody>
var saved=JSON.parse(localStorage.getItem("createEvent"));
alert(saved.name);
//etc
You can simply read from the localStorage in the same way, you wrote to it.
You could add this function to your js:
function loadEvents() {
//get the JSON Object from local storage
var event = JSON.parse(localStorage["CreateEvent"]);
//get the first row in the table
var firstRow = document.querySelector('table tbody tr');
//get the single tds
var eventName = firstRow.querySelector('td:nth-child(1)');
//put the data into the tds
eventName.innerHTML = event.name;
}
Call this function with <body onLoad="loadEvents()"in your View Events page.
Make sure you add the <script /> to the file.
This way it is very cumbersome to select the child nodes, so maybe you would want to put some classes in your markup.

Categories

Resources