how to use webgrid and html helper method on the same view - asp.net-mvc-3

In asp.net mvc3 project iam using ienumerable view to display collection of object in the webgrid. In the same view i am using html helper methods to create object. i got the error in the helper method "System.collection.generic.ienumerable<...> does not contain definition for <...>"
#model IEnumerable<TRADEBLOTTER_MVCPOC.Models.Trader />
#{
ViewBag.Title = "NewTrader";
}
#{
var grid = new WebGrid(source: Model,
defaultSort: "TradeID",
rowsPerPage: 5, fieldNamePrefix: "wg_",
canPage: true, canSort: true,
pageFieldName: "pg", sortFieldName: "srt" );
}
<h2>NewTrader</h2>
#using (Html.BeginForm(FormMethod.Post))
{
#Html.ValidationSummary()
<table cellpadding="0" cellspacing="0" width="100%">
<tr>
<td>
#Html.LabelFor(t=>t.TraderName,"Trader Name")
</td>
<td>
#Html.TextBoxFor(t=>t.TraderName)
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type="submit" value="Submit Trader" />
</td>
</tr>
</table>
}

I think typically you would use something like that in the model above your variable
[DisplayName("Trader Name")]
public string TraderName { get; set; }
and then your view
<h2>NewTrader</h2>
#using (Html.BeginForm(FormMethod.Post))
{
#Html.ValidationSummary()
<table cellpadding="0" cellspacing="0" width="100%">
<tr>
<td>
#Html.LabelFor(t=>t.TraderName)
</td>
<td>
#Html.TextBoxFor(t=>t.TraderName)
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type="submit" value="Submit Trader" />
</td>
</tr>
</table>
}

My suggestion: use a partial page for the grid (with the IEnumerable version of the model) and another partial page for the individual variables (with the single model).
If the grid is to display information only, and not to edit anything, then bind the grid to a method defined in the model - then there is no need for the view to have an IEnumberable model.

Related

Bootstrap Modal window and Thymeleaf

I have a project with Spring Mvc and I want to use Bootstrap modal windows and Thymeleaf. I hava a view students.jsp witch get list of students from model when I make loop without Thymeleaf everything work ok.
I use JS. But when I use Thymeleaf model windows didn't work ok.
<table class="table table-hover">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
<tr id="user-${user.id}" th:each="user: ${students}">
<td th:text="${user.id}" />
<td th:text="${user.firstName}" />
<td th:text="${user.lastName}" />
<td>
<button type="button" class="btn btn-primary editButton"
data-toggle="modal" data-target="#myModal" data-user-id="${user.id}">Edit</button>
</td>
</tr>
</tbody>
</table>
<script type="text/javascript">
$("#myModal").on('show.bs.modal', function(e) {
var userId = $(e.relatedTarget).data('user-id');
var cols = $('#user-' + userId + ' td');
var firstName = $(cols[0]).text();
var lastName = $(cols[1]).text();
var email = $(cols[2]).text();
$('#firstNameInput').val(firstName);
$('#lastNameInput').val(lastName);
$('#emailInput').val(email);
});
$("#myModal").on('hidden.bs.modal', function() {
var form = $(this).find('form');
form[0].reset();
});
</script>
It doesn't get data from list. I don't know how to solve this problem. Please help me :)
There's a small problem with data-user-id attribute in your "Edit" button.
Instead of:
data-user-id="${user.id}"
...you should have:
th:data-user-id="${user.id}"
...so that the attribute is processed by Thymeleaf and ${user.id} actually replaced with expected value.
<tr th:each="user: ${students}" th:id="'user-' + ${user.id}">
<td th:text="${user.id}" />
<td th:text="${user.firstName}" />
<td th:text="${user.lastName}" />
<td th:text="${user.email}" />
<td>
<button type="button" class="btn btn-primary editButton"
data-toggle="modal" data-target="#myModal"
th:data-user-id="${user.id}">Edit</button>
</td>
</tr>

Pass id to the controller

Firstly, I am passing values from database to the table. In the first column I want to create a form that will pass the id to delete function in Controller.
<tr th:each="blg: ${all}" th:object="${blg}" >
<td>
<form th:action="#{/delete}" th:object= "${blg}" method="post">
<input type="text" th:field="${blg.id}"/>
<button type="submit">Delete</button>
</form>
</td>
<td th:text="*{title}"> title </td>
<td th:text="*{content}"> title </td>
<td th:text="*{category}"> title </td>
<td th:text="*{signature}"> title </td>
</tr>
Controller:
#GetMapping("/show")
public String show(Model model){
List<Blog> all = br.findAll();
model.addAttribute("all",all);
return "show";
}
#RequestMapping(value="/delete", method=RequestMethod.POST)
public String deletePost(#RequestParam Long id){
br.delete(id);
return "redirect:/show";
}
The thymeleaf engine doesn't map the object as this error occcurs:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'blg' available as request attribute.
What is the way to create a correct form in this case?
Update your html code as shown below:
<tr th:each="blg: ${all}" >
<td>
<form th:action="#{|/delete/${blg.id}|}" method="post">
<button type="submit">Delete</button>
</form>
</td>
<td th:text="${blg.title}"> title </td>
<td th:text="${blg.content}"> title </td>
<td th:text="${blg.category}"> title </td>
<td th:text="${blg.signature}"> title </td>
</tr>
Better to use HTTP method DELETE for delete operations.
The reason because th:object tried to look in your request attribute for the attribute blg. But blg is a result of an iteration.

Values for th:field attributes in checkbox

I have table with datas from database (insert dynamically). In one column I insert checkbox. Now I want to select one of them and send to next form (I select one product and send properties to another form. In this form should be displayed properties only the select product). But I don't know what kind of value insert in th:field="*{}". I tried many solutions but doesn't work. My html form with all products table:
<form action="/oferta/zamow" th:action="#{/oferta/zamow}"
th:object="${oferta}" method="post">
<table border="1" id="display-data">
<tr>
<td>#</td>
<td>title</td>
<td>author</td>
<td>rok</td>
<td>cena</td>
<td></td>
</tr>
<tr th:each="produkt, pozycja : ${oferta}">
<td th:text="${pozycja.count}"></td>
<td><span th:text="${produkt.tytul}"></span></td>
<td><span th:text="${produkt.autor}"></span></td>
<td><span th:text="${produkt.rok}"></span></td>
<td><span th:text="${produkt.cena}"></span></td>
<td>
<input type="submit" value="zamow"/>
<!-- <a th:href="#{/zamowienie}">zamow</a> -->
</td>
<td>
<label>zamow</label>
<input type="checkbox" th:field="*{produkt}" th:value="${produkt}"/>
</td>
</tr>
</table>
</form>
Form to display select product:
<form action="/zamowienie/zam" th:action="#{/zamowienie/zam}"
th:object="${zamowienie}" method="post">
<table border="1" id="display-data">
<tr align="center">
<td colspan="2">twoje zamowienie</td>
</tr>
<tr>
<td>tytul</td>
<td><span th:text="${produkt.tytul}"></span></td>
</tr>
<tr>
<td>autor</td>
<td><span th:text="${produkt.autor}"></span></td>
</tr>
<tr>
<td>rok</td>
<td><span th:text="${produkt.rok}"></span></td>
</tr>
<tr>
<td>cena</td>
<td><span th:text="${produkt.cena}"></span></td>
</tr>
<tr>
<td>data zlozenia zamowienia</td>
<td><span th:text="${datazam}"></span></td>
</tr>
</table>
</form>
Thanks for help.
I am not sure if this is the answer you seek, but you can find an example at http://www.thymeleaf.org/doc/html/Thymeleaf-Spring3.html#checkbox-fields.
Here is a simple example to illustrate how to use a checkbox in Thymeleaf with Spring MVC.
Controller:
#RequestMapping(value = "/showForm", method=RequestMethod.GET)
public String showForm(Model model) {
List<String> allItems = new ArrayList<String>();
allItems.add("value1");
allItems.add("value2");
allItems.add("value3");
model.addAttribute("allItems", allItems);
Foo foo = new Foo();
List<String> checkedItems = new ArrayList<String>();
// value1 will be checked by default.
checkedItems.add("value1");
foo.setCheckedItems(checkedItems);
model.addAttribute("foo", foo);
...
}
#RequestMapping(value = "/processForm", method=RequestMethod.POST)
public String processForm(#ModelAttribute(value="foo") Foo foo) {
// Get value of checked item.
List<String> checkedItems = foo.getCheckedItems();
...
}
html:
<form action="#" th:action="#{/processForm}" th:object="${foo}" method="post">
<div th:each="item : ${allItems}">
<input type="checkbox" th:field="*{checkedItems}" th:value="${item}" />
<label th:text="${item}">example</label>
</div>
<input type="submit" />
</form>
Foo.java:
public class Foo {
private List<String> checkedItems;
public List<String> getCheckedItems() {
return checkedItems;
}
public void setCheckedItems(List<String> checkedItems) {
this.checkedItems = checkedItems;
}
}
Hope this helps.
Take a look at the thymeleaf spring integration docs.
All th:field are mapped against the command object. Thats why you need the *{} expression.
One thing the template engine is not able to do (yet) is mapping fields inside a loop directly. So you cannot use the *{} approach to reference the produkt variable from the loop.
What you have to do is use the index of the th:each expression and build a property accessor with a pre-evaluated expression for the index.
<input type="checkbox" th:field="*{produkts[__${index}__].checked" />
You do not need the th:value, th:field is taking care of it. (Except if you want to superseed it)

HTTP POST, GET in MVC?

In MVC3, i created one register form. I created one model,,controller and view. This is my code:
[HttpGet]
public ActionResult Insert()
{
Models.Employees objEmpl = new Models.Employees();
return View(objEmpl);
}
[HttpPost]
[AcceptVerbs("Post")]
public ActionResult Insert(Models.Employees objs)
{
var v = new Models.test().InsertDl(objs);
return View();
}
The above is my controller
#model MvcVideo.Models.Employees
#{
ViewBag.Title = "Insert";
Layout = "~/Views/Shared/VideoLayout.cshtml";
}
<h2>Insert</h2>
#using(Html.BeginForm("Insert","Home",FormMethod.Post ))
{
<table>
<tr>
<td>
Employee Name
</td>
<td>
#Html.TextBox("Ename",#Model.Enames)
</td>
</tr>
<tr>
<td>
Department Id
</td>
<td>
#Html.TextBox("Departmentid",#Model.DepartId )
</td>
</tr>
<tr>
<td>
Email Id
</td>
<td>
#Html.TextBox("Emailid",#Model.EmailIds)
</td>
</tr>
<tr>
<td>
Address
</td>
<td>
#Html.TextBox("Address",#Model.Adress)
</td>
</tr>
<tr>
<td colspan="2" style="text-align:center;" >
<button title ="Ok" value="OK"></button>
</td>
</tr>
</table>
}
But the objs object at public actionresult Insert(models.Empoyees objs) action method parameter is showing null values. Imean Ename=Null, Department=0, Emailid=Null and Address=null
It isn't working because the names you've provided in your Html helpers don't match up with the property names on your model, so the default model binder can't resolve them when the values get posted back.
Using Html.TextBoxFor instead of Html.TextBox will provide you with strong typing against your model, and is the safer approach.
Replace this
#Html.TextBox("Ename",#Model.Enames)
With
#Html.TextBoxFor(model => model.Enames)
This will fix your issue.

Updating multiple items within same view

I am trying to make a stock take application, My view loads all my stock with one editor.
My controller is not getting any of the data from the view?
I want to be able to edit all my stock at the same time?
How can I do this
Model Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace FlatSystem.Models
{
public class Stock
{
public int ID { get; set; }
public string Item_Name { get; set; }
public int Actual_Stock { get; set; }
public int Wanted_Stock { get; set; }
}
}
View Code
#model IEnumerable<FlatSystem.Models.Stock>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="sidemenu">
<div class="sidemenu-heading">
ReStock
</div>
<div class="div-body">
<table>
<tr>
<th>
Item Name
</th>
<th>
Wanted Stock
</th>
<th>
Stock On Hand
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Item_Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Wanted_Stock)
</td>
<td>
<div class="editor-field">
#Html.EditorFor(modelItem => item.Actual_Stock)
#Html.ValidationMessageFor(modelItem => item.Actual_Stock)
</div>
</td>
#Html.HiddenFor(modelItem => item.ID)
</tr>
}
</table>
</div>
</div>
<input type="submit" value="Submit" />
}
Controller Code
[HttpPost]
public ActionResult ReStock(List<Stock> stock)
{
foreach (var item in stock)
{
if (ModelState.IsValid)
{
GR.InsertOrUpdate(item);
}
}
GR.Save();
return RedirectToAction("Restock");
}
It's hard to answer your question without model class, but idea is that your edit inputs must contain index in name attribute.
Something like this:
#for(int i = 0: i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].Item_Name)
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].Wanted_Stock)
</td>
<td>
<div class="editor-field">
#Html.EditorFor(modelItem => Model[i].Actual_Stock)
#Html.ValidationMessageFor(modelItem => Model[i].Actual_Stock)
</div>
</td>
#Html.HiddenFor(modelItem => Model[i].ID)
</tr>
}
Added:
Sorry, thanks to Darin Dimitrov, you can't access IEnumerable by index, use List or Array.
You could use editor templates. I would recommend you to first read the following article in order to understand why your code doesn't correctly bind the collection. Once you understand that you could do the following:
#model IEnumerable<FlatSystem.Models.Stock>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<div class="sidemenu">
<div class="sidemenu-heading">
ReStock
</div>
<div class="div-body">
<table>
<thead>
<tr>
<th>Item Name</th>
<th>Wanted Stock</th>
<th>Stock On Hand</th>
<th></th>
</tr>
</thead>
<tbody>
#Html.EditorForModel()
</tbody>
</div>
</div>
<input type="submit" value="Submit" />
}
and now define a custom editor template for the Stock type which will automatically be rendered for each element of the collection (~/Views/Shared/EditorTemplates/Stock.cshtml) - the name and location of the editor template is important as it works by convention:
#model FlatSystem.Models.Stock
<tr>
<td>
#Html.DisplayFor(x => x.Item_Name)
</td>
<td>
#Html.DisplayFor(x => x.Wanted_Stock)
</td>
<td>
<div class="editor-field">
#Html.EditorFor(x => x.Actual_Stock)
#Html.ValidationMessageFor(x => x.Actual_Stock)
</div>
</td>
#Html.HiddenFor(x => x.ID)
</tr>
Remark: You might also want to include the Wanted_Stock and Item_Name as hidden fields along with the ID in the editor template in order for their values to be sent to the server, because you don't have a corresponding input field for them.

Resources