Getting values from the html to the controller - asp.net

I'm trying to access the values a user introduces in a table from my controller.
This table is NOT part of the model, and the view source code is something like:
<table id="tableSeriales" summary="Seriales" class="servicesT" cellspacing="0" style="width: 100%">
<tr>
<td class="servHd">Seriales</td>
</tr>
<tr id="t0">
<td class="servBodL">
<input id="0" type="text" value="1234" onkeypress = "return handleKeyPress(event, this.id);"/>
<input id="1" type="text" value="578" onkeypress = "return handleKeyPress(event, this.id);"/>
.
.
.
</td>
</tr>
</table>
How can I get those values (1234, 578) from the controller?
Receiving a formcollection doesn't work since it does not get the table...
Thank you.

Using the FormCollection should work unless your table is not inside of a <form> tag
On top of Lazarus's comment, you can try this, but you have to set the name attribute for each:
<input id="seriales[0]" name="seriales[0]" type="text" value="1234" onkeypress="return handleKeyPress(event, this.id);"/>
<input id="seriales[1]" name="seriales[1]" type="text" value="578" onkeypress="return handleKeyPress(event, this.id);"/>
Now in your Action method you can make your method look like this:
[HttpPost]
public ActionResult MyMethod(IList<int> seriales)
{
// seriales.Count() == 2
// seriales[0] == 1234
// seriales[1] == 578
return View();
}
and seriales will be wired up to those values.

First Option:
Using FormCollection is the simplest way to access dynamic data. It is strange that you cannot get those values from it, can you check the following?
Is the table inside the
element?
Can you add name attribute
to the input elements? Note that
form items are bound by their names,
not id.
Second Option:
The second option is to add a collection in your model, and name everything accordingly. i.e.
public class MyModel
{
...
public IList<string> MyTableItems { get; set; }
}
and in your view use following names:
<input name="MyTableItems[]" value="" />

Related

How to post table rows data to a controller w/o using ajax in asp.net core

What is want to achieve is I have a form to adds rows with data to a html table, it's like a temporary table and all the data from it will be added in just one submit button. How can I possibly do this?
This is my sample table structure, data from it must be added to db
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<table class="table">
<thead>
<tr>
<!--some other fields-->
<th>Amount</th>
<th>Check #</th>
<th>Check Date</th>
</tr>
</thead>
<tbody>
<tr>
<!--some other fields-->
<td>
<input asp-for="Amount" class="form-control" />
<span asp-validation-for="Amount" class="text-danger"></span>
</td>
<td>
<input asp-for="Check_No" class="form-control" />
<span asp-validation-for="Check_No" class="text-danger"></span>
</td>
<td>
<input asp-for="Check_Date" class="form-control" />
<span asp-validation-for="Check_Date" class="text-danger"></span>
</td>
</tr>
<!--row 2-->
<!--row 3-->
<!--row 4-->
<!--etc..-->
</tbody>
</table>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
And here is my controller code so far, i don't know what do I need to change
// POST: Books/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Year,Month,Document_Code,GLA_Code,Expense_Code,Function_Code,Document_Reference_No,Document_Date,Quantity,Amount,Check_No,Check_Date,Remarks,Encoder")] Book book)
{
if (ModelState.IsValid)
{
_context.Add(book);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(book);
}
What must needed to be change in my view and controller, and help will is appreciated.
Thank you.
There's a couple of issues here.
First, if you've got a table of "books" (plural), the input names need to be indexed. You then also need to accept something like List<Book> instead of Book as the param to your action method. It's a little hard to tell with just the code provided, but I'd imagine you're repeating these inputs, all with the same names for each row. If that's the case, only the values for the last item will be posted. Making it a list of items enables you to post them all.
Simplistically, that means your inputs need to have names like [0].Amount, which Razor will generate for you if you use a for loop and render the inputs like:
<input asp-for="#Model[i].Amount" class="form-control" />
If you're adding the additional rows (and contained inputs) via JavaScript, you'll need to ensure that you're generating these indexed names properly yourself. A JS templating library may help in this regard.
Second, do not use Bind. Just don't. It's awful, horrible, and kills both puppies and kittens. For more explanation see my post, Bind is Evil. Use a view model instead. As a general rule you should never post an entity class. Your entity classes serve the database and its concerns, which are almost always different from the concerns of the view. Additionally, you should never just blindly save something posted by a user. Even if you insist on using your entity class to bind to, you can improve the security and safety of your code exponentially by literally mapping the values from the posted version of the class over to a new instance you create. Then, you know exactly what is being persisted to the database (without the godforsaken Bind) and you also have the opportunity to sanitize input as necessary.
I was facing a similar problem, but using ASP.NET Core 3.1 and Razor Pages. I was looking for a way to add and remove rows from a table with JavaScript, and then post it. My problem was to post the table without Ajax. Based in the question and in the accepted answer, I could do that.
Here is Index.cshtml.cs:
public class IndexViewModel {
public string Name { get; set; }
public IList<ResourceViewModel> Resources { get; set; }
}
public class ResourceViewModel {
public string Key { get; set; }
public string Value { get; set; }
}
public class IndexModel: PageModel {
[BindProperty]
public IndexViewModel ViewModel {get; set; }
public void OnGet() {
// You can fill your ViewModel property here.
}
public void OnPost() {
// You can read your posted ViewModel property here.
}
}
Here is Index.cshtml:
#page
#model IndexModel
#{
ViewData["Title"] = "Index";
}
<form method="post">
<div class="form-group">
<label asp-for="ViewModel.Name"></label>
<input asp-for="ViewModel.Name" class="form-control" />
</div>
<div class="form-group">
<table class="table">
<thead>
<th>Key</th>
<th>Value</th>
</thead>
<tbody>
#for(int i = 0; i < Model.ViewModel.Resources.Count; i++) {
<tr>
<td>
<input asp-for="ViewModel.Resources[i].Key" type="hidden" />
#Model.ViewModel.Resources[i].Key
</td>
<td>
<input asp-for="ViewModel.Resources[i].Value" type="hidden" />
#Model.ViewModel.Resources[i].Value
</td>
</tr>
}
</tbody>
</table>
</div>
<button type="submit" class="btn btn-primary">Send</button>
</form>
Notice I've used type="hidden" because I didn't want the user to edit the table directly.
I hope you find this useful!

Access value outside form using thymeleaf

I need to obtain vaulue of an input using thymeleaf and spring but haven't been able to do so. Since I need that value in a lot of the methods in the controller I can't put that input inside of one of the forms.
I tried to use javascript to pass on the value to a hidden input in the forms, however since I'm using th:each I'm only getting the value of the first input.
I also tried adding a string to the model and then trying to access that string with #ModelAttribute, but it didn't workout either.
This is the html:
<tr th:each="pro:${productos}">
<td th:text="${pro.id}">id</td>
<!-- More code here omitted for brevity-->
<td>
<div>
<form th:action="#{|/actualizarMas/${pro.id}|}" method="post">
<button type="submit" id="mas">+</button>
</form>
<form th:action="#{|/actualizarMenos/${pro.id}|}" method="post">
<button type="submit" id="menos">-</button>
</form>
<input name="masomenos"/>
<form th:action="#{|/${pro.id}|}" method="post">
<button type="submit">Borrar</button>
</form>
</div>
</td>
</tr>
This is the controller:
#RequestMapping(value = "/actualizarMenos/{productosId}", method = RequestMethod.POST)
public String eliminarUno(#PathVariable int productosId, RedirectAttributes redirectAttributes, #RequestParam("masomenos") String masomenos) {
//Code here using that string omitted for brevity
return "redirect:/";
}
I need to access the input with the name "masomenos", if that is posible, how could I do it?, if not, what options do I have? besides creating inputs inside all the forms.
Thank you very much.

Take object from list and pass to another method

As the title describes, using thymeleaf I display the contents of a list and then I put "Update" buttons next to each item on the list that send the particular object to an editing form page.
Here is the controller method for adding the list to the list view:
#RequestMapping("/list")
public String list(Model model){
List<Employee> employees = repository.findAll();
model.addAttribute("employees", employees);
return "list";
}
And here is the thymeleaf html code:
<tr th:each="emp : ${employees}">
<td th:text="${emp.id}"></td>
<td th:text="${emp.name}"></td>
<td th:text="${emp.surname}"></td>
<td th:text="${emp.age}"></td>
<td th:text="${emp.department}"></td>
<td>
<form th:action="#{/update}" method = "POST" th:object="${emp}">
<input type="hidden" th:field="*{id}"></input>
<input type="hidden" th:field="*{name}" ></input>
<input type="hidden" th:field="*{surname}"></input>
<input type="hidden" th:field="*{age}"></input>
<input type="hidden" th:field="*{department}"></input>
<button type = "submit">Update</button>
</form>
</td>
</tr>
And here is the receiving method:
#RequestMapping("/update")
public String update(#ModelAttribute("emp") Employee emp){
return "update";
}
I keep getting the following exception:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'emp' available as request attribute
Please let me know if you have any ideas on accomplishing this task.
This could be help.Change your controller like this.Its work for me.
model.addAttribute("emp", new Employee());
#RequestMapping("/list")
public String list(Model model){
List<Employee> employees = repository.findAll();
model.addAttribute("emp", new Employee());
model.addAttribute("employees", employees);
return "list";
}

Pass loop variable from Freemarker template to Spring controller

I am listing objects in a table in my view. I want to be able to edit an object using a button in the table.
<#list products as product>
<tr>
<td>${product.productName}</td>
<td>${product.price}</td>
<td>${product.quantity}</td>
<td>
<form name="product" method="post" action="/product/edit">
<input type="submit" name="submit" value="Edit this product"/>
</form>
</td>
</tr>
</#list>
The object then should be passed to a controller method:
#RequestMapping(value="/edit", method = RequestMethod.POST)
public ModelAndView edit(#ModelAttribute("product") Product product){
ModelAndView mav = new ModelAndView("product/edit");
mav.addObject("product", product);
return mav;
}
However, the product obtained by the edit method is null. How do I fix this? I tried to bind the product inside form using the code below, but that did not work either.
<form name="product" method="post" action="/product/edit">
<#spring.bind "product" />
<input type="hidden" name="${spring.status.expression}" value="${spring.status.value}"/>
<input type="submit" name="submit" value="Edit this product"/>
</form>
I want to use the POST method.
I would like to suggest a different approach. If I'm not mistaken you just want to pick an object for later editing - you don't really edit it in that very view.
If so, all you have to do is to pass an identifier of your object to your controller, but not the selected object itself.
If not, you should give us the hole story and provide the rest of the view as well.
Assuming I'm right the next question is why you need to use a form submission at all. Passing an id is best done by links - either as parameter or, if you follow REST-style, as part of the URI itself:
<!-- Link parameter -->
<#list products as product>
<tr>
<td>${product.productName}</td>
<td>${product.price}</td>
<td>${product.quantity}</td>
<td>
Edit ${product.productName}
</td>
</tr>
</#list>
<!-- REST-style -->
...
Edit ${product.productName}
...
productName isn't a good id of course. If products is a list (meaning, java.util.List) the index of the list is handy. Even in a HashMap or Set I'd create a unique id instead of using the product name.
Now that you can identify your object, select it in the backing code for later editing, but not in the view.
You'll find loads of examples of how to get link parameters in a controller. So, no need to go into detail here.
If however you insist on using a form and a POST-method then do it like this:
<form method="post" action="/product/edit">
<#list products as product>
<tr>
<td>${product.productName}</td>
<td>${product.price}</td>
<td>${product.quantity}</td>
<td>
<button value="${product.productName}" name="product" type="submit">Edit ${product.productName}</button>
</td>
</tr>
</#list>
</form>
Note that this won't work for older IE browsers (below Ver. 10), because they don't return the value, but everything that is inside the button tag.
Hidden inputs and a single submit button won't help at all, because all inputs are submitted and using different forms is not the way either.

asp.net mvc 3, dynamic array

I am a beginner in ASP.Net MVC 3
I will make a dynamic array initially must show me the first ten elements, and when I click view more displays all array elements
here's what I did:
<table>
#foreach (var tweet in Model)
{
<tr>
<td>
<img alt="" src="#tweet.ProfileImageUrl" />
<br />
<input id="rowIDs" type="checkbox" />
</td>
<td>
<strong>#tweet.Name</strong>
<br />
Friends: <strong>#tweet.FriendsCount</strong>
</td>
</tr>
}
</table>
thank you in advance
You have to put 10 items in the controller,
return View(array.Take(10).Skip(page));
Do not use the button anymore. Use the pager.
You need to peredovat variable Pag.
The easiest way(on my opinion) is to create a anchor to the page, itself, with a query string.
Your View must have an anchor like this:
All Comments
And relative controller(HttpGet, not HttpPost(if it has any)) must be something like this:
public ViewResult List(bool fullComment=false)
{
if (fullComment)
return View(dbContext.EntityList.ToList());
else
return View(dbContext.EntityList.Take(5).ToList());
}
Note: if the page has querystring already, in creating anchor link, in view, you must pay attention to this.

Resources