Button not passing variable to controller - c#

I am new to ASP.net core and have run into an issue with passing a variable form a button to the controller. The examples that I have found seem to be straight forward and simple regarding this but I must be doing something wrong since I cannot get it to work. I am attempting to pass the variable in #Reload.Mail_Id to the method RecallRecord in the controller. If some one could tell me what I'm missing I would really appreciate it.
View
<thead>
<tr>
<th>Mail ID</th>
<th>Process Date</th>
<th>Name</th>
<th>Address</th>
<th>Brochure Order Name</th>
</tr>
</thead>
<tbody>
#foreach (var Reload in Model)
{
<tr>
<td class="text-center">#Reload.Mail_Id</td>
<td class="text-center">#Reload.Created_Date</td>
<td class="text-left">#Reload.Pax_Name_Envelope</td>
<td class="text-right">#Reload.Address_1</td>
<td class="text-right">#Reload.Brochure_Order_Name</td>
<td>
<form asp-action="RecallRecord" method="post">
<input type="number" name="Mail_Id" value="#Reload.Mail_Id" />
<button type="submit" class="btn btn-sm btn-danger">
Recall
</button>
</form>
</td>
</tr>
}
</tbody>
</table>
Contoller
public RedirectToActionResult RecallRecord(int MailID)
{
{
using (var ctx = new BrochureDbContext())
{
var reloadSet = ctx.Reload.FromSql($"usp_OAK_Brochure_Reload {MailID}")
.ToList();
return RedirectToAction("ReloadOrders");
}
}
}

change your method as below
public RedirectToActionResult RecallRecord(int Mail_Id)
{
{
using (var ctx = new BrochureDbContext())
{
var reloadSet = ctx.Reload.FromSql($"usp_OAK_Brochure_Reload {Mail_Id}")
.ToList();
return RedirectToAction("ReloadOrders");
}
}
}

Related

Get element value in Razor with Jquery

I have a foreach loop like that.I want to get item id when pressed "delete" button.
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Name - Sirname</th>
<th>Date - Time</th>
<th>Message</th>
<th>id</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Items)
{
<tr>
<th>#(Model.Items.IndexOf(item)+1)</th>
<td>#item.Name</td>
<td>#item.DateTime</td>
<td>#item.Message</td>
<td id="itemId">#item.id</td>
<td><button class="btn btn-danger">Delete</button></td>
</tr>
}
</tbody>
</table>
my Qjuery is like that;
$("button").click(function () {
var id = $("#itemId").html();
$("#sonuc").html(id);
});
});
and my result must be in it;
<p id="sonuc"> </p>
But everytime it shows only first item's id of table. So how can i get value of each element in loop with Jquery?
You can use var id = $(this).parent().prev().text();
Demo
$("button").click(function() {
var id = $(this).parent().prev().text();
$("#sonuc").html(id);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Name - Sirname</th>
<th>Date - Time</th>
<th>Message</th>
<th>id</th>
</tr>
</thead>
<tbody>
<tr>
<th>#(Model.Items.IndexOf(item)+1)</th>
<td>#item.Name</td>
<td>#item.DateTime</td>
<td>#item.Message</td>
<td>#item.id1</td>
<td><button class="btn btn-danger">Delete</button></td>
</tr>
<tr>
<th>#(Model.Items.IndexOf(item)+1)</th>
<td>#item.Name</td>
<td>#item.DateTime</td>
<td>#item.Message</td>
<td>#item.id2</td>
<td><button class="btn btn-danger">Delete</button></td>
</tr>
</tbody>
</table>
<p id="sonuc"> </p>
Id must be unique for each element and if you want to get value of Item Id and use razor after pressing delete button you can set value of Item Id on delete button as Id or data attribute so
you can try
<td id="itemId_#item.id">#item.id</td>
<button id="#item.Id" class="btn btn-danger">Delete</button>
instead of
<td id="itemId">#item.id</td>
<button class="btn btn-danger">Delete</button>
$("button").click(function () {
var id = this.id; // value of itemId
});
});

Implement delete button on each table row using model binding and POST request

On my view, I have a table with a form that I want to use to delete a particular row. I use a foreach loop to generate an hidden input field with the row value that I want to pass to the controller and asp-for tag for model biding, and a submit button.
The value that is passed to the controller is always the first row. I'm inclined to think that the reason for this behavior is that the generated input fields all have the same name attribute, because the asp-for expression is invariant for every iteration of the foreach loop.
Is there a straight-forward way to implement this using a form and a POST request, or should I just use anchors with route values, i.e., GET requests?
Here's my ViewModel:
public class RolesViewModel
}
public IList<AppUser> UsersInRole {get; set;}
public string SelectedRole {get; set;}
public RemoveUserFromRole RemoveUser {get; set;}
public class RemoveUserFromRole
{
public string UserName {get; set;}
public string RoleName {get; set;}
}
}
My View
<form method="post" asp-action="RemoveUser" id="removeUserForm"></form>
<table id="userTable" class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">User name</th>
<th scope="col" class="text-center">Delete</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model.UsersInRole)
{
<tr>
<td>#user.UserName</td>
<td class="text-center">
<input form="removeUserForm" asp-for="RemoveUser.UserName" type="hidden" value="#user.UserName" />
<input form="removeUserForm" asp-for="RemoveUser.RoleName" type="hidden" value="#Model.SelectedRoleName" />
<button form="removeUserForm" type="submit" class="btn btn-sm btn-link text-danger py-0 my-0">
<i class="fas fa-times"></i>
</button>
</td>
</tr>
}
</tbody>
</table>
And my action method in controller
[HttpPost]
public async Task<IActionResult> RemoveUser(RolesViewModel model)
{
//model.RemoveUser.UserName always have the value from the first row
var user = await _userManager.FindByNameAsync(model.RemoveUser.UserName);
if (user == null)
return RolesError(await GetModel());
var result = await _userManager.RemoveFromRoleAsync(user, model.RemoveUser.RoleName);
if (!result.Succeeded)
return RolesError(await GetModel());
return RedirectToAction("Roles", new { roleName = model.RemoveUser.RoleName });
}
Thanks in advance for your time.
According to your codes, I found you have multiple hidden filed which contains the user.UserName.
If you click the submit button, it will upload all the hidden filed value to the code-behind and it will just bind the first one, this is the reason why your model is always first one.
You could find the formdata in F12 developtool's network.
To solve this issue, we have a easily but not a good solution.
We could set mutiple form tag in your table to avoid post all the all the hidden filed username value to controller:
Like below:
<table id="userTable" class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">User name</th>
<th scope="col" class="text-center">Delete</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model.UsersInRole)
{ int i = 0;
<tr>
<td>#user.UserName</td>
<td class="text-center">
<form method="post" asp-action="RemoveUser" id="#user.UserName">
<input form="#user.UserName" name="RemoveUser.UserName" type="hidden" value="#user.UserName" />
<input form="#user.UserName" name="RemoveUser.RoleName" type="hidden" value="#Model.SelectedRole" />
<button form="#user.UserName" type="submit" class="btn btn-sm btn-link text-danger py-0 my-0">
<i class="fas fa-times">iiiii</i>
</button>
</form>
</td>
</tr>
}
</tbody>
</table>
If you choose this way, you should rebuild all your view's html makeup.
Besides, you could try to use ajax to achieve your requirement, this solution is better than before solution. You could use jquery to get the right form data according to the submit button's id or position and then use jquery ajax to post the form data into controller. Then you could return the redirect url instead of RedirectToAction methods.
More details about how to use ajax to send form data, you could refer to below codes:
#model MVCRelatedIssue.Models.RolesViewModel
#{
ViewData["Title"] = "Index";
}
<h1>Index</h1>
<form method="post" asp-action="RemoveUser" id="removeUserForm">
<table id="userTable" class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">User name</th>
<th scope="col" class="text-center">Delete</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model.UsersInRole)
{
<tr>
<td>#user.UserName</td>
<td class="text-center">
<input form="removeUserForm" name="RemoveUser.UserName" type="hidden" value="#user.UserName" />
<input form="removeUserForm" name="RemoveUser.RoleName" type="hidden" value="#Model.SelectedRole" />
<button form="removeUserForm" type="submit" id="submit" class="btn btn-sm btn-link text-danger py-0 my-0 subbtn">
<i class="fas fa-times">iiiii</i>
</button>
</td>
</tr>
}
</tbody>
</table>
</form>
#section Scripts{
<script>
$(document).ready(function () {
$(".subbtn").bind("click", function (e) {
e.preventDefault();
var formdata = new FormData();
var UserName = $(this).prev().prev().val();
formdata.append("RemoveUser.UserName", UserName);
console.log(UserName);
var roleName = $(this).prev().val();
formdata.append("RemoveUser.RoleName", roleName);
console.log(roleName);
$.ajax({
type: "POST",
url: "/RemoveUser/RemoveUser",
data: formdata,
contentType: false,
processData: false,
success: function (data) {
alert("success");
window.location.href = data;
}
});
});
});
</script>
}
Controller:
[HttpPost]
public async Task<IActionResult> RemoveUser(RolesViewModel model)
{
//model.RemoveUser.UserName always have the value from the first row
//var user = await _userManager.FindByNameAsync(model.RemoveUser.UserName);
//if (user == null)
// return RolesError(await GetModel());
//var result = await _userManager.RemoveFromRoleAsync(user, model.RemoveUser.RoleName);
//if (!result.Succeeded)
// return RolesError(await GetModel());
string redirecturl = "/RemoveUser/Roles?roleName=" + model.RemoveUser.RoleName;
return Ok(redirecturl);
}
Result:
You can use a Delete Link
in View
#foreach (var user in Model.UsersInRole)
{
<a href="#Url.Action("RemoveUser", "YOUR_Controller",new {username = user.UserName})"
onclick="return confirm('Do You want to Delete');"
</a>
}
In Controller
[HttpGet]
public async Task<IActionResult> RemoveUser(String username)
{
// Get the user Object the delete it
}
I was capable of solving this issue with minimal code footprint.
As it turns out, <td> tags can have forms, so, knowing that, it is possible to have a different form on each row, like so:
View:
//Remove inline table form
<table id="userTable" class="table table-striped table-sm">
<thead>
<tr>
<th scope="col">User name</th>
<th scope="col" class="text-center">Delete</th>
</tr>
</thead>
<tbody>
#foreach (var user in Model.UsersInRole)
{
<tr>
<td>#user.UserName</td>
<td class="text-center">
//now each form will have the correct, row-wise formdata
<form method="post" asp-action="RemoveUser">
<input asp-for="RemoveUser.UserName" type="hidden" value="#user.UserName" />
<input asp-for="RemoveUser.RoleName" type="hidden" value="#Model.SelectedRoleName" />
<button type="submit" class="btn btn-sm btn-link text-danger py-0 my-0">
<i class="fas fa-times"></i>
</button>
</form>
</td>
</tr>
}
</tbody>
</table>

Table data not posting to controller

I have the following table:
<form method="post" asp-action="Index" asp-controller="Record">
<table class="table table-hover">
<thead>
<tr>
<th scope="col"><input type="checkbox" id="chkAll"></th>
<th scope="col">Created</th>
<th scope="col">User Reference</th>
<th scope="col">Type</th>
<th scope="col">Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
#foreach (var rec in Model.Data)
{
<tr>
<td style="display: none">
#Html.TextBoxFor(m => rec.Id)
</td>
<td>
#Html.CheckBoxFor(m => rec.IsChecked)
</td>
<td>#rec.Created</td>
<td>#rec.UserReference</td>
<td>#rec.Type</td>
<td>#rec.Status</td>
<td>
<input name="submit" type="submit" id="process" value="submit" />
</td>
</tr>
}
</tbody>
</table>
</form>
The issue I have is when I press submit I'm expecting to pass the content of the table into my controller, however when I submit the form the model on my controller is null:
[HttpPost]
public async Task<IActionResult> Index(List<UserData> data)
When I submit the form I expect to have a list of id's and checkbox values either true / false, can someone shed some light into why I'm not able to see this within the post method of the controller?
Found the solution of the following thread, seems switching foreach to for resolved the issue.

How to pass List<Tuple> from Table to Controller?

I have this code in C# using EF Core 1.2 where I have a form containing two submit buttons. The first button 'upload' invokes my method 'UpLoadMyFile' which compares
each line from my textarea to a pattern and returns a string which tells me if it matches one pattern.
Then I add all my text and its states into a
List <Tuple<string, string>>
that I pass to my View via a ViewModel and display each line plus its state in a table.
Now I'm trying to save each line into my database when I click my second button 'save'. But every time I try to save my lines a NullReferenceException occurs
which tells me my List from my table is null.
I would like to know how to pass all lines and states from my Table 'MyTupleList' to my Post Method since I really don't know how to fix my problem.
My View:
#model Models.ViewModels.CreateSaetzeModelView
<form asp-action="ProcessCreateLines" asp-controller="SoftwareService" method="post" enctype="multipart/form-data">
<div class="div-marginBottom">
<table class="table">
<tbody>
<tr>
<td>
<textarea name="ExpressionTextarea" id="ExpressionTextarea" runat="server" TextMode="MultiLine" asp-for="#Model.LoadExpressions"></textarea>
<div class="col-md-10">
<input type="submit" name="upload" value="upload" /> !--Calls 'uploadmyfile' action-->
</div>
</td>
<td></td>
</tr>
</tbody>
</table>
</div>
<br />
<div class="div-ExpressionEingabe">
</div>
#if (Model.MyLinesList != null)
{
<div class="div-marginBottom">
<table id="MyTupleList" class="table table_align">
<thead>
<tr>
<th>
State
</th>
<th>
MyLines
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.MyLinesList)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Item2)
</td>
<td>
#Html.DisplayFor(modelItem => item.Item1)
</tr>
}
</tbody>
</table>
<input type="submit" name="save" value="save" />
</div>
}
My Code:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ProcessCreateLines(string upload, string save, CreateLinesModelView cmv)
{
//Button 'upload': Checking my lines
if (!string.IsNullOrEmpty(upload))
{
string expressions = Request.Form["ExpressionTextarea"].ToString();
List<Tuple<string, string>> result = new FileUploadController().CheckExpressions(expressions);
cmv.MyLinesList = result;
return View("ProcessCreateLines", cmv);
}
//Button 'save': Saving my lines into a Database
if (!string.IsNullOrEmpty(save))
{
// ****************************MyLinesList is null*******************
var list = cmv.MyLinesList;
...saving my list into database...
}
}
I managed to solve my problem thanks to the comment of #StephenMuecke by using instead of a Tupel a selfmade class
public class MyListModel
{
public string myLine { get; set; }
public string myState { get; set; }
}
}
and creating a List out of it in my ViewModel
public List<MyListModel> LineWithState { get; set; }
Also in my View I replaced the foreach loop with a for loop
#for (int i = 0; i < Model.LineWithState.Count; i++)
{
<tr>
<td>
#Html.TextBoxFor(m=>m.LineWithState[i].myState)
</td>
<td>
#Html.TextBoxFor(m=>m.LineWithState[i].myLine)
</tr>
}

add edit table, how to change a row to edit mode?

Below is my razor code for my table of users and the current add/edit layout
<table class="smalltable" cellpadding="0" cellspacing="0" id="tblUsers">
<thead>
<tr>
<th> </th>
<th>First Name</th>
<th>Last Name</th>
<th>Dept</th>
<th>Assyst Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>#{ Html.BeginForm("AddEditUser", "Home"); }
<input type="submit" value="Add" id="btnSave" name="cmd" class="plain-button" />
</td>
<td>#Html.Editor("Forename")</td>
<td>#Html.Editor("Surname")</td>
<td>#Html.DropDownList("lstDepts")</td>
<td>#Html.Editor("AssystName")
#{ Html.EndForm(); }</td>
</tr>
#foreach (var User in Model)
{
<tr>
<td>#Html.ActionLink("Edit", "AddEditUser", new { id = User.ID }, new { name = "cmd", value = "Edit" })</td>
<td>
#User.Forename
</td>
<td>
#User.Surname
</td>
<td>
#User.Dept
</td>
<td>
#User.AssystName
</td>
</tr>
}
</tbody>
</table>
What i want to achieve is when a edit is pressed, the row that the edit link was on turns into edit boxes, i how to load up the add form with the edit users details (i could use hidden id and set it with querystring) but i wanted to edit in place really
anyone know how to do this or can point me in the right place?
THanks

Categories

Resources