I have a table where I add and remove rows dynamically:
#model AHBReports.Models.AdjustmentModel
#using (Html.BeginForm())
{
<table id="container">
#Html.EditorFor(model => model.Adjustments)
</table>
<div >
<input type="button" id="btnAdd" value="+ Add" />
<input type="submit" value="Submit" />
</div>
}
EditorTemplate:
#model AHBReports.Models.Adjustment
<tr>
<td>#Html.HiddenFor(x => x.Id, new { #class = "iHidden" })</td>
<td>#Html.AutocompleteFor(model => model.BRANCH, "GetBranches", "Report700H")</td>
<td>#Html.EditorFor(model => model.Amount)</td>
<td><a onclick="removeRow(this)">x</a></td>
</tr>
Script for table manipulation:
<script type="text/javascript">
function removeRow(selector)
{
if ($('#container tr').length > 1)
{
$(selector).closest('tr').remove();
}
}
$(document).ready(function () {
$("#btnAdd").click(function (e) {
var ind = $("#container tr:last").find("input.iHidden").val();
var itemIndex = parseInt(ind);
itemIndex++;
console.log(itemIndex);
e.preventDefault();
var newItem = $("<tr>"+
"<td><input id='Adjustments_" + itemIndex + "__Id' type='hidden' value='"+itemIndex+"' class='iHidden' name='Adjustments[" + itemIndex + "].Id' /></td>" +
"<td><input type='text' id='Adjustments_" + itemIndex + "__BRANCH' name='Adjustments[" + itemIndex + "].BRANCH' data-autocomplete-url='#Url.Action("GetBranches", "Report700H")'/></td>" +
"<td><input type='text' id='Adjustments_" + itemIndex + "__Amount' name='Adjustments[" + itemIndex + "].Amount'/></td>" +
"<td><a onclick='removeRow(this)'>x</a></td>" +
"</tr>");
$("#container").append(newItem);
});
});
My add/delete functions work fine visually in my view, as well as when I accept the collection in my POST method:
public ActionResult Adjust(AdjustmentModel model)
{
//working with model.Adjustments
}
I receive correct values. However, when I try to delete some row, which is in the middle of the table and then sumbit the form, I receive only elements that were above deleted row, for example:
id branch amount
0 aaa 500
1 bbb 200
2 ccc 300 --deleted this row
3 ddd 400
Collection receives:
id branch amount
0 aaa 500
1 bbb 200
So, the last row is missing.
What am I doing wrong??
Thanks a lot
When the row you deleted it containts model's input and input has name and id based on index.
So when you delete row you have to update input's name and id that are in row after the deleted row..
or regenerate row next all from deleted row with new index name
.
Replace your delete function with this one
function removeRow(selector) {
if ($('#container tr').length > 1) {
$(selector).closest('tr').remove();
var itemIndex =0;
$('#container tr').each(function(){
var this_row = $(this);
this_row.find('input[name$=".BRANCH"]').attr('name','Adjustments[' + itemIndex + '].BRANCH');//replace name of input that ends the name BRANCH
this_row.find('input[name$=".Amount"]').attr('name','Adjustments[' + itemIndex + '].Amount');
this_row.find('input[name$=".Id"]').attr('name', 'Adjustments[' + itemIndex + '].Id');
itemIndex ++;
});
}
}
The indexer for collections must start at zero and be consecutive unless you use an Index property where the value of Index is equal to the indexer. For example
<input ... name="Adjustments[0].ID" ..>
<input ... name="Adjustments[2].ID" ..>
wont post back correctly. But if you add an Index property for the object
<input ... name="Adjustments[0].ID" ..>
<input ... name="Adjustments[0].Branch" ..>
<input ... name="Adjustments[0].Index" value="0"..>
<input ... name="Adjustments[2].ID" ..>
<input ... name="Adjustments[2].Branch" ..>
<input ... name="Adjustments[2].Index" value="2"..>
Then the collection will post back correctly
Since you don't have access to the indexer in the EditorTemplate, you will need to generate the controls in a for loop in the main page
for (int i = 0; i < Model.Adjustments.Count; i++)
{
var name = string.Format("Adjustments[{0}].Index", i);
#Html.HiddenFor(m => m[i].ID)
....
<input type=hidden name="#name" value="#i" />
}
You will also need to modify your script to include the hidden input for the Index property. Rather than basing the value of itemIndex on the number of existing rows, base it on a unique value. For example
$("#btnAdd").click(function (e) {
var itemIndex = (new Date()).getTime();
u can give the row an unique id.
var newItem = $("<tr id='row"+itemIndex+"'>"+
"<td><input id='Adjustments_" + itemIndex + "__Id' type='hidden' value='"+itemIndex+"' class='iHidden' name='Adjustments[" + itemIndex + "].Id' /></td>" +
"<td><input type='text' id='Adjustments_" + itemIndex + "__BRANCH' name='Adjustments[" + itemIndex + "].BRANCH' data-autocomplete-url='#Url.Action("GetBranches", "Report700H")'/></td>" +
"<td><input type='text' id='Adjustments_" + itemIndex + "__Amount' name='Adjustments[" + itemIndex + "].Amount'/></td>" +
"<td><a onclick='$('#row"+ itemIndex +").remove();'>x</a></td>" +
"</tr>');
Actually this works fine for a smiliar page which i've created.
Greetings
Related
I need help filling dependent dropdowns. I have dependent dropdown that work when entering data, select the State dropdown and the dependent dropdowns reload based on the state selected.
Issue is when I want to edit, the state is filled and selected from database, but the dependents don't get filled and selected. The onChange function doesn't get activated or hit.
Here are my codes:
<div class="form-row">
<div class="col">
<div class="form-group">
<label asp-for="Sposted"></label>
<select asp-for="Sposted"
class="form-control"
asp-items="#(new SelectList(#ViewBag.statelist, "Stateid", "Statename" ))"
onchange="sposted(this)">
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label asp-for="Pcommand"></label>
<select asp-for="Pcommand" class="form-control" id="Pcommand"
asp-items="#(new SelectList(string.Empty, "Commandid", "Cfname"))">
<option>Select ...</option>
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label asp-for="PayP"></label>
<select asp-for="PayP" id="PayP"
class="form-control"
asp-items="#(new SelectList(string.Empty, "Ppid", "Ppfull"))"></select>
</div>
</div>
</div>
The 2 dropdowns, Pcommand and PayP are dependent on sposted. Again, when editing, the sposted drop down is selected and filled from db, but doesn't cascade to the other 2.
Here is the JS:
<script type="text/javascript">
//$(document).ready(function () {
//$('#Sposted').change(function () {
function sposted(stateid) {
console.log(stateid.value);
var url = '#Url.Content("~/")' + "MemberList/RetPayPoint";
//var ddlsource = "#Sposted";
//$.getJSON(url, { Stateid: $(ddlsource).val() }, function (data) {
$.getJSON(url, { Stateid: stateid.value }, function (data) {
var items = '';
$("#PayP").empty();
$.each(data, function (i, pp) {
items += "<option value='" + pp.value + "'>" + pp.text + "</option>";
});
$('#PayP').html(items);
});
}//});
// });
</script>
Thank you in advance.
A few days later, I have decided to add the controller method that is supposed to fill the dropdowns in the view.
public IActionResult DisplayMem()
{
var statelist = _mr.GetStates().ToList();
statelist.Insert(0, new ToxState { Stateid = 0, Statename = "Select..." });
ViewBag.statelist = statelist;
var rank = _mr.GetRanks().ToList();
rank.Insert(0, new ToxRank { Rankid = 0, Fullname = "Select..." });
ViewBag.rank = rank;
//memid = memlist.FirstOrDefault().MemberId;
var obj = _mr.MemberInfo((long)_ar.FindAcc(long.Parse(HttpContext.Session.GetString("memberid"))).MemId);
return View(obj);
}
All he information needed to fill the view elements are in obj. It loads the selects the state from the id in obj, but the onchange isn't fired to fill the dependent dropdowns.
When editing using selected stateid you need to get both dropdowns data, just like you are getting PayP data by using selected stateid like:
$.getJSON(url, { Stateid: stateid.value }, function (data) {
var items = '';
$("#PayP").empty();
$.each(data, function (i, pp) {
items += "<option value='" + pp.value + "'>" + pp.text + "</option>";
});
$('#PayP').html(items);
});
You will call your function sposted and pass selected stateid both times while creating or editing.
After days of research, I couldn't seem to find a way to to force the onchange to call Ajax to dynamically fill the dependent dropdowns. So I took a cue from Mateen's 3rd comment and rewrote the method in the controller to read load the relevant items into a ViewBag.
public IActionResult DisplayMem()
{
var statelist = _mr.GetStates().ToList();
statelist.Insert(0, new ToxState { Stateid = 0, Statename = "Select..." });
ViewBag.statelist = statelist;
var rank = _mr.GetRanks().ToList();
rank.Insert(0, new ToxRank { Rankid = 0, Fullname = "Select..." });
ViewBag.rank = rank;
var obj = _mr.MemberInfo((long)_ar.FindAcc(long.Parse(HttpContext.Session.GetString("memberid"))).MemId);
ViewBag.payp = _mr.GetPayPoint(obj.Sposted.Value).ToList();
ViewBag.pcommand = _mr.GetCommand(obj.Sposted.Value).ToList();
return View(obj);
}
I have a table filled with generated data using razor. Each row has the id of the PlanID in the database.
<tbody>
#foreach(var plan in ViewBag.plans) {
<tr id="#plan.PlanID">
<td contenteditable="true">#plan.Name</td>
<td contenteditable="true">#plan.Code</td>
<td contenteditable="true">#plan.Description</td>
<td contenteditable="true">#plan.DataAmount</td>
<td contenteditable="true">#plan.Price</td>
<td contenteditable="true">#plan.SmartPhoneCost</td>
<td><a><span class="glyphicon glyphicon-pencil"></span></a></td>
</tr>
}
</tbody>
I have also made button click append the table with a new row to add a plan
function Add() {
$("#tableData tbody").append(
"<tr role='form' action='/api/wirelessplans' method='post'>" +
"<td><input name='Name' type='text' size='30' maxlength='30'/></td>" +
"<td><input name='Code' type='text' /></td>" +
"<td><input name='Description' type='text' size='50' maxlength='50'/></td>" +
"<td><input name='DataAmount' type='text' /></td>" +
"<td><input name='Price' type='text' /></td>" +
"<td><input name='SmartPhoneCost' type='text' /></td>" +
"<td><a class='save' type='submit'><span class='glyphicon glyphicon-ok'></span></a></td>" +
"</tr>")
};
$(function () {
$("body").on("click", ".addPlan", function () {
Add()
});
});
I have made the the td's editable and would like to click on the icon to submit the changes to -- api/wirelessplans/ that I defined in my controller. How do I grab only the values that are changed (or added in the new row) and post/put to the database?
I have a need to be able to post back an unknown number of this model class:
public class UserRegisterModel
{
public string UserName { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public string RepName { get; set; }
public string ContactNumber { get; set; }
}
in a List<UserRegisterModel> to a controller.
I need my view to have a form that can send back multiple instances of the model to the controller, so for example if my user wants to add 3 Reps, he can make 3 reps and give them each details and usernames and passwords, and send them all back at once in a List.
I have this starting point for my view code:
#model List<PicsWebApp.Models.UserRegisterModel>
#{
ViewBag.Title = "NewRep";
}
<h2>NewRep</h2>
#using (Html.BeginForm("NewRep", "Admin", FormMethod.Post, new { id = "fieldform", #class = "form" }))
{
}
Can anybody show me the correct way of accomplishing this? I know I need javascript in order to dynamically add more form elements if the user clicks "add new rep" so this is mainly about the C#.
you need to make sure the properties' ID's conform to the standard set (I used the link from Felipe's comment when I was doing this). I did this before, where a table row would get added when the user click a button. I found the best way is to add an entry before the page gets rendered, then taking the HTML for that, and using it in your jquery.
Here's a function I've used:
$("#nameAdd").click(function (e) {
var index = $("#nameTable tr").length - 1;
e.preventDefault();
var newItem = $("<tr> \
<td> \
<span id='Names_" + index + "__FullName' /> \
</td> \
<td> \
<input class='table-editor-small update-name' id='Names_" + index + "__FirstName' name='Names[" + index + "].FirstName' type='text' value='' /> \
</td> \
<td> \
<input class='table-editor-small update-name' id='Names_" + index + "__MiddleName' name='Names[" + index + "].MiddleName' type='text' value='' /> \
</td> \
<td> \
<input class='table-editor-small update-name' data-val='true' data-val-required='Person Last Name Required' id='Names_" + index + "__LastName' name='Names[" + index + "].LastName' type='text' value='' /> \
</td> \
<td class='center'> \
<input data-group='nameRadios' id='Names_" + index + "__IsPrimary' name='Names[" + index + "].IsPrimary' type='radio' value='True' /> \
</td> \
<td class='center'> \
<input data-val='true' data-val-required='The Delete? field is required.' id='Names_" + index + "__ToDelete' name='Names[" + index + "].ToDelete' type='checkbox' value='true' /> \
<input name='Names[" + index + "].ToDelete' type='hidden' value='false' /> \
</td> \
</tr>");
$("#nameTable").append(newItem);
}
again, the HTML to add is straight from an item that had been rendered by the view, i just swapped in the index
So I have a simple ASP.NET/ C# generated html form where I have a list of textboxes that I want to be able to add and/or delete on the fly. There are pre-existing textboxes that are generated from a SP that look like this, with an 'add another textbox' button below:
<tr>
<td id="lblRole" style="vertical-align:top;" ><strong>The Role *</strong><br />(2000 characters maximum each)</td>
<td id="rolesColumn">
<div id="roles-1" class="div_row">
<textarea name="ctl00$mainContent$uxRolesList$ctl01" rows="5" cols="100"
id="ctl00_mainContent_uxRolesList_ctl01">yuyuy</textarea>
<input type="button" style="vertical-align:top;" value="X" class="remove-roles-btn" /><br /><br />
</div>
<input type="hidden" name="ctl00$mainContent$uxTxtBoxRolesCount"
id="ctl00_mainContent_uxTxtBoxRolesCount" value="1" />
</td>
</tr>
<tr>
<td> </td>
<td>
<input type="submit" name="ctl00$mainContent$uxAddRoleBtn"
value="Add a new role requirement"
id="ctl00_mainContent_uxAddRoleBtn" class="btn" />
</td>
</tr>
My jQuery is this:
$("#ctl00_mainContent_uxAddRoleBtn").live("click", (function (e) {
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
rolesCounter++;
if (rolesCounter < 10) {
var rolesCounterText = "0" + rolesCounter;
} else {
var rolesCounterText = rolesCounter;
}
$('#rolesColumn').append("<div id='roles-" + rolesCounter + "' class='div_row'><textarea name='ctl00$mainContent$uxRolesList$ctl" + rolesCounterText + "' rows='5' cols='100' id='ctl00_mainContent_uxRolesList_ctl" + rolesCounterText + "'></textarea><input class='remove-roles-btn' type='button' value='X' style='vertical-align:top;' /><br /><br /></div>");
e.preventDefault();
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter);
}));
$(".remove-roles-btn").on("click", (function (e) {
$(this).parents('.div_row').remove();
e.preventDefault();
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
rolesCounter--;
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter);
}));
But when I click to add a new textbox, all the textboxes are deleted.
And when I click to delete a textbox, nothing happens.
Thank you.
You have a typo in your code:
$("#ctl00_mainContent_uxAddRoleBtn").live("click", (function (e) {
//-------------------------------------------^----here you can see a "("
and here:
$(".remove-roles-btn").on("click", (function (e) {
//------------------^-----------------here
but i suggest you to use .on() method:
$(document).on("click", "#ctl00_mainContent_uxAddRoleBtn", function (e) {
and this:
$(document).on("click", ".remove-roles-btn", function (e) {
NOTE, be sure to be using jQuery 1.8.3 or lower, otherwise it will NOT work. All you have to do is change 'on' to 'live'
$(".remove-roles-btn").live("click", (function (e) {
Here is a simple example with your code that shows it working.
For remove button you need to use event delegation
$(document).on("click", "#rolesColumn .remove-roles-btn", function (e) {
e.preventDefault();
$(this).closest('.div_row').remove();
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter - 1);
});
$(document).on("click", "#ctl00_mainContent_uxAddRoleBtn", function (e) {
var rolesCounter = $('#ctl00_mainContent_uxTxtBoxRolesCount').val();
rolesCounter++;
if (rolesCounter < 10) {
var rolesCounterText = "0" + rolesCounter;
} else {
var rolesCounterText = rolesCounter;
}
$('#rolesColumn').append("<div id='roles-" + rolesCounter + "' class='div_row'><textarea name='ctl00$mainContent$uxRolesList$ctl" + rolesCounterText + "' rows='5' cols='100' id='ctl00_mainContent_uxRolesList_ctl" + rolesCounterText + "'></textarea><input class='remove-roles-btn' type='button' value='X' style='vertical-align:top;' /><br /><br /></div>");
e.preventDefault();
$('#ctl00_mainContent_uxTxtBoxRolesCount').val(rolesCounter);
});
Demo: Fiddle
I am bit new in the c# programming, so I got stuck at one place. Need your help.
Actually through javascript I am generating table(4 columns) rows(having textboxes so that user can give inputs) as per as the user button click. As the number of rows are not fixed and we dont have the exact name of the textboxes so now my problem is how should we insert these rows into the sqlserver table?
should I use simply the loop for generating the name of the Textboxes for every user button click? and once we got the name for all controls can we insert these all through a single insert statement by using loop?
warm regrads,
ammy
If you're using just a regular html table add 'runat="server"' Tag with JS as well as html form controls then just change TableRow to HtmlTableRow and TextBox to HtmlInputText. All of those controls are in the System.Web.UI.HtmlControls namespace.
Assuming you're using the Table server control then it's just:
foreach (TableRow row in table.Rows)
{
var col2 = (TextBox)row.Cells[1].Controls[0];
//Do DB inserting stuff here With col2
string stringToInsert= col2 .Text;
}
I'm asuming you're using MVC..
You can start by creating a model such as:
public class YourModel
{
public IEnumerable<Users> users { get; set; }
}
Than create a view and add the rows dynamically by script given below:
<script type="text/javascript">
var Rows = 1;
// We already got the 0 element as html so start from 1
function AddUser() {
$("#UserTable").append('<tr>' +
'<td><input type="text" name="users[' + Rows + '].Name" style="width:100px;" /></td>' +
'<td><input type="text" name="users[' + Rows + '].Surname" style="width:100px;" /></td>' +
'<td><input type="text" name="users[' + Rows + '].Age" style="width:50px;" /></td>' +
'<td><input type="text" name="users[' + Rows + '].Date" style="width:70px;" /></td>' +
'</tr>');
// Add datepicker (this is an optional jQueryUI stuff)
$('input[name="users[' + Rows + '].Date"]').datepicker({ dateFormat: 'yy.mm.dd' });
// Go to next row
Rows = Rows + 1;
}
$(document).ready(function(){
// Create an empty row on load
AddUser();
// Than on each click add another row
$('input[type=button]').click(function(){ AddUser(); });
});
</script>
<div>
<table id="UserTable">
<tr>
<td><input type="text" name="user[0].Name" style="width:100px;" value="Berker" /></td>
<td><input type="text" name="user[0].Surname" style="width:100px;" value="YĆ¼ceer" /></td>
<td><input type="text" name="user[0].Age" style="width:50px;" value="24" /></td>
<td><input type="text" name="user[0].Date" style="width:70px;" value="2012.12.11" /></td>
</tr>
</table>
<input type="button" id="add" value="Add" />
</div>
fiddle for the script: http://jsfiddle.net/BerkerYuceer/YFecD/
From your controller you can get the values as show below:
// Thanks to LinqToSql you can define ur Sql-DB this way
YourDBDataContext db = new YourDBDataContext();
//
// POST: /YourForm/Edit
[HttpPost]
public ActionResult Edit(YourModel model)
{
try
{
// if users not empty..
if (model.users != null)
{
// Each User in Users
foreach (var user in model.users)
{ // Save it to your Sql-DB
db.Users.InsertOnSubmit(user);
db.SubmitChanges();
}
}
// Return
return RedirectToAction("Index");
}
catch (Exception ex)
{
return RedirectToAction("Error", new { ErrorMessage = "Message[" + ex.Message + "] - Source[" + ex.Source + "] - StackTrace[" + ex.StackTrace + "] - Data[" + ex.Data + "]" });
}
}
//
// GET: /YourForm/Error
public ActionResult Error(String ErrorMessage)
{
ViewData["Error"] = ErrorMessage;
return View();
}
simple as this!