dynamically convert table values on loading - javascript

I have a html table that lists data from data from a database. One of the entries is the file size in bytes. I want to display the value in the appropriate kb/mb/gb values.
I found a script here to make the conversion.
Below is my attempt at implementing the script, however it is not working.
The desired end state is to have a value like 3597671 Bytes display as 3.43 MB.
<script>
function SizeSuffix(a, b = 2, k = 1024) { with (Math) { let d = floor(log(a) / log(k)); return 0 == a ? "0 Bytes" : parseFloat((a / pow(k, d)).toFixed(max(0, b))) + " " + ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][d] } }
function setSize(size, id) {
document.getElementById(id).innerText = SizeSuffix(size);
}
window.onload = function () {
var sizedata = document.getElementsByName("Size");
for (size in sizedata) {
bytes = size.innerText;
setSize(bytes, size.id);
}
}
</script>
#foreach (var History in Model)
{
<tr>
<td>#History.Date</td>
<td>#History.Path</td>
<td>#History.File</td>
<td name="Size" id="#History.Id">#History.FileSize</td>
</tr>
}
EDIT: I came up with a different solution. I am working with a partial view in razor pages. What I've done is pass the page model of the page that calls the partial view. I included a function in that page model that performs the transformation.
I replaced the line
<td name="Size" id="#History.Id">#History.FileSize</td>
with
<td>#Model.SizeSuffix((ulong)History.FileSize)</td>
and removed the script block. This performs the calculation when ever the partial view is loaded and supports the infinite scrolling code.

Related

Laravel - JS [ajax] Var must be constant

i will be happy if someone know how to do this and why i m getting error , i would like to pass "var size" inside route() method inside forelse is it somehow passible ?
whot it do ?
based on radio box ( if size M and L are avaible there will be 2 radioboxes ), then if user click on add to card it gets Value of radio box for example ( 6 ) = L them pass it to ajax route
Error :
Use of undefined constant size - assumed 'size' (View: C:\xampp\htdocs\EcSc\resources\views\shop\home.blade.php)
JS :
<script>
var CartCount = {{ Session::has("cart") ? Session::get("cart")->totalQty : "0" }} ;
var size;
#forelse($products as $productsjs)
$("#product-{{$productsjs->id}}").click(function () {
var radios{{$productsjs->id}} = document.getElementsByName('radio-{{$productsjs->id}}');
for (var i = 0, length = radios{{$productsjs->id}}.length; i < length; i++) {
if (radios{{$productsjs->id}}[i].checked) {
// do whatever you want with the checked radio
size = radios{{$productsjs->id}}[i].value;
// only one radio can be logically checked, don't check the rest
break;
}
}
$.ajax({
type: "get",
url: "{{route("product.addToCartAjax", $productsjs->id, size)}}", // insert product with specific size into session
success: function () {
CartCount++;
$("#shoppingCartCounter").html(CartCount);
console.log("Produkt bol pridani");
console.log("Velkost produktu je : " + size); // size contain value of checked radio box
}
})
});
#empty
#endforelse
</script>
You can't print the javascript variable in PHP. Think of {{ }} as <?php ?>. If you just insert it in there, it may look like <?php echo size; ?> which won't work, as obviously size will look like a constant here, which of course is undefined (your error).
Instead, you need to declare the variable in php. However, since you're doing this after run time, there's no way that you're going to be able to assign a PHP variable after the page has been rendered. So what are your alternatives?
1 - Construct the route manually: (recommended, easiest)
url: '/products/' + {{$productsjs->id}} + '/add-to-cart-ajax/' + size
2 - Use a client side route generator for Laravel, such as La Route (harder, but more dynamic and reusable)
laroute.route('product.{id}.addToCartAjax.{size}', {id: '{{$productsjs->id}}', size: size});
3 - Other generic solutions such as generating the route ahead of time and dynamically modifying it with javascript (ugly, non-portable)

For Loop in MVC 4 From JavaScript value

How can I make a repeater type in the page. In the page I have a quantity field:
<td>
#Html.DisplayNameFor(x => x.Quantity)
#Html.ValidationMessageFor(x => x.Quantity)
</td>
<td>
#Html.TextBoxFor(x => x.Quantity, new { #id = "txtQty" })
</td>
When I want to add the item, which there could be several of the same item, just different serial numbers, I need to pop open a div with repeated fields for entering serial numbers:
for (int I = 0; I < *****; I++)
{
<td>Serial Number:</td>
<td>#Html.TextboxFor(x=>x.Quantity, new { #id = "txtQty" + 1})
}
In the JS:
function AddItem() {
Qtys = parseINT($("#txtQty").val());
$("#divSerials").show();
}
How can I do this? Is there a better way?
Is this the way to do it? I try this but 'i' in the HTML model statement is not recognized.
if (parseInt($("#txtQuantity").val()) > 0) {
$("#divSerialNumbers").show();
var html = "<table>";
for (i = 1; i <= serialquantity; i++) {
html += "<tr><td>Serial Number:" + #Html.TextAreaFor(x => x.SerialNumber, new { id = "sns" + i }) + "</td></tr>";
}
html += "</table>";
$("#divSerialNumbers").html(html);
}
Razor code is parsed on the server before it is sent to the view. Javascript is client side code and is not executed until the browser receives the view. This line of code
#Html.TextAreaFor(x => x.SerialNumber, new { id = "sns" + i })
means that on the server you are trying to generate a textarea and set the id attribute to a value that includes a javascript variable which does not yet exist.
Its unclear even what the point of this would be. id attributes serve as selectors in javascript. Whats important is the name and value attributes when it comes to posting your data, and even if it could work, your generating duplicate name attributes which could not bind to you models collection property on post back.
For dynamically generating the html for collections, your name attributes need an indexer, for example <input type="text" name="[0].SerialNumber" />. Options for dynamically creating the html include using the BeginCollectionitem() helper, or a pure client side approach is shown in this answer
If all you are doing is post back an array of strings (the serial numbers) then you could use
var div = $("#divSerialNumbers"); // cache it
$('#Quantity').change(function() { // assumes you remove the pointless 'new { #id = "txtQty" }'
var quantity = parseInt($(this).val()); // use $(this) - don't traverse the DOM all over again
if (!isNan(quantity) && quantity > 0) { // must check for NAN
// note it does not seem necessary to use a table, as opposed to simply adding 4 inputs to the div, but
div.empty(); // clear existing contents
var table = $('</table>');
for (i = 1; i <= quantity; i++) {
var input = $('<input>').attr('name', 'SerialNumber');
var cell = $('</td>').append(input);
var row = $('</tr>').append(cell);
table.append(row);
}
div.append(table).show(); // add the table and display it
}
})
and your controller would need a parameter string[] SerialNumber, for example
public ActionResult Edit(string[] SerialNumber)

difficulty getting list of values from series of input elements inside table rows

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.

How do we set the value of an HTML element using Jquery and ASP.NET MVC 4 complex model data

In one of my ASP.NET MVC 4 view, I am using a Model's data to set the values of different HTML elements. I can use this model in the view to display the values such as:
<div>#Model.Category.Name</div> etc...
But one of the div tag <div id="DivTotalCost"></div> needs to display the total cost of all the products in all the categories. So at the end of the view I have the following script code to set the value of this DivTotalCost tag. But the following code does not set this value. I have put an alert statement to test the value and the alert displays:
function(){
return total;
}
View:
#model MyMVC_app.Models.ProductDetails
<div>#Model.Category.Name</div> etc...
<div id="DivTotalCost"></div>
#section scripts{
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/jqueryui")
<script type="text/javascript">
$(document).ready(function () {
var TotalCost = function () {
#if(Model.ProductCategoryList != null)
{
var total = "";
foreach(var item in Model.ProductCategoryList)
{
foreach(var product in #item.products)
{
total += product.price;
}
}
}
return total;
}
alert(TotalCost);
$('#DivTotalCost').text(TotalCost);
});
</script>
}
Please help.
Thanks..Nam
First:
The alert displays
function(){
return total;
}
because you're passing the function itself, no its result. Your alert (and the div text assignment)should use the function result, like this
alert(TotalCost());
now, inside the function you're mixing razor and javascript, and both are different things and run in a different time each, so you should adjust your code like this (not tested, but you might get the idea)
$(document).ready(function () {
var TotalCost = function () {
#{
var total = 0;
if(Model.ProductCategoryList != null)
{
foreach(var item in Model.ProductCategoryList)
{
foreach(var product in #item.products)
{
total += product.price;
}
}
}
}//end of razor block
return #total;
}
});
You can also create a ViewModel and add that logic on it, just in case you're open to try a different approach

split a big HTML page to pages on client side

I have a huge HTML page which is mainly a form which is mostly like this:
<FIELDSET id= '1'>
<TABLE>
<TR> </TR>
</FIELDSET>
</TABLE>
.
.
.
<FIELDSET id= 'n'>
<TABLE>
<TR> </TR>
</TABLE>
The number of fieldsets are generated by dynamically on the server.
Question: On the client side I want to do a pagination for this huge page, so that only say,3 fieldset appear per page on the client.
I don't want to change the way page is loading or form is being submitted currently.
Well just a little tips you may use
$('fieldset')
document.querySelectorAll('fieldset')
will return you fields
in order to get show only i .. i+3 fieldsets you can use
var i = 3
$('fieldset').hide().each(function ( index, el) {
if (index >= i && index < i+3) $(el).show()
})
var fieldsets = [].slice(document.querySelectorAll('fieldset'))
for (var index in fieldsets) {
var display = index < i && index >= i+3 ? 'none' : ''
fieldsets[index].style.display = display
}
Pagination won't really help you in any way other than visual if done on the client side (no speed increases, load reductions, etc), but if that's what you want you can do it with DOM manipulation. Something like the following might work for you:
var i=0,sets=document.getElementsByTagName('fieldset'),len=sets.length;
for(;i<len;i+=3) {
// wrap sets[i] through sets[i+2], as long as they exist, in a div
// if i !== 0, hide or minimize the div
}
// add controls to unhide/unminimize each div

Categories