Thymeleaf future/past dates - thymeleaf

I have a database with a timesheet table which has an id column and wcdate(week commencing) column. I have 4 scenarios to accomplish on a web page, using Thymeleaf.
I am new to Thymeleaf, I have looked at Thymeleaf regarding dates, but I flummoxed about how to manipulate a date for instance more than week ago, do something. There are four scenarios which work on timesheet table and wcdate column. I didn't use the <pre> </pre> tags because the code didn't show up correctly.
<!--if the id is 0 but the wcdate is in the future, show as available-->
<span th:if="${timesheet.id == 0 AND timesheet.wcdate.after()}"
class="available">AVAILABLE</span>
<!--if the timesheet id is 0 and the wcdate is today or in the past, show as missing-->
<span
th:unless="${timesheet.id == 0 AND timesheet.wcdate.createNow(),'YYYY/MM/dd HH:mm')}"
class="missing">MISSING</span>
<!--if timesheet is 0-->
<span
th:unless="${timesheet.id == 0}"
class="draft">DRAFT</span>
<!--if the id is not 0 but the wcdate is more than a week ago -->
<span
th:unless="${timesheet.id == !0 AND timesheet.wcdate.}"
class="overdue">OVERDUE</span>

There is no need to directly expose an entity to your template, you can expose additional helper variables to make your templates simpler.
I am currently supposing that your controller looks something like this:
#GetMapping
public String showTimesheet(Model model) {
Timesheet timesheet = ... // from service or repo
model.addAttribute("timesheet", timesheet );
}
You can do something like this:
#GetMapping
public String showTimesheet(Model model) {
Timesheet timesheet = ... // from service or repo
model.addAttribute("timesheet", timesheet );
model.addAttribute("timesheetStatus", calculateTimesheetStatus(timesheet) );
}
And your template becomes:
<span th:class="${timesheetStatus}">${timesheetStatus}</span>
This way, you can do the calculations in Java.
If the Timesheet class has all the info, you can also expose a getStatus() method and use something like this for the template:
<span th:class="${timesheet.status}">${timesheet.status}</span>

Related

Grails - How to send one ID from view to controller (many-to-many relationship)

I am trying to send an ID of an iterated item but I think the whole list is being sent. How can I send just one ID?
I have STUDENT and COURSE domain class.
Domain Model
class Student {
String fullName
String toString() {
"$fullName"
}
static belongsTo = [school: School]
static hasMany = [courses:Course, studentCourses:StudentCourse]
}
class Course {
String course
String toString() {
"$course"
}
static hasMany = [studentCourses:StudentCourse]
static belongsTo = Student
}
class StudentCourse {
Student student
Course course
//Some methods...
}
And this is my edit view.
<g:if test="${studentInstance.studentCourses?.course}">
<g:each class="courseList" in="${studentInstance.studentCourses?.course}" var="courses">
<li class="courseList">
<span class="courseList" aria-labelledby="courses-label">${courses.id} ${courses}
<g:actionSubmitImage class="deleteIcon" action="deleteCourse" value="delete"
src="${resource(dir: 'images', file: 'delete.png')}" height="17"
onclick="return confirm('${message(code: 'default.button.delete.confirm.message', default: 'Are you sure?')}');"
params="${courses.id}"/></span>
</li>
</g:each>
</g:if>
I'd like to be able to delete one course from the list when user clicks delete.png image. But when I println params.course the parameter is being sent as a whole list, not as an individual item of the list even though it is within g:each tag. How can I just send one corresponding item to the controller?
My edit page has a list of courses.
Course 23 English (delete icon here)
42 Science (delete icon here)
67 Math (delete icon here)
In my println params.course this is what I see.
[ English, Science, Math ]
How can I just have [English] when user clicks the delete button next to English line?
Thank you in advance.
As far as I have understand your problem, The problem should be in your taglib
I am giving you the example of similar code and this is working.
<g:each in="${student?.studentCourses?.course}" var="course">
<div>
<span>${course.id} ${course.course}</span>
<g:link controller="login" action="delete" params="[courseId:course.id]">
Delete
</g:link>
</div>
In this block of code, by clicking delete link with params having params="${[id:course.id]}, it will redirect to delete action inside login controller. Print params in delete action and you will get output as
params: [courseId:2, action:delete, format:null, controller:login]
Here you can see your params.courseId is only a Long value not a list.
Hope it will help you understand your problem.

grails render list of checkboxes

I've scoured the web for almost a day and can't seem to find a solution to my problem.
I have a lookup table called Hobby which has a bunch of hobbies in it (camping, hiking, biking, etc). The hobbies table is populated during the bootstrap. Grails creates a hobby table with an id, and description field.
I have a domain object called Applicant. An applicant can have zero or more hobbies. I've declared the domain like this:
class Applicant {
static hasMany = [hobbies:Hobby]
List <Hobby> hobbies = LazyList.decorate(new ArrayList(), FactoryUtils.instantiateFactory(Hobby.class));
}
In my controller I'm using a command object for the page that will allow the applicant to select their hobbies. It is defined as:
class LifestyleCommand {
List <Hobby> hobbies = LazyList.decorate(new ArrayList(), FactoryUtils.instantiateFactory(Hobby.class));
}
My gsp looks like this:
<g:each var="item" in="${Hobby.list()}" status="i">
<g:set var="newline" value="${(i % 3) == 0 ? 'newline' : ''}" />
<div class="formcheckbox columns3 ${newline}">
<g:checkBox name="hobbies_${item.id}" optionKey="id" value="${item.id}" />
<label>${item.description}</label>
</div>
</g:each>
The page will display all of the hobbies in the page correctly. However when I try to submit the form back to the controller the list in the LifeStyleCommand object is null. I'm not sure if my gsp has the g:checkBox variables set correctly, and I'm not sure if I declared the List in the command object correctly either. Once I get the data to be sent back to the controller, my next problem to overcome will be copying the data from the command object to the Applicant. Any help would be appreciated.
I've tried using just a plain List in the command but grails complains about type conversions when the form is submitted.
EDIT:
Here is what I got to work:
class Applicant {
static hasMany = [hobbies:Hobby]
//I removed the List <hobby>... code
...
}
My command object:
class LifestyleCommand {
Set <Hobby> hobbies;
}
gsp:
<g:each in="${Hobby.list()}" var="hobby">
<g:set var="checked" value="${ command?.hobbies.find{h->h.id == hobby.id } != null }" />
<g:checkBox value="${checked}" name="${ 'hobby' +'[' + hobby.id + ']'}"/>${hobby.description}</td>
</g:each>
And my new controller code:
Hobby.list().each{hobby->
if (params["hobby[${hobby.id}]"] == 'on') {
applicant.addToHobbies(hobby)
}
else if (applicant.getHobbies().contains(hobby)) {
applicant.removeFromHobbies(hobby)
}
}
Everything is working. There may be better ways, and I haven't done any refactoring yet but having it work is a starting point.
The problem is with your GSP. When you need a list of objects, you have to maintain a standard name for your checkbox:
<g:checkBox name="hobbies[$i].id" ... />
This will be mapped correctly to your command list.

Grails 2.1 createCriteria issue with params

edit-
I am trying to return a list of portfolios, along with the last 5 publications attached to each portfolio from my 2 domain classes. I am getting the last total 5 publications back and each list displays all 5. The query is not returning that particular instances own publications. Kellys great ideas put back into another track.
I have created the method in the portfolio controller which is the hasMany side to the publications which belongsTo the portfolio domain class.
I just cant seem to get the portfolios to list their own publications. If I change the eq portfolios, it all works fine, except each portfolio list shows the same publications.
How do I load each portfolio and list the last 5 publications. This is rendered from the portfolio/list page as a partial.Is this the issue maybe. Should I just render it from a new view which is not associated with the portfolio list action??
Newbie to grails and have read and read the doc's, just cant seem to get the params query to return correctly. Help
def _webList (){
//def per = Portfolio.properties
def portfolios = Portfolio.list(params.id)
def results = Publication.withCriteria {
eq('published', 'Yes')
order('lastUpdated', 'desc')
maxResults(5)
}
def reportscount = Publication.count()
[ portfolios: portfolios, results: results, reportscount: reportscount]
}
I can show the the sql log if needed.
EDIT
The following code is the entire partial from file _webList.gsp. The top div -alert loads on the page, but the content within the div property-list portfolio fails to load. Using Kelly's hibernate criteria produces the query in the sql log but not results or styles or anything are return to the view??. weird.!
<div class="alert alert-info" xmlns="http://www.w3.org/1999/html">Permissions apply to <strong>editing</strong> publications.<br>
<div style="display: inline;"><p>Click portfolio name to read or edit publications. Total number of sites: <strong>${rsNumb}</strong> | Total number of publications: <strong>${reportscount}</strong> </p>
</div>
</div>
<div class="property-list portfolio">
<g:each in="${portfolios}" var="portfolioInstance">
<div class="site-listing">
<div><span class="label">Site Name:</span><g:link action="show" id="${portfolioInstance?.id }">${portfolioInstance?.portfolioName?.encodeAsHTML()}</g:link></div>
<div><span class="label">Site Description: </span>${portfolioInstance?.portdescrip?.encodeAsHTML() }</div> <br>
<div><span class="label">Site Administrator: </span>${portfolioInstance?.profile?.portfolioAdmin?.encodeAsHTML() }</div> <br>
<div><span class="label"> Total publications:</span><span class="badge badge-success"> ${portfolioInstance?.publications?.size()}</span> </div>
<!-- whatever else you need here -->
<!-- now iterate through the pubs -->
<g:if test="${portfolioInstance?.publications}">
<g:set var="publicationInstance" />
<ul class="site-publication">
<li class="fieldcontain">
<span id="publications-label" class="property-label"><g:message code="portfolio.publications.label" default="Last 5 published publications:" /></span>
<g:each in="${portfolioInstance.publications}" var="publicationInstance">
${publicationInstance?.id}
<span class="property-value" aria-labelledby="publications-label"><g:link controller="publication" action="show" id="${publicationInstance.id}">${publicationInstance?.encodeAsHTML()}</g:link></span>
<!-- and again whatever else you need here -->
</g:each>
</g:if>
</g:each>
</div>
EDIT - sql log below
Hibernate: select this_.id as id5_1_, this_.version as version5_1_, this_.date_created as date3_5_1_, this_.last_updated as last4_5_1_,
this_.portdescrip as portdesc5_5_1_, this_.portfolio_name as portfolio6_5_1_, this_.portpublished as portpubl7_5_1_, this_.profile_id as profile8_5_1_,
this_.status as status5_1_,
publicatio1_.portfolio_id as portfolio5_5_3_,
publicatio1_.id as id3_, publicatio1_.id as id2_0_,
publicatio1_.version as version2_0_,
publicatio1_.date_created as date3_2_0_,
publicatio1_.last_updated as last4_2_0_,
publicatio1_.portfolio_id as portfolio5_2_0_,
publicatio1_.publication_content as publicat6_2_0_,
publicatio1_.publication_name as publicat7_2_0_,
publicatio1_.published as published2_0_,
publicatio1_.publisheddate as publishe9_2_0_,
publicatio1_.publishedemail as publish10_2_0_,
publicatio1_.pubproduct_id as pubproduct11_2_0_
from portfolio this_ left outer join publication publicatio1_
on this_.id=publicatio1_.portfolio_id where (this_.status=?)
and (publicatio1_.published=?) order by publicatio1_.last_updated desc
You are getting the java.lang.ClassCastException because portfolios is a list and portfolio in the Publication class (probably) isn't, it's probably an id (long); can't cast a list in any meaningful way to compare to a long in eq ('portfolio', portfolios)
You should not need two separate queries since the domain classes are related.
--EDIT--
Editing to not use separate action and just use list action. I've not been able to get the include to work either, but below is pretty much what I've in dozens of cases. If there is some reason you can't do this then maybe a new question on just using the include mechanism might generate some attention.
I'm not sure what your current list action looks like. This is how I would code a list method to get ALL Portfolios and their last 5 Publications. No need for any parameters because I'm returning ALL portfolios.
//PortfolioController
def list (){
def portfolios = Portfolio.createCriteria().list {
//if you needed to filter the list by for example portfolio status or something you could add that here
or {
eq('status','ACTIVE')
eq('status','PENDING')
}
publications(org.hibernate.criterion.CriteriaSpecification.LEFT_JOIN) {
eq("published", "Yes")
order("lastUpdated", "desc")
firstResult(5)
}
}
[portfolios: portfolios, portfolioCount:portfolios.size()]
}
Now the Publications come pre-attached to their Portfolio.
The LEFT_JOIN part of the above insures you get back a list of portfolios with ONLY those Publications attached that meet the criteria; if you leave that out it defaults to an inner join and when you iterate you will get ALL of the Publications for that Portfolio (even if they don't meet the criteria).
Then in your gsp iterate through the portfolios - it can either be directly in the list.gsp or in a template rendered in list.gsp. If you put it in a template called _webList.gsp you would render it in the list.gsp as
<g:render template="weblist" model="['portfolios': portfolios]" />
This is either in list.gsp or _webList.gsp - I would start with it directly in list.gsp to make sure it's all working.
<g:each in="${portfolios}" var="portfolioInstance" status="i">
${portfolioInstance?.portfolioName?.encodeAsHTML()
<!-- whatever else you need here -->
<!-- now iterate through the pubs -->
<g:each in="${portfolioInstance.publications"} var="publicationInstance" status="j">
${publicationInstance.id}
<!-- and again whatever else you need here -->
</g:each>
</g:each>
--EDIT--
firstResult(5) seems to do the trick.
--EDIT--
You'll notice I have the maxResults(5) commented in there - I'm having trouble getting that to work correctly. It seems to control the number of portfolios that are returned even though it is in the association block. Maybe someone else will see this and add that piece of the puzzle - or tinker with it yourself. I'll keep trying and update if I figure it out.

The string was not identified as a valid Boolean string

I have a page where I list checkboxes named TimeRange1, TimeRange2.... TimeRange7, and I generate them in a for loop like this:
<% for (int currentDay = 1; currentDay <= 7; currentDay++)
......<%= Html.CheckBox("TimeRange" + currentDay.ToString(), false)%>
Works fine til I post the form, then I get a "The string was not identified as a valid Boolean string."
Apparently the problem is that I concatenate the name of the checkbox.
Is there some neat way of fixing this? I need to have them named 1-7. It's like a big schedule where you select which times should be available.
Try without helpers:
<% for (int currentDay = 1; currentDay <= 7; currentDay++) { %>
<input type="checkbox" name="TimeRange<%= currentDay.ToString() %>" />
<% } %>
Html Helpers get their values from :
ViewData.ModelState["controlName"].Value.RawValue.
value parameter passed to HTML helper method.
They also generate a hidden input field in addition to the checkbox. So depending on the context sometimes you may end up with markup like this:
<input type="checkbox" name="TimeRange1" value="SomeValue, false" />
and when you post the form the data binder will be unable to convert the value to a boolean type.
An addition to this ol' question - might save someone a headache. I had accidentally labeled a ViewBag property to the same name as a model property, and got the above mentioned error message (when getting the view though, not posting).
In essence I had set the following in the controller:
ViewBag.TermsAndConditions = "blah blah blah"
and in my model I had:
public bool TermsAndConditions { get; set; }
The line #Html.CheckBoxFor(m => m.TermsAndConditions) threw and error from the view.
Renaming either the ViewBag or model property fixed it, obviously.

How to handle checkboxes in ASP.NET MVC forms?

Caution: This question is over nine years old!
Your best option is to search for newer questions, or to search the answers below looking for your specific version of MVC, as many answers here are obsolete now.
If you do find an answer that works for your version, please make sure the answer contains the version of MVC you are using.
(The original question starts below)
This seems a bit bizarre to me, but as far as I can tell, this is how you do it.
I have a collection of objects, and I want users to select one or more of them. This says to me "form with checkboxes." My objects don't have any concept of "selected" (they're rudimentary POCO's formed by deserializing a wcf call). So, I do the following:
public class SampleObject{
public Guid Id {get;set;}
public string Name {get;set;}
}
In the view:
<%
using (Html.BeginForm())
{
%>
<%foreach (var o in ViewData.Model) {%>
<%=Html.CheckBox(o.Id)%> <%= o.Name %>
<%}%>
<input type="submit" value="Submit" />
<%}%>
And, in the controller, this is the only way I can see to figure out what objects the user checked:
public ActionResult ThisLooksWeird(FormCollection result)
{
var winnars = from x in result.AllKeys
where result[x] != "false"
select x;
// yadda
}
Its freaky in the first place, and secondly, for those items the user checked, the FormCollection lists its value as "true false" rather than just true.
Obviously, I'm missing something. I think this is built with the idea in mind that the objects in the collection that are acted upon within the html form are updated using UpdateModel() or through a ModelBinder.
But my objects aren't set up for this; does that mean that this is the only way? Is there another way to do it?
Html.CheckBox is doing something weird - if you view source on the resulting page, you'll see there's an <input type="hidden" /> being generated alongside each checkbox, which explains the "true false" values you're seeing for each form element.
Try this, which definitely works on ASP.NET MVC Beta because I've just tried it.
Put this in the view instead of using Html.CheckBox():
<% using (Html.BeginForm("ShowData", "Home")) { %>
<% foreach (var o in ViewData.Model) { %>
<input type="checkbox" name="selectedObjects" value="<%=o.Id%>">
<%= o.Name %>
<%}%>
<input type="submit" value="Submit" />
<%}%>
Your checkboxes are all called selectedObjects, and the value of each checkbox is the GUID of the corresponding object.
Then post to the following controller action (or something similar that does something useful instead of Response.Write())
public ActionResult ShowData(Guid[] selectedObjects) {
foreach (Guid guid in selectedObjects) {
Response.Write(guid.ToString());
}
Response.End();
return (new EmptyResult());
}
This example will just write the GUIDs of the boxes you checked; ASP.NET MVC maps the GUID values of the selected checkboxes into the Guid[] selectedObjects parameter for you, and even parses the strings from the Request.Form collection into instantied GUID objects, which I think is rather nice.
HtmlHelper adds an hidden input to notify the controller about Unchecked status.
So to have the correct checked status:
bool bChecked = form[key].Contains("true");
In case you're wondering WHY they put a hidden field in with the same name as the checkbox the reason is as follows :
Comment from the sourcecode MVCBetaSource\MVC\src\MvcFutures\Mvc\ButtonsAndLinkExtensions.cs
Render an additional <input
type="hidden".../> for checkboxes.
This addresses scenarios where
unchecked checkboxes are not sent in
the request. Sending a hidden input
makes it possible to know that the
checkbox was present on the page when
the request was submitted.
I guess behind the scenes they need to know this for binding to parameters on the controller action methods. You could then have a tri-state boolean I suppose (bound to a nullable bool parameter). I've not tried it but I'm hoping thats what they did.
You should also use <label for="checkbox1">Checkbox 1</label> because then people can click on the label text as well as the checkbox itself. Its also easier to style and at least in IE it will be highlighted when you tab through the page's controls.
<%= Html.CheckBox("cbNewColors", true) %><label for="cbNewColors">New colors</label>
This is not just a 'oh I could do it' thing. Its a significant user experience enhancement. Even if not all users know they can click on the label many will.
I'm surprised none of these answers used the built in MVC features for this.
I wrote a blog post about this here, which even actually links the labels to the checkbox. I used the EditorTemplate folder to accomplish this in a clean and modular way.
You will simply end up with a new file in the EditorTemplate folder that looks like this:
#model SampleObject
#Html.CheckBoxFor(m => m.IsChecked)
#Html.HiddenFor(m => m.Id)
#Html.LabelFor(m => m.IsChecked, Model.Id)
in your actual view, there will be no need to loop this, simply 1 line of code:
#Html.EditorFor(x => ViewData.Model)
Visit my blog post for more details.
Here's what I've been doing.
View:
<input type="checkbox" name="applyChanges" />
Controller:
var checkBox = Request.Form["applyChanges"];
if (checkBox == "on")
{
...
}
I found the Html.* helper methods not so useful in some cases, and that I was better off doing it in plain old HTML. This being one of them, the other one that comes to mind is radio buttons.
Edit: this is on Preview 5, obviously YMMV between versions.
They appear to be opting to read the first value only, so this is "true" when the checkbox is checked, and "false" when only the hidden value is included. This is easily fetched with code like this:
model.Property = collection["ElementId"].ToLower().StartsWith("true");
#Dylan Beattie Great Find!!! I Thank you much. To expand even further, this technique also works perfect with the View Model approach. MVC is so cool, it's smart enough to bind an array of Guids to a property by the same name of the Model object bound to the View. Example:
ViewModel:
public class SampleViewModel
{
public IList<SampleObject> SampleObjectList { get; set; }
public Guid[] SelectedObjectIds { get; set; }
public class SampleObject
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}
View:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Sample View</h2>
<table>
<thead>
<tr>
<th>Checked</th>
<th>Object Name</th>
</tr>
</thead>
<% using (Html.BeginForm()) %>
<%{%>
<tbody>
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
</tbody>
</table>
<input type="submit" value="Submit" />
<%}%>
Controller:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult SampleView(Guid id)
{
//Object to pass any input objects to the View Model Builder
BuilderIO viewModelBuilderInput = new BuilderIO();
//The View Model Builder is a conglomerate of repositories and methods used to Construct a View Model out of Business Objects
SampleViewModel viewModel = sampleViewModelBuilder.Build(viewModelBuilderInput);
return View("SampleView", viewModel);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SampleView(SampleViewModel viewModel)
{
// The array of Guids successfully bound to the SelectedObjectIds property of the View Model!
return View();
}
Anyone familiar with the View Model philosophy will rejoice, this works like a Champ!
I'd also like to point out that you can name each checkbox a different name, and have that name part of the actionresults parameters.
Example,
View:
<%= Html.CheckBox("Rs232CheckBox", false, new { #id = "rs232" })%>RS-232
<%= Html.CheckBox("Rs422CheckBox", false, new { #id = "rs422" })%>RS-422
Controller:
public ActionResults MyAction(bool Rs232CheckBox, bool Rs422CheckBox) {
...
}
The values from the view are passed to the action since the names are the same.
I know this solution isn't ideal for your project, but I thought I'd throw the idea out there.
<input type = "checkbox" name = "checkbox1" /> <label> Check to say hi.</label>
From the Controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(FormCollection fc)
{
var s = fc["checkbox1"];
if (s == "on")
{
string x = "Hi";
}
}
This issue is happening in the release 1.0 as well. Html.Checkbox() causes another hidden field to be added with the same name/id as of your original checkbox. And as I was trying loading up a checkbox array using document.GetElemtentsByName(), you can guess how things were getting messed up. It's a bizarre.
From what I can gather, the model doesn't want to guess whether checked = true or false, I got around this by setting a value attribute on the checkbox element with jQuery before submitting the form like this:
$('input[type="checkbox"]').each(function () {
$(this).attr('value', $(this).is(':checked'));
});
This way, you don't need a hidden element just to store the value of the checkbox.
I know that this question was written when MVC3 wasn't out, but for anyone who comes to this question and are using MVC3, you may want the "correct" way to do this.
While I think that doing the whole
Contains("true");
thing is great and clean, and works on all MVC versions, the problem is that it doesn't take culture into account (as if it really matters in the case of a bool).
The "correct" way to figure out the value of a bool, at least in MVC3, is to use the ValueProvider.
var value = (bool)ValueProvider.GetValue("key").ConvertTo(typeof(bool));
I do this in one of my client's sites when I edit permissions:
var allPermissionsBase = Request.Params.AllKeys.Where(x => x.Contains("permission_")).ToList();
var allPermissions = new List<KeyValuePair<int, bool>>();
foreach (var key in allPermissionsBase)
{
// Try to parse the key as int
int keyAsInt;
int.TryParse(key.Replace("permission_", ""), out keyAsInt);
// Try to get the value as bool
var value = (bool)ValueProvider.GetValue(key).ConvertTo(typeof(bool));
}
Now, the beauty of this is you can use this with just about any simple type, and it will even be correct based on the Culture (think money, decimals, etc).
The ValueProvider is what is used when you form your Actions like this:
public ActionResult UpdatePermissions(bool permission_1, bool permission_2)
but when you are trying to dynamically build these lists and check the values, you will never know the Id at compile time, so you have to process them on the fly.
The easiest way to do is so...
You set the name and value.
<input type="checkbox" name="selectedProducts" value="#item.ProductId" />#item.Name
Then on submitting grab the values of checkboxes and save in an int array.
then the appropriate LinQ Function. That's it..
[HttpPost]
public ActionResult Checkbox(int[] selectedObjects)
{
var selected = from x in selectedObjects
from y in db
where y.ObjectId == x
select y;
return View(selected);
}
Same as nautic20's answer, just simply use MVC default model binding checkbox list with same name as a collection property of string/int/enum in ViewModel. That is it.
But one issue need to point out. In each checkbox component, you should not put "Id" in it which will affect MVC model binding.
Following code will work for model binding:
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
Following codes will not binding to model (difference here is it assigned id for each checkbox)
<% foreach (var item in Model.SampleObjectList)
{ %>
<tr>
<td><input type="checkbox" name="SelectedObjectIds" id="[some unique key]" value="<%= item.Id%>" /></td>
<td><%= Html.Encode(item.Name)%></td>
</tr>
<% } %>
this is what i did to loose the double values when using the Html.CheckBox(...
Replace("true,false","true").Split(',')
with 4 boxes checked, unchecked, unchecked, checked it turns
true,false,false,false,true,false
into
true,false,false,true.
just what i needed
How about something like this?
bool isChecked = false;
if (Boolean.TryParse(Request.Form.GetValues(”chkHuman”)[0], out isChecked) == false)
ModelState.AddModelError(”chkHuman”, “Nice try.”);
When using the checkbox HtmlHelper, I much prefer to work with the posted checkbox form data as an array. I don't really know why, I know the other methods work, but I think I just prefer to treat comma separated strings as an array as much as possible.
So doing a 'checked' or true test would be:
//looking for [true],[false]
bool isChecked = form.GetValues(key).Contains("true");
Doing a false check would be:
//looking for [false],[false] or [false]
bool isNotChecked = !form.GetValues(key).Contains("true");
The main difference is to use GetValues as this returns as an array.
Just do this on $(document).ready :
$('input:hidden').each(function(el) {
var that = $(this)[0];
if(that.id.length < 1 ) {
console.log(that.id);
that.parentElement.removeChild(that);
}
});
My solution is:
<input type="checkbox" id="IsNew-checkbox" checked="checked" />
<input type="hidden" id="IsNew" name="IsNew" value="true" />
<script language="javascript" type="text/javascript" >
$('#IsNew-checkbox').click(function () {
if ($('#IsNew-checkbox').is(':checked')) {
$('#IsNew').val('true');
} else {
$('#IsNew').val('false');
}
});
</script>
More you can find here:
http://www.blog.mieten.pl/2010/12/asp-net-mvc-custom-checkbox-as-solution-of-string-was-not-recognized-as-a-valid-boolean/
I had nearly the same Problem but the return Value of my Controller was blocked with other Values.
Found a simple Solution but it seems a bit rough.
Try to type Viewbag. in your Controller and now you give it a name like Viewbag.Checkbool
Now switch to the View and try this #Viewbag.Checkbool with this you will get the value out of the Controller.
My Controller Parameters look like this:
public ActionResult Anzeigen(int productid = 90, bool islive = true)
and my Checkbox will update like this:
<input id="isLive" type="checkbox" checked="#ViewBag.Value" ONCLICK="window.location.href = '/MixCategory/Anzeigen?isLive=' + isLive.checked.toString()" />
Using #mmacaulay , I came up with this for bool:
// MVC Work around for checkboxes.
bool active = (Request.Form["active"] == "on");
If checked
active = true
If unchecked
active = false

Resources