I have a "DOM" list in MVC 4 using jQuery to add elements dynamically but at the moment of removing all the elements
The table no longer allows me to add more elements, I have tried to use length and comparisons but it does not work.
Am probably missing something obvious but can't see what it is. Any ideas?
Example
Here is my table code
<div><img src="~/Images/splus.png" alt="Add Product" style="border:0"/></div>
<table id="dataTable" border="0" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th></th>
<th></th>
<th>Product</th>
<th>Quantity</th>
<th></th>
</tr>
</thead>
<tbody>
#if (Model != null && Model.Count > 0)
{
int j = 0;
int index = 1;
foreach (var i in Model)
{
<tr>
<td>#index</td>
<td>#Html.HiddenFor(a => a[j].SEQ_NO, new { id = "nrow", Value = index })</td>
<td>#Html.DropDownList("PRODUCTS", "Select Product")</td>
<td>#Html.TextBoxFor(a => a[j].QUANTITY)</td>
<td>
<img src="~/Images/sminus.png" alt="Add Product" style="border:0"/>
</td>
</tr>
index += 1;
j++;
}
}
</tbody>
</table>
Here is my jQuery Code when i click on Add New
$("#addNew").click(function (e) {
e.preventDefault();
var last = $('#dataTable>tbody>tr:last');
if (last.length > 0) {
var name = last.children().find('input,select')[0].name;
var index = Number(name.replace(/[^0-9]/gi, '')) + 1;
var tr = ('<tr>' + last.html().replace(/[0-9]+__/gi, index + '__') + '</tr>').replace(/\[[0-9]+\]+[.]/gi, '[' + index + '].');
numberRows($('#dataTable tbody').append(tr));
}
});
UPDATE:
Add "REMOVE CODE"
$(document).on('click', '#remove', function (e) {
e.preventDefault();
$(this).parent().parent().remove();
numberRows($('#dataTable tbody'));
});
Am probably missing something obvious but can't see what it is. Any ideas?
var name = last.children().find('input,select')[0].name;
This line of code requires one last child, which means after you removed the last under , the name will be undefined. In fact, the Add New function won’t even pass the if (last.length > 0) since when the last got removed, the last.length becomes 0.
You can debug in devtools, and will see:
BEFORE the last got removed:
AFTER the last got removed:
Thus, to fix this issue, the simplest solution is to not remove the last but hide it. Please check below code:
$(document).on('click', '#remove', function (e) {
e.preventDefault();
if ($('#dataTable>tbody>tr').length > 1) {
$(this).parent().parent().remove();
//numberRows($('#dataTable tbody'));
}
else {
$(this).parent().parent().hide();
}
});
Ps. Not sure what happens in numberRows() function so I commented it.
Related
I created an sample c# blazor (server-side) app to practice a little.
I try to generate table rows dynamically for a calendar but i run into a problem there.
<table class="table">
<thead>
<tr>
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
<th>Sunday</th>
</tr>
</thead>
<tbody>
<tr>
#* currentDateTimeValues is a list with DateTime objects *#
#foreach (var item in currentDateTimeValues)
{
#if (counter % 7 == 0 && counter > 0)
{
#:</tr><tr>
}
counter++;
<td>#item.ToString("dd.MM.yyyy")</td>
}
</tr>
</tbody>
</table>
After 7 cells a new row should be created but it doesn't. The cells go straight ahead without linebreak.
Maybe you guys have any idea.
UPDATE:
In the meantime I've created a workaround because I think that blazor can't handle the </tr><tr>
My currentDateTimeValues-List now contains week objects
<tbody>
#* currentDateTimeValues is a list with Week objects *#
#foreach (var week in currentDateTimeValues)
{
<tr>
<td>#week.Monday</td>
<td>#week.Tuesday</td>
<td>#week.Wednesday</td>
<td>#week.Thursday</td>
<td>#week.Friday</td>
<td>#week.Saturday</td>
<td>#week.Sunday</td>
</tr>
}
</tbody>
I think the solution you are trying isn't possible in Blazor at the moment. Why not use two loops to create the calendar. Something like:
#while (counter < currentDateTimeValues.Length)
{
<tr>
#{
var i = 0;
if (i < 7 && counter + i < currentDateTimeValues.Length)
{
<td>#currentDateTimeValues[counter + i].ToString("dd.MM.yyyy")</td>
i++;
}
}
</tr>
counter += 7;
}
I have here a view model which has two list objects. I will display them as two tables in my view. I've already created EditorFor for them. I'll place four buttons (move one right, move all right, move one left, move all left) for the exchange operations. I've googled everywhere and no goal on how to accomplish that, because I need to move the entire object, replace all "name" and "id" tags, reorder indexes and so on, because this way my lists will be posted correctly. I'm using Datatables.net and jQuery too.
Does anybody have a clue on how to do that?
Thank you in advance. The code goes below
EDIT
Since list elements on ASP.NET MVC are indexed like "ListName_0__Code"(for Id) and "ListName[0].Code" (for name) how to properly reorder these indexes?
EditorFor
#model ViewModels.UserPermissionDetails
<tr id="#Model.Id">
<td>
#Html.HiddenFor(m => m.Code)
#Html.HiddenFor(m => m.Login)
#Html.HiddenFor(m => m.Name)
#Html.HiddenFor(m => m.IdEmpUser)
#Html.DisplayFor(m => m.Code)
</td>
<td>#Html.DisplayFor(m => m.Login)</td>
<td>#Html.DisplayFor(m => m.Nome)</td>
</tr>
View
<table id="tbBlock">
<thead>
<tr>
<th>Code</th>
<th>Login</th>
<th>Name</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(model => model.BlockList)
</tbody>
</table>
<table id="tbAllow">
<thead>
<tr>
<th>Code</th>
<th>Login</th>
<th>Name</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(model => model.AllowList)
</tbody>
</table>
Exchange method (jQuery)
function addElement(OriginTableId, DestinyTableId, OriginListName, DestinyListName) {
var originTb = $(OriginTableId).DataTable(); //initialize DataTable.Net for origin table
var destinyTb = $(DestinyTableId).DataTable(); //initialize DataTable.Net for destiny table
var objectLine = $('#' + originTb.$('tr.selected').attr('id')); //get selected line that will be moved
//Name replacing code piece
var elementsFromLine = $(objectLine.children()[0]).children().toArray();
elementsFromLine.forEach(function (item, index, array) {
$(item).attr('id', $(item).attr('id').replace(OriginListName, DestinyListName)); //Replace 'OriginListName_0' with 'DestinyListName_0'
$(item).attr('name', $(item).attr('name').replace(OriginListName, DestinyListName)); //Replace 'OriginListName[0]' with 'DestinyListName[0]'
});
//Reordering code piece here, how to?
$(DestinyTableId + ' tbody').append(objectLine.clone(true, true));
objectLine.parent().remove();
}
It will be much easier for you to calculate and set the name values with the index only before you submit the form, not for every move action.
#Html.HiddenFor(m => m.Code, new { #class = "code" } })
// same for all the inputs you send to server
$("button[type='submit']").on("click", function (e) {
e.preventDefault();
updateIndexes();
$("form").submit();
});
function updateIndexes() {
$("#tbAllow").find("tbody").children("tr").each(function (i) {
var prefix = "BlockList[" + i + "].";
var $tr = $(this);
$tr.find("input.code").attr("name", prefix + "Code");
$tr.find("input.login").attr("name", prefix + "Login");
// same for all the inputs you send to server
});
};
In the past I've used jQuery/Ajax to capture the key press of an end user, and build up a WHERE clause to filter data on a Web form.
I'm now taking advantage of the strongly type facilitates in ASP.NET 4.5. I was wondering if anyone has a way of performing real-time filtering/searching on a Gridview.
Basically, I have three grids, all showing different information. I want the end-user to key in or select from a drop down list (generic searching) and all girds reflect those changes.
I'm not adverse to resorting back to the old method, just didn't; know if there was anything new I could use?
So you can look at this. I hope this help you.
Here is the HTML:
<input id="searchInput" value="Type To Filter">
<br/>
<table>
<thead>
<tr>
<th>Column1</th>
<th>Column2</th>
</tr>
</thead>
<tbody id="fbody">
<tr>
<td>cat</td>
<td>one</td>
</tr>
<tr>
<td>dog</td>
<td>two</td>
</tr>
<tr>
<td>cat</td>
<td>three</td>
</tr>
<tr>
<td>moose</td>
<td>four</td>
</tr>
<tr>
<td>mouse</td>
<td>five</td>
</tr>
<tr>
<td>dog</td>
<td>six</td>
</tr>
</tbody>
</table>
And here is the JavaScript code:
$("#searchInput").keyup(function () {
// Split the current value of searchInput
var data = this.value.split(" ");
// Create a jQuery object of the rows
var jo = $("#fbody").find("tr");
if (this.value == "") {
jo.show();
return;
}
// Hide all the rows
jo.hide();
// Recusively filter the jquery object to get results.
jo.filter(function (i, v) {
var $t = $(this);
for (var d = 0; d < data.length; ++d) {
if ($t.is(":contains('" + data[d] + "')")) {
return true;
}
}
return false;
})
// Show the rows that match.
.show();
}).focus(function () {
this.value = "";
$(this).css({
"color": "black"
});
$(this).unbind('focus');
}).css({
"color": "#C0C0C0"
});
Enter link description here
My setup is as follows...
I have a service which brings back data from a stored procedure to a UI in no particular order. The UI binds the data to an MVC partial using knockout which looks like this...
#{ ViewBag.Title = "People List"; }
<h2>People List</h2>
<table id="people">
<thead>
<tr>
<th>Name</th>
<th>Gender</th>
<th>Job Title</th>
<th>Job Description</th>
</tr>
</thead>
<tbody data-bind="foreach: people">
<tr>
<td style="width: 125px;"><span data-bind="text: Name"></span></td>
<td style="width: 75px;"><span data-bind="text: Gender"></span></td>
<td style="width: 105px;"><span data-bind="text: JobTitle"></span></td>
<td style="width: 300px;"><span data-bind="text: JobDescription"></span></td>
</tr>
</tbody>
</table>
<button style="margin-top: 15px;" data-bind="click: sortByName">Sort by Name</button>
The JS for the VM looks like this...
<script type="text/javascript">
function Person(data) {
this.Name = ko.observable(data.Name);
this.Gender = ko.observable(data.Gender);
this.JobTitle = ko.observable(data.JobTitle);
this.JobDescription = ko.observable(data.JobDescription);
}
function PersonListVM() {
var self = this;
self.people = ko.observableArray([]);
$.getJSON('#Url.Action("DisplayPeople", "People")',
function (results) {
for (var i = 0; i < results.length; i++) {
self.people.push(new Person(results[i]));
}
});
self.sortByName = function () {
self.people.sort(function (x, y) {
return x["Name"] == y["Name"] ? 0 : (x["Name"] < y["Name"] ? -1 : 1);
});
};
};
ko.applyBindings(new PersonListVM());
</script>
I can get and display data with no problem, even adding another dummy person in a VM function goes off without a hitch. But sorting by name seems to do nothing. There are no errors, but I'm obviously doing something wrong. This is supposed to be a pretty simple search, what am I missing?
PS: The reason I'm supplying the property name as a string is because I want to make a sortable, paginated grid out of this table, sorting by table headers. My goal is to be able to pass in any valid property on which the table can be sorted dynamically but this is just as experiment working up to it.
Even though you're accessing your properties using array syntax, they're still ko.observables. You need to "unwrap" the observable to get at the value.
Try this instead:
return x['Name']() == y['Name']() ? 0 : (x['Name']() < y['Name']() ? -1 : 1);
Just off the top of my head have you tried using dot syntax to access the person object properties instead of array syntax?
self.people.sort(function (x, y) {
return x.Name == y.Name ? 0 : (x.Name < y.Name ? -1 : 1);
});
I have a loop on the server ( C# ) that does this:
for(i=0;i<=Request.Files.Count - 1; i++)
{
// tell the client that the upload is about to happen
// and report useful information
Update(percent, message, i, 0);
System.Threading.Thread.Sleep(1000);
// tell the client that upload succeeded
// and report useful information
Update(percent, message, i, 1);
}
The function "Update" writes to the client-side javascript function "PublishUpdate".
The row parameter is the row in the table containing the uploading file. The 'status' tells us if the file is about to be uploaded (0) or completed (1).
THE PROBLEM is that I can't seem to get the count correct. The loop seems to
start 2 or 3 rows into the table or (after playing with the row value) it ends before the
final row. I am very new to jQuery. Does anything look obviously wrong to you?
function PublishUpdate(percent, message, row, status)
{
var bodyRows = $("#picTableDisplay tbody tr");
bodyRows.each(function(index){
if (index == row && status == 0)
$('#status'+index).html("<img alt='inproc' src='images/loading.gif' />");
else if (index == row && status == 1)
$('#status'+index).html("complete");
});
}
Finally, the table looks like this:
<table width="100%" cellspacing="0" cellpadding="3" border="0" align="center" id="picTableDisplay" summary="" class="x-pinfo-table">
<tbody id="files_list" class="scrollContent">
<tr class="evenRow">
<td class="numCol" id="num0">
</td>
<td class="fnameCol" id="fname0">
</td>
<td class="statusCol" nowrap="" id="status0">
</td>
<td class="remCol" id="rem0">
</td>
</tr>
<tr class="oddRow">
<td class="numCol" id="num1">
</td>
<td class="fnameCol" id="fname1">
</td>
<td class="statusCol" nowrap="" id="status1">
</td>
<td class="remCol" id="rem1">
</td>
</tr>
<tr class="evenRow">
<td class="numCol" id="num2">
</td>
<td class="fnameCol" id="fname2">
</td>
<td class="statusCol" nowrap="" id="status2">
</td>
<td class="remCol" id="rem2">
</td>
</tr>
AND SO ON ...
Thanks in advance.
The C# is using zero indexing, and typically HTML authors use indexing starting from one. Check to see if you need to correct the index from 0 to 1-based, like this:
$('#status' + (index + 1))
Also refactoring your code to something simpler can often fix hidden errors, or at least make the error more obvious. I'd suggest something along these lines:
if (index == row)
{
if (status == 0) {
html = "<img alt='inproc' src='images/loading.gif' />";
} else {
html = "complete";
}
$('#status'+index).html(html);
}
You should also use C# idiom for looping, < x not <= x - 1:
for(i=0; i < Request.Files.Count; i++)
I'm not entirely sure what you're trying to do as it's not clear where the #status elements are. However, assuming they're cells within the row it might be better to give them a class "status" and then write something like
function PublishUpdate(percent, message, row, status) {
$('#picTableDisplay tbody tr:eq('+row+') .status').html(
status==0 ? '<img alt="inproc" src="images/loading.gif"/>' : 'complete'
);
}