MVC razor display element that can be edited by javascript - javascript

I'm working with a table that I would like to have display text but also have that text updated by javascript.
I can create a readonly textbox and have javascript edit that, but I would rather just have some text on the screen. Here is a sample that has a DisplayFor which displays text and a readonly textbox which shows the same text.
#for (var i = 0; i < Model.ProjectSubmissions.Count; i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model.ProjectSubmissions[i].ChapterNumber)
</td>
<td>
#Html.TextBox("recordsToSort[" + i + "].ChapterNumber", Model.ProjectSubmissions[i].ChapterNumber, new { #id = "recordsToSort[" + i + "].ChapterNumber", #class = "SortOrder", #readonly = "readonly" })
</td>
</tr>
}
My javacript can edit the textbox like this:
$(".sortable-table tr").each(function (index, element) {
var hiddenInput = $(element).find(".SortOrder").first();
hiddenInput.val(index);
});
Can I write javascript that will update the DisplayFor? Or should I use a different element than DisplayFor that javascript can update?
UPDATE:
I'd like to end up with something like this (I would like to keep the hidden .SortOrder element.):
#for (var i = 0; i < Model.ProjectSubmissions.Count; i++)
{
<tr>
<td>
<span id="#Html.Id("recordstosort[" + i + "].ChapterNumber")" class="SortOrderDisplay">#Model.ProjectSubmissions[i].ChapterNumber</span>
#Html.Hidden("recordsToSort[" + i + "].ChapterNumber", Model.ProjectSubmissions[i].ChapterNumber, new { #id = "recordsToSort[" + i + "].ChapterNumber", #class = "SortOrder" })
</td>
</tr>
}
And javascript like this:
$(".sortable-table tr").each(function (index, element) {
var hiddenInput = $(element).find(".SortOrder").first();
hiddenInput.val(index);
var displayInput = $(element).find(".SortOrderDisplay").first();
if (displayInput !== 'undefined') {
displayInput.text = index;
}
});
But this isn't working.

You can use jQuery text instead of val.
#for (var i = 0; i < Model.ProjectSubmissions.Count; i++)
{
<tr>
<td class="SortOrder">
#Html.DisplayFor(modelItem => Model.ProjectSubmissions[i].ChapterNumber)
</td>
</tr>
}
Then the javascript would be
$(".sortable-table tr").each(function (index, element) {
var hiddenInput = $(element).find(".SortOrder").first();
hiddenInput.text(index);
});

Javascript can be used to update any element you like. The easiest way would probably be to create a span with an id property and then use document.getElementById.innerText to set the text.
You can easily replace the #Html.DisplayFor with a <span id="#Html.IdFor(m => m.ProjectSubmissions[i].ChapterNumber)"></span>.
This only an example, and there are several ways to go about changing text client-side.

Related

How to add and subtract numbers via JavaScript in an HTML table

I want to add numbers in <td></td> below via JavaScript. For example using the following description:
<td id='last'> + formatNumber(data.tickers[key].last) + </td>
<td id='high'> + formatNumber(data.tickers[key].high) + </td>
<td id='low'> + formatNumber(data.tickers[key].low) + </td>
How do I change the text of table data elements via JavaScript?
<td id='new1'> = + <td id='last'> + <td id='high'> + </td>
<td id='new2'> = + <td id='high'> + <td id='loww'> + </td>
Try this:
// these target the cell elements
let last = document.getElementById("last");
let high = document.getElementById("high");
let low = document.getElementById("low");
let new1 = document.getElementById("new1");
let new2 = document.getElementById("new2");
// now we convert cell content to numbers, add them and make them 2 decimal places.
new1.textContent = (parseFloat(last.textContent) + parseFloat(high.textContent)).toFixed(2);
new2.textContent = (parseFloat(high.textContent) + parseFloat(low.textContent)).toFixed(2);
td {
border: solid 1px;
}
<table>
<tr>
<th>last</th>
<th>high</th>
<th>low</th>
<th>new1</th>
<th>new2</th>
</tr>
<tr>
<td id='last'> 23.40 </td>
<td id='high'> 28.20 </td>
<td id='low'> 22.10 </td>
<td id='new1'></td>
<td id='new2'></td>
</tr>
</table>
First I'm going to make your life a bit easier. Instead of using document.getElementsByTagName('tr')[3].getElementsByTagName('td')[2] to get the fourth tr element's third td element ([0] = first, [2] = third, etc) this will help make your code much much easier to read. You don't need id attributes on every element if you know how reliable code and order are by default.
function tag_(t)
{//Example: tag_('body')[0];
return (document.getElementsByTagName(t)) ? document.getElementsByTagName(t) : false;
}
Object.prototype.tag_ = function(t)
{//Example: id_('unique_id').tag_('td')[0];
return (this.getElementsByTagName && this.getElementsByTagName(t) && this.getElementsByTagName(t).length > 0) ? this.getElementsByTagName(t) : false;
}
Secondly the easiest way to both read and write data to any element is to use textContent.
Read the fourth td on the third tr:
//Read an element's text node:
console.log(tag_('tr')[2].tag_('td')[5].textContent);
//Write to an element's text node:
tag_('table')[0].tag_('tr')[2].tag_('td')[5].textContent = '1,234');
JavaScript is a bit strict when it comes to types. So if you need to do some math with text content that you just read you need to convert it:
Number(tag_('tr')[1].tag_('td')[5].textContent);//'123' becomes `123`
Number(tag_('tr')[2].tag_('td')[2].textContent);//'a123' becomes `NaN` (Not a Number)
If I recall correctly I recently used the following to strip non-numeric text from a string:
var my_number = Number('String or replace with object reference'.replace(/\D/g,''));
Now that you're getting the read/write aspects and overcoming some of the more oddities associated with it I'll iterate over...iteration! You may already know this though I'm presuming a full answer is more desirable than a partial answer for not just you though also others reading this in the future.
var table = tag_('table');
for (var i = 0; i < table.length; i++)
{
console.log(table[i]);
var tr = table[i].tag_('tr');//Whatever table[i] is and it's table rows.
for (var j = 0; j < tr[i].length; j++)
{
console.log(tr[j]);
var td = table[i].tag_('tr')[j].tag_('td');//All the table data elements.
for (var k = 0; k < td.length; k++)
{
//apply read/write conditions here.
//potentially call a second global function to keep your code reusable.
}
}
}
That should help you get far enough with specific and iteral targeting of table data elements to help you learn and achieve your goals.

Run OnChange event for each row in table - MVC

MVC 5 - Razor, Javascript
Novice user!!
I would like to be able to run a simple onchange event when a checkbox is altered in the table, but the onchange only works for the first row.
I have read that this is because the script only runs on the first row and does not run for the subsequent dynamically populated data.
I understand this but don't know how to fix it... I assume that I need to create an individual ID for each checkbox in the each row - I don't know how to do this.
Also, when the checkboxes have different IDs I don't know how to refer to them to add the onchange.
Hope this makes sense. Thanks in advance.
#model IEnumerable<core_point.Models.RegisterEmployee_Step6Model>
#{
ViewBag.Title = "Index";
}
<h2>Select the roles that you have been employed to do, by clicking the check-box...</h2>
<table class="table">
#foreach (var item in Model)
{
<tr class="h3">
<td class="vert-align">
<img src="#item.IconLocation" height="80" width="80" />
</td>
<td class="vert-align">
#Html.CheckBoxFor(modelItem => item.Selected, new { #id = "CheckBoxSelected" })
</td>
<td class="vert-align">
#Html.DisplayFor(modelItem => item.RoleDescription)
</td>
<td class="vert-align">
#Html.TextBoxFor(modelItem => item.Role, new { hidden = "hidden"} )
</td>
</tr>
}
</table>
<div>
Roles selected:<input type="number" id="noSelected" value="0"/>
</div>
<script>
var fld_CheckBoxSelected = document.getElementById("CheckBoxSelected");
var fld_noSelected = document.getElementById("noSelected");
fld_CheckBoxSelected.onchange = function () {
if (fld_CheckBoxSelected == true) {
fld_noSelected = fld_noSelected.value + 1;
}
else
{
fld_noSelected = fld_noSelected.value - 1;
}
}
</script>
replace id with class in CheckBoxFor:
<td class="vert-align">
#Html.CheckBoxFor(modelItem => item.Selected, new {#class= "CheckBoxSelected"})
</td>
In Javascript code use fallowing code:
(function($) {
var onChanged = function(){
/*Do smth that you needed*/
};
$(function() {
$(".checkbox").on("change", onChanged)
});
}(jQuery));
Because all your input boxes will have the same Id value "CheckBoxSelected". That is invalid markup.Id values should be unique.
You may consider removing the id from the markup and use a css class.
#Html.CheckBoxFor(modelItem => item.IsSelected, new { #class = "mycheckBox" })
and using jQuery library, listen to the change event on the input element with this css class.
$(function(){
$("input.mycheckBox").change(function(){
var isSelected = this.checked;
alert("Checkbox changed");
if (isSelected ) {
$("#noSelected").val( parseInt($("#noSelected").val())+ 1));
}
else
{
$("#noSelected").val( parseInt($("#noSelected").val()) - 1));
}
});
});
Assuming the current value of input with id noSelected is a numeric value(else parseInt will fail).

Looping object inside a table cell and create a unordered list

I have this table that has a column in which the cell may or may not contain a value, but when it does, it is in a JSON format; otherwise it will be empty (null).
<table>
<tbody>
<tr>
<td>Barley</td>
<td>AK, AZ</td>
<td class="fpdCell">[{"date":"06/01/2016","error":"Double/Triple cropping","id":2},{"date":"06/07/2016","error":"Lack of Planting Dates Established","id":2}]</td>
<td>null</td>
</tr>
<tr>
<td>Barley</td>
<td>AK, AZ, AR</td>
<td class="fpdCell">[{"date":"06/04/2016","error":"No Error Found","id":3},{"date":"06/27/2016","error":"Lack of Planting Dates Established","id":3},{"date":"06/28/2016","error":"Weather Patterns","id":3}]</td>
<td>null</td>
</tr>
<tr>
<td>Burley Tobacco</td>
<td>null</td>
<td class="fpdCell">null</td>
<td>null</td>
</tr>
<tr>
<td>Fire Cured Tobbacco</td>
<td>null</td>
<td class="fpdCell">null</td>
<td>null</td>
</tr>
<tr>
<td>Flue Cured Tobacco</td>
<td>null</td>
<td class="fpdCell">null</td>
<td>null</td>
</tr>
<tr>
<td>Oats</td>
<td>null</td>
<td class="fpdCell">null</td>
<td>null</td>
</tr>
What I need to do is to loop through each of the cells with the fpdCell class, loop the object inside of each of those cell, create a list and add them as list element.
This is as far as I was able to get. I really don't know how to move forward from here.
var theCells = $('.fpdCell');
$.each(theCells, function(index, value) {
var cellValues = $.parseJSON(value.textContent);
if (cellValues != 'null') {
console.log(cellValues);
value.textContent = '';
$(value).append('<ul class="list-group ul'+index+'"></ul>')
//then add <li class="list-group-item">Test</li>
//Not working------------------
/*
for (var u = 0; u < cellValues. length; u++) {
$('ul' + index).append('<li class="list-group-item">'+cellValues[u].date+'</li>');
console.log(cellValues[u].date);
}
*/
}
});
Thanks in advance.
To achieve this you just need two loops, one to go through the .fpdCell elements, the other to go through the parsed JSON and build the HTML of the ul. Try this:
$('.fpdCell').each(function() {
var $el = $(this), html = '';
$.each(JSON.parse($el.text()), function(i, obj) {
html += '<li class="list-group-item">' + obj.date + '</li>';
})
$el.append('<ul>' + html + '</ul>');
});
Working example
var theCells = $('.fpdCell');
$.each(theCells, function() {
var cellValues = $.parseJSON($(this).text());
if (cellValues != 'null') {
console.log(cellValues);
$(this).html("");
var list = '<ul class="list-group ul'+index+'">';
for (var u = 0; u < cellValues.length; u++) {
list+='<li class="list-group-item">'+cellValues[u].date+'</li>';
console.log(cellValues[u].date);
}
if(cellValues.length>0)
list+="</ul>";
$(this).append(list);
}
The objects in the fpdcell columns are array objects which you may have missed in your logic.
One more thing, may be a typo, but, you missed the . in the commented code to append list items to the ul :)
Here is a solution which loops through the array and then loops through the individual elements in each array element to create a linear list.
var theCells = $('.fpdCell');
$.each(theCells, function(index, value) {
var cellValues = JSON.parse(value.textContent);
if (cellValues != 'null') {
$(value).html('<ul class="list-group ul'+index+'"></ul>');
$.each(cellValues, function(cellValueIndex, cellValue){
for (var prop in cellValue) {
$('.ul'+index).append('<li class="list-group-item">'+ cellValue[prop] +'</li>');
}
});
} else {
$(value).html('');
}
});
This may not be the exact solution to what you are looking for but, should help you along the line you would want to go. Happy coding.
Here is a fiddle with the solution JSFiddle

jQuery - get next element inside checkbox each

I have a table with following columns: checkbox, text, text, ...
For every selected checkbox I need to get the 2nd text value and test if contains some value.
My code so far
$('input:checkbox').each(function () {
var current = $(this);
if (current.is(':checked')) {
var txt = current.next('.inf-name').text();
if (txt.contains(inf) { ... }
}
});
razor code:
<table class="table table-bordered table-modified">
<thead>
<tr>
<th></th>
<th>State</th>
<th>Lookup Type</th>
<th>Plates</th>
<th>Notices</th>
</tr>
</thead>
<tbody>
#Html.HiddenFor(p => p.OrgUnitID, new { #Value = orgUnitId })
#for(var ind = 0; ind < records.Count(); ++ind)
{
var r = records[ind];
var i = ind;
#Html.HiddenFor(p => p.Comp[i].State, new { #Value = #r.State })
<tr>
<td>#Html.CheckBoxFor(p => p.Comp[i].Checked)</td>
<td>#r.State</td>
#if (dict.ContainsKey(r.State))
{ <td class="inf-name">#dict[r.State].ToString()</td> }
else
{ <td class="inf-name"></td> }
<td>#Html.ActionLink(#r.Plates.ToString(CultureInfo.InvariantCulture), "Plates", new { controller = "Lookup", state = #r.State})</td>
<td>#Html.ActionLink(#r.Notices.ToString(CultureInfo.InvariantCulture), "Plates", new { controller = "Lookup" }, new { state = #r.State })</td>
</tr>
}
</tbody>
</table>
where inf-name is the class on 2nd element. I can't get it done. Anyone know a solution?
using next() will get the direct sibling , you need to get parent for check box which is a <td> find the next next sibling using nextAll().eq(1) , get the text inside the that sibling using .text()
Edit :
if you want your target using classes ( provided classes will never change later ) , then just change your code to be :
$('input:checkbox').each(function () {
var current = $(this);
if (current.is(':checked')) {
var txt = current.next('.inf-name').eq(1).text();
if (txt.contains(inf) { ... }
}
});
var currentRows = $('.table tbody tr');
$.each(currentRows, function () {
$(this).find(':checkbox').each(function () {
if ($(this).is(':checked')) {
console.log($(currentRows).eq(1).val());
}
});
});

Passing hidden value using jQuery in MVC

My MVC Controller passes a Model to view in the following form
public class LibaryModel
{
public int LibaryId { get; set; }
public string[] Books { get; set; }
}
This is my LibraryView.cshtml
#model IEnumerable<LibaryModel>
<table id="myTable" class="table-bordered">
<thead>
<tr>
<th>Libary Id</th>
</tr>
</thead>
<tbody>
#foreach (var library in Model)
{
<tr>
<td>#library.LibaryId</td>
</tr>
}
</tbody>
</table>
Now, On clicking the library id, I need to show another div with the list of books in that library. I am able to get the row number and column number of click event, but I am not able to figure a way to get the list of books in the libary from jQuery. Is there any pattern to solve this?
$("#myTable td").on('click', function () {
var column_num = parseInt($(this).index()) + 1;
var row_num = parseInt($(this).parent().index()) + 1;
});
I would suggest using the LibraryId in a function on a click event in your td.
foreach (var library in Model)
{
<tr>
<td onclick="getHiddens(#library.LibraryId)">#library.LibaryId</td>
</tr>
}
And give your books' hidden inputs a class that contains its library's LibraryId
for (var i = 0; i < library.Books.Length; i++)
{
<input type="hidden" class="book#library.LibraryId" value="#library.Books[i]" />
}
And then sending that LibraryId into a function as an argument that gets all matching inputs by class, and does something with the input's value, like for this example, loading it into a div.
var getHiddens = function (libraryId) {
var books = document.getElementsByClassName("book" + libraryId);
var bookDiv = document.getElementById("bookDiv");
bookDiv.innerHTML = "<ul>";
for (var i = 0; i < books.length; i++) {
bookDiv.innerHTML += "<li>" + books[i].value + "</li>";
}
bookDiv.innerHTML += "</ul>";
}
Please check my code .
#foreach (var library in Model)
{
<tr>
<a href="javascript:void(0)"
onclick="GoToInsured('#library.LibaryId');">
</tr>
}
function GoToInsured(LibaryId)
{
//This LibaryId is current selected row ID.You can open new Diva per
LibaryId. You can get Library details as per LibaryId and you can display
that data on Popup or any place you want.
}
Tell me you have any query regarding my code .
Thanks .

Categories

Resources