Liferay 7 Clay Management Toolbar - liferay-7.1

How add advance search in Clay management toolbar ?
<clay:management-toolbar
clearResultsURL="${assignmentsManagementToolbarDisplayContext.getSearchActionURL()}"
componentId="assignmentsManagementToolbar"
creationMenu="${assignmentsManagementToolbarDisplayContext.getCreationMenu()}"
disabled="${assignmentCount eq 0}"
filterDropdownItems="${assignmentsManagementToolbarDisplayContext.getFilterDropdownItems()}"
itemsTotal="${assignmentCount}"
searchActionURL="${assignmentsManagementToolbarDisplayContext.getSearchActionURL()}"
searchContainerId="assignmentEntries"
searchFormName="searchFm"
selectable="false"
showInfoButton="<%= true %>"
sortingOrder="${assignmentsManagementToolbarDisplayContext.getOrderByType()}"
sortingURL="${assignmentsManagementToolbarDisplayContext.getSortingURL()}"
viewTypeItems="${assignmentsManagementToolbarDisplayContext.getViewTypes()}"
showAdvancedSearch="<%= true %>"
searchDropdownItems="${assignmentsManagementToolbarDisplayContext.getFilterDropdownItems()}"
/>
How to add functionality of Advance Search ?

view.jsp
<%
PortletURL portletURL = renderResponse.createRenderURL();
AssignmentsManagementToolbarDisplayContext assignmentsManagementToolbarDisplayContext = new AssignmentsManagementToolbarDisplayContext(renderRequest, renderResponse);
%>
<clay:management-toolbar
clearResultsURL="${assignmentsManagementToolbarDisplayContext.getSearchActionURL()}"
componentId="assignmentsManagementToolbar"
creationMenu="${assignmentsManagementToolbarDisplayContext.getCreationMenu()}"
disabled="${assignmentCount eq 0}"
filterDropdownItems="${assignmentsManagementToolbarDisplayContext.getFilterDropdownItems()}"
itemsTotal="${assignmentCount}"
searchActionURL="${assignmentsManagementToolbarDisplayContext.getSearchActionURL()}"
searchContainerId="assignmentEntries"
searchFormName="searchFm"
selectable="false"
showInfoButton="<%= true %>"
sortingOrder="${assignmentsManagementToolbarDisplayContext.getOrderByType()}"
sortingURL="${assignmentsManagementToolbarDisplayContext.getSortingURL()}"
viewTypeItems="${assignmentsManagementToolbarDisplayContext.getViewTypes()}"
showAdvancedSearch="<%= true %>"
searchDropdownItems="${assignmentsManagementToolbarDisplayContext.getFilterDropdownItems()}"
/>
class -> AssignmentsManagementRequestHelper
public class AssignmentsManagementRequestHelper extends BaseRequestHelper{
public AssignmentsManagementRequestHelper(HttpServletRequest httpServletRequest) {
super(httpServletRequest);
_renderRequest = (RenderRequest)httpServletRequest.getAttribute(JavaConstants.JAVAX_PORTLET_REQUEST);
_portletPreferences = _renderRequest.getPreferences();
}
public PortletPreferences getPortletPreferences() {
return _portletPreferences;
}
public RenderRequest getRenderRequest() {
return _renderRequest;
}
private final PortletPreferences _portletPreferences;
private final RenderRequest _renderRequest;
}
class -> AssignmentsManagementToolbarDisplayContext
public class AssignmentsManagementToolbarDisplayContext {
public AssignmentsManagementToolbarDisplayContext(
RenderRequest renderRequest,
RenderResponse renderResponse) {
_renderRequest = renderRequest;
_renderResponse = renderResponse;
_assignmentsManagementRequestHelper = new AssignmentsManagementRequestHelper(PortalUtil.getHttpServletRequest(_renderRequest));
}
}
You can refer to Liferay portal source code for module : dynamic-data-lists.
web folder

Related

Custom Provider for AWS SSM using Microsoft.Configuration.ConfigurationBuilders

I seem to be stuck at developing a custom Key/Value pair provider for Amazon's System Manager Parameter Store (SSM) using NETFramework 4.7.1 that utilizes Microsoft.Configuration.ConfigurationBuilders.
The implementation:
using System;
using System.Collections.Generic;
using Amazon.SimpleSystemsManagement;
using Amazon.SimpleSystemsManagement.Model;
using Microsoft.Configuration.ConfigurationBuilders;
using System.Linq;
using System.Diagnostics;
using System.Collections.Specialized;
using Amazon.Runtime;
using Amazon.Runtime.CredentialManagement;
using System.Configuration;
using System.Threading.Tasks;
namespace AXS.Configurations
{
public class ParameterStoreConfigBuilder : KeyValueConfigBuilder
{
public const string envTag = "Environment";
public const string appNameTag = "AppName";
private IAmazonSimpleSystemsManagement client;
/// <summary>
/// Gets or sets an environment (dev|qa|staging|production)
/// </summary>
public string Environment { get; set; }
/// <summary>
/// Gets or sets a AppName
/// </summary>
public string AppName { get; set; }
public ParameterStoreConfigBuilder(IAmazonSimpleSystemsManagement client,
string appName,
string environment)
{
this.client = client;
Environment = environment.ToLower();
AppName = appName;
}
public ParameterStoreConfigBuilder()
{
client = new AmazonSimpleSystemsManagementClient();
}
public override string Description => "Parameter Store";
public override string Name => "SSM";
protected override void LazyInitialize(string name, NameValueCollection config)
{
Optional = false;
base.LazyInitialize(name, config);
string env = UpdateConfigSettingWithAppSettings(envTag);
if (string.IsNullOrWhiteSpace(env))
throw new ArgumentException($"environment must be specified with the '{envTag}' attribute.");
Environment = env;
string appName = UpdateConfigSettingWithAppSettings(appNameTag);
if (string.IsNullOrWhiteSpace(appName))
throw new ArgumentException($"appName must be specified with the '{appNameTag}' attribute.");
AppName = appName;
client = new AmazonSimpleSystemsManagementClient("","", Amazon.RegionEndpoint.USWest2);
}
public override ICollection<KeyValuePair<string, string>> GetAllValues(string prefix)
{
Trace.TraceInformation($"return values prefix {prefix}");
if (client == null)
return null;
var parameters = new List<Parameter>();
string nextToken = null;
do
{
var response = client.GetParametersByPath(new GetParametersByPathRequest { Path = prefix, Recursive = true, WithDecryption = true, NextToken = nextToken });
nextToken = response.NextToken;
parameters.AddRange(response.Parameters);
} while (!string.IsNullOrEmpty(nextToken));
return parameters.Select(p => new
{
Key = p.Name,
p.Value
}).ToDictionary(parameter => parameter.Key, parameter => parameter.Value, StringComparer.OrdinalIgnoreCase);
}
public override string GetValue(string key)
{
return Task.Run(async () => { return await GetValueAsync(key); }).Result;
}
private async Task<string> GetValueAsync(string key)
{
var name = $"/{Environment}/{AppName}/{key.Replace(':', '/')}";
Trace.WriteLine($"get value async:{name}");
if (client == null)
return null;
try
{
Trace.TraceInformation($"fetch key {name}");
var request = new GetParameterRequest
{
Name = name,
WithDecryption = true
};
var response = await client.GetParameterAsync(request);
var parameter = response.Parameter;
var value = parameter.Type == ParameterType.SecureString ? "*****" : parameter.Value;
Trace.TraceInformation($"fetched name={name} value={value}");
return value;
}
catch (Exception e) when (Optional && ((e.InnerException is System.Net.Http.HttpRequestException) || (e.InnerException is UnauthorizedAccessException))) { }
return null;
}
}
}
The problem seems to be that AWS SSM client never gets created.
If I change the code and try to instantiate in the constructor I get a stack overflow exception due to recursion.
Any ideas on how to force to get AmazonSimpleSystemsManagementClient created?
The code uses guidance from https://github.com/aspnet/MicrosoftConfigurationBuilders
The App.Config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection,
System.Configuration, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
restartOnExternalChanges="false"
requirePermission="true" />
</configSections>
<configBuilders>
<builders>
<add name="ParameterStore" Environment="development" AppName="myAppNameforParmStore" type="AXS.Configurations.ParameterStoreConfigBuilder, AXS.Configurations" />
<add name="Env" prefix="appsettings_" stripPrefix="true" type="Microsoft.Configuration.ConfigurationBuilders.EnvironmentConfigBuilder, Microsoft.Configuration.ConfigurationBuilders.Environment, Version=2.0.0.0, Culture=neutral" />
</builders>
</configBuilders>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" />
</startup>
<appSettings configBuilders="Env,ParameterStore">
<add key="Url" value="URL Value for from paramter Store" />
<add key="Secret" value="Some Secret value decrypted" />
</appSettings>
</configuration>
Thanks
UPDATE
I posted an updated version of the AwsSsmConfigurationBuilder, and a sample ASP.NET Web Forms project that uses it, on my GitHub:
https://github.com/Kirkaiya/AwsSsmConfigBuilderPoC/
Disclaimer: This is a proof-of-concept (POC) for a custom ConfigurationBuilder for ASP.NET 4.7.1 or higher (running on .NET Framework obviously). It's a POC, so it doesn't do anything besides allow you store Configuration AppSettings in AWS Parameter Store (a feature of Simple Systems Manager). So, clearly, don't use this in production without productizing and testing it!
Prerequisites:
Your project must target .NET Framework 4.7.1 or higher
Include NuGet package Microsoft.Configuration.ConfigurationBuilders.Base
Have parameters in AWS SSM Parameter Store that have the same name (not counting the prefix) as parameters in your web.config file, and vice-versa.
Notes
In order to avoid recursively calling a concrete constructor or Initialize, I used a static constructor to instantiate the AmazonSimpleSystemsManagementClient, which is held in a static member.
Web.Config additions
Note: change the assembly/class-name of your builder to match yours, etc.
<configSections>
<section name="configBuilders" type="System.Configuration.ConfigurationBuildersSection, System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" restartOnExternalChanges="false" requirePermission="false" />
</configSections>
<configBuilders>
<builders>
<add name="ParameterStore" ssmPrefix="/padnugapp/ApiKeys" type="Microsoft.Configuration.ConfigurationBuilders.AwsSsmConfigBuilder, AspNetWebFormsSample" />
</builders>
</configBuilders>
<appSettings configBuilders="ParameterStore">
<add key="TestKey" value="TestKey Value from web.config" />
<add key="TwitterKey" value="TwitterKey value from web.config" />
</appSettings>
And the AwsSsmConfigBuilder.cs file:
namespace Microsoft.Configuration.ConfigurationBuilders
{
public class AwsSsmConfigBuilder : KeyValueConfigBuilder
{
private string BaseParameterPath = "/padnugapp/ApiKeys";
private static IAmazonSimpleSystemsManagement _client;
static AwsSsmConfigBuilder()
{
_client = new AmazonSimpleSystemsManagementClient();
}
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
if (config["ssmPrefix"] == null)
return;
BaseParameterPath = config["ssmPrefix"];
}
public override ICollection<KeyValuePair<string, string>> GetAllValues(string prefix)
{
if (_client == null)
return null;
var request = new GetParametersByPathRequest
{
Path = $"{BaseParameterPath}/{prefix}",
WithDecryption = true,
};
var response = _client.GetParametersByPathAsync(request).Result;
var result = response.Parameters.ToDictionary(param => param.Name, param => param.Value, StringComparer.OrdinalIgnoreCase);
return result;
}
public override string GetValue(string key)
{
if (_client == null)
return null;
var request = new GetParameterRequest
{
Name = $"{BaseParameterPath}/{key}",
WithDecryption = true,
};
var response = _client.GetParameterAsync(request).Result;
return response.Parameter.Value;
}
}
}
The code I put into a web-forms (.aspx) page that renders the two appSettings items in HTML:
TestKey =
<%=(System.Configuration.ConfigurationManager.AppSettings["TestKey"]) %>
<br />
TwitterKey =
<%=(System.Configuration.ConfigurationManager.AppSettings["TwitterKey"]) %>
I can't stress enough that this is just for a demo I'm doing, and not tested in any way, shape or form except on my laptop ;-)

not able to store cookie value in cookies

I am not able to store a cookie value in a cookie. Here is my code:
namespace CookieCreation.Controllers
{
public class CookieController : Controller
{
// GET: /<controller>/
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult WriteCookie(String CookieName, String CookieValue, bool IsPersistent)
{
if (IsPersistent)
{
CookieOptions cookies = new CookieOptions();
cookies.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Append(CookieName, CookieValue, cookies);
}
else
{
Response.Cookies.Append(CookieName, CookieValue);
}
ViewBag.Message = ("Sucessful");
return View("Index");
}
public IActionResult ReadCookie()
{
ViewBag.CookieValue = Request.Cookies["CookieName"];
return View();
}
}
}
How do you determine that the cookie is not stored? Use Chrome developer tools, Application/Cookies to see if the cookie is created.
I used your code with the Index.cshtml below and everything worked, cookie is stored and read using your code:
<h1>Index</h1>
<p>Last operation: #ViewBag.Message</p>
#{
using(Html.BeginForm("WriteCookie", "Cookie", new { CookieName = "CookieName", IsPersistent = false}, FormMethod.Post )) {
<input type="text" value="42" name="CookieValue" />
<input type="submit" value="post"/>
}
}

MVC 4 - populate dropdownlistfor with model list

I am trying to populate a dropdownlistfor in my view and I don't know the correct lambda expression for it to work. See code below:
#model Website.Models.modelTeamSelect
<h2>MatchSelect.cshtml</h2>
#using (Ajax.BeginForm("_PartialTeams",
new
{
model = this.Model
},
new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "divMatchScheduler",
InsertionMode = InsertionMode.Replace
}))
{
<div id="divMatchScheduler">
#Html.LabelFor(m => m.modelMatch.HomeTeam)
#Html.DropDownListFor(m => m.modelMatch.HomeTeam, new SelectList
{
Items = Model.teams.Select(t => t.TeamName)
})
#Html.LabelFor(m => m.modelMatch.AwayTeam)
#Html.LabelFor(m => m.modelMatch.MatchDate)
#Html.TextBoxFor(m => m.modelMatch.MatchDate)
</div>
<input type="submit" value="Add Match" name="btnSubmit" />
}
This syntax is wrong
#Html.DropDownListFor(m => m.modelMatch.HomeTeam, new SelectList
{
Items = Model.teams.Select(t => t.TeamName)
})
My model being used by the view and the collection it contains
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Website.Models
{
public class modelMatch
{
public Guid MatchID { get; set; }
public Guid AwayTeamID { get; set; }
public string AwayTeam { get; set; }
public Guid HomeTeamID { get; set; }
public string HomeTeam { get; set; }
public DateTime MatchDate { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Website.Models
{
public class modelTeamSelect
{
public modelTeamSelect()
{
teams = new List<modelTeam>();
team = new modelTeam();
modelMatch = new Models.modelMatch();
modelMatches = new List<modelMatch>();
}
public List<modelTeam> teams { get; set; }
public modelTeam team { get; set; }
public modelMatch modelMatch { get; set; }
public List<modelMatch> modelMatches { get; set; }
public string message { get; set; }
}
}
Summary
How do I populate dropdownlistfor using a list collection that is in my model?
For most cases you'll want to use this overload of SelectList to populate your dropdowns.
#Html.DropDownListFor(m => m.modelMatch.HomeTeam, new SelectList(Model.teams, "dataValueField", "dataTextField"))
dataValueField and dataTextField are the properties from your modelTeam model that will be used as value and text for the dropdown.
#{
<br />
ViewBag.TeamList = Model.teams.Select(t => t.TeamName);
<br />
}
<br />
#Html.DropDownListFor(m => m.modelMatch.HomeTeam, ViewBag.TeamList as SelectList)
You also can create HtmlHelperExtensions class to bind dropdowns.
public static IEnumerable<SelectListItem> ObtenerPais(this HtmlHelper helper)
{
var cnx = new db();
var resultado = cnx.PAIS.ToList()
.Select(e => new SelectListItem
{
Text = e.NOMBRE,
Value = Convert.ToString(e.ID_PAIS)
}).ToList();
//if (Default)
resultado.Insert(0, new SelectListItem
{
Text = "-- Seleccionar --",
Value = ""
});
return resultado;
}
And for use it:
#Html.DropDownListFor(model => model.ID_ENTIDAD, Html.ObtenerPais(Default: true))
Hope this helps

ModelState.IsValid is always false for RegularExpression ValidationAttribute in MVC 4

In my class, I have a property for a file attachment like so...
public class Certificate {
[Required]
// TODO: Wow looks like there's a problem with using regex in MVC 4, this does not work!
[RegularExpression(#"^.*\.(xlsx|xls|XLSX|XLS)$", ErrorMessage = "Only Excel files (*.xls, *.xlsx) files are accepted")]
public string AttachmentTrace { get; set; }
}
I don't see anything wrong with my regex, but I always get ModelState.IsValid false. This seems pretty trivial and simple regex, am I missing something? Do I need to write my own custom validation?
I'm populating AttachmentTrace via a regular input of type file:
<div class="editor-label">
#Html.LabelFor(model => model.AttachmentTrace)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.AttachmentTrace, new { type = "file" })
#Html.ValidationMessageFor(model => model.AttachmentTrace)
</div>
The action method is just a regular action:
public ActionResult Create(Certificate certificate, HttpPostedFileBase attachmentTrace, HttpPostedFileBase attachmentEmail)
{
if (ModelState.IsValid)
{
// code ...
}
return View(certificate);
}
Ok, here's the solution I found. I'm sure there are other solutions out there. First a little background, because my application uses EF code-first migration, specifying a HttpPostedFileBase property type in my model, produces this error when adding migration:
One or more validation errors were detected during model generation:
System.Data.Entity.Edm.EdmEntityType: : EntityType
'HttpPostedFileBase' has no key defined. Define the key for this
EntityType. \tSystem.Data.Entity.Edm.EdmEntitySet: EntityType:
EntitySet 'HttpPostedFileBases' is based on type 'HttpPostedFileBase'
that has no keys defined.
So I really had to stick with using a string type for the AttachmentTrace property.
The solution is to employ a ViewModel class like this:
public class CertificateViewModel {
// .. other properties
[Required]
[FileTypes("xls,xlsx")]
public HttpPostedFileBase AttachmentTrace { get; set; }
}
Then create a FileTypesAttribute like so, I borrowed this code from this excellent post.
public class FileTypesAttribute : ValidationAttribute {
private readonly List<string> _types;
public FileTypesAttribute(string types) {
_types = types.Split(',').ToList();
}
public override bool IsValid(object value) {
if (value == null) return true;
var postedFile = value as HttpPostedFileBase;
var fileExt = System.IO.Path.GetExtension(postedFile.FileName).Substring(1);
return _types.Contains(fileExt, StringComparer.OrdinalIgnoreCase);
}
public override string FormatErrorMessage(string name) {
return string.Format("Invalid file type. Only {0} are supported.", String.Join(", ", _types));
}
}
In the controller Action, I needed to make a change to use the ViewModel instead, then map it back to my Entity using AutoMapper (which is excellent by the way):
public ActionResult Create(CertificateViewModel certificate, HttpPostedFileBase attachmentTrace, HttpPostedFileBase attachmentEmail) {
if (ModelState.IsValid) {
// Let's use AutoMapper to map the ViewModel back to our Certificate Entity
// We also need to create a converter for type HttpPostedFileBase -> string
Mapper.CreateMap<HttpPostedFileBase, string>().ConvertUsing(new HttpPostedFileBaseTypeConverter());
Mapper.CreateMap<CreateCertificateViewModel, Certificate>();
Certificate myCert = Mapper.Map<CreateCertificateViewModel, Certificate>(certificate);
// other code ...
}
return View(myCert);
}
For the AutoMapper, I created my own TypeConverter for the HttpPostedFileBase as follows:
public class HttpPostedFileBaseTypeConverter : ITypeConverter<HttpPostedFileBase, string> {
public string Convert(ResolutionContext context) {
var fileBase = context.SourceValue as HttpPostedFileBase;
if (fileBase != null) {
return fileBase.FileName;
}
return null;
}
}
That's it. Hope this helps out others who may have this same issue.

CheckBoxList multiple selections: how to model bind back and get all selections?

This code:
Html.CheckBoxList(ViewData.TemplateInfo.HtmlFieldPrefix, myList)
Produces this mark-up:
<ul><li><input name="Header.h_dist_cd" type="checkbox" value="BD" />
<span>BD - Dist BD Name</span></li>
<li><input name="Header.h_dist_cd" type="checkbox" value="SS" />
<span>SS - Dist SS Name</span></li>
<li><input name="Header.h_dist_cd" type="checkbox" value="DS" />
<span>DS - Dist DS Name</span></li>
<li><input name="Header.h_dist_cd" type="checkbox" value="SW" />
<span>SW - Dist SW Name </span></li>
</ul>
You can check multiple selections. The return string parameter Header.h_dist_cd only contains the first value selected. What do I need to do to get the other checked values?
The post method parameter looks like this:
public ActionResult Edit(Header header)
I'm assuming that Html.CheckBoxList is your extension and that's markup that you generated.
Based on what you're showing, two things to check:
The model binder is going to look for an object named Header with string property h_dist_cd to bind to. Your action method looks like Header is the root view model and not a child object of your model.
I don't know how you are handling the case where the checkboxes are cleared. The normal trick is to render a hidden field with the same name.
Also a nit, but you want to use 'label for="..."' so they can click the text to check/uncheck and for accessibility.
I've found that using extensions for this problem is error prone. You might want to consider a child view model instead. It fits in better with the EditorFor template system of MVC2.
Here's an example from our system...
In the view model, embed a reusable child model...
[AtLeastOneRequired(ErrorMessage = "(required)")]
public MultiSelectModel Cofamilies { get; set; }
You can initialize it with a standard list of SelectListItem...
MyViewModel(...)
{
List<SelectListItem> initialSelections = ...from controller or domain layer...;
Cofamilies = new MultiSelectModel(initialSelections);
...
The MultiSelectModel child model. Note the setter override on Value...
public class MultiSelectModel : ICountable
{
public MultiSelectModel(IEnumerable<SelectListItem> items)
{
Items = new List<SelectListItem>(items);
_value = new List<string>(Items.Count);
}
public int Count { get { return Items.Count(x => x.Selected); } }
public List<SelectListItem> Items { get; private set; }
private void _Select()
{
for (int i = 0; i < Items.Count; i++)
Items[i].Selected = Value[i] != "false";
}
public List<SelectListItem> SelectedItems
{
get { return Items.Where(x => x.Selected).ToList(); }
}
private void _SetSelectedValues(IEnumerable<string> values)
{
foreach (var item in Items)
{
var tmp = item;
item.Selected = values.Any(x => x == tmp.Value);
}
}
public List<string> SelectedValues
{
get { return SelectedItems.Select(x => x.Value).ToList(); }
set { _SetSelectedValues(value); }
}
public List<string> Value
{
get { return _value; }
set { _value = value; _Select(); }
}
private List<string> _value;
}
Now you can place your editor template in Views/Shared/MultiSelectModel.ascx...
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<WebUI.Cofamilies.Models.Shared.MultiSelectModel>" %>
<div class="set">
<%=Html.LabelFor(model => model)%>
<ul>
<% for (int i = 0; i < Model.Items.Count; i++)
{
var item = Model.Items[i];
string name = ViewData.ModelMetadata.PropertyName + ".Value[" + i + "]";
string id = ViewData.ModelMetadata.PropertyName + "_Value[" + i + "]";
string selected = item.Selected ? "checked=\"checked\"" : "";
%>
<li>
<input type="checkbox" name="<%= name %>" id="<%= id %>" <%= selected %> value="true" />
<label for="<%= id %>"><%= item.Text %></label>
<input type="hidden" name="<%= name %>" value="false" />
</li>
<% } %>
</ul>
<%= Html.ValidationMessageFor(model => model) %>
Two advantages to this approach:
You don't have to treat the list of items separate from the selection value. You can put attributes on the single property (e.g., AtLeastOneRequired is a custom attribute in our system)
you separate model and view (editor template). We have a horizontal and a vertical layout of checkboxes for example. You could also render "multiple selection" as two listboxes with back and forth buttons, multi-select list box, etc.
I think what you need is how gather selected values from CheckBoxList that user selected and here is my solution for that:
1- Download Jquery.json.js and add it to your view as reference:
2- I've added a ".cssMyClass" to all checkboxlist items so I grab the values by their css class:
<script type="text/javascript" >
$(document).ready(function () {
$("#btnSubmit").click(sendValues);
});
function populateValues()
{
var data = new Array();
$('.myCssClas').each(function () {
if ($(this).attr('checked')) {
var x = $(this).attr("value");
data.push(x);
}
});
return data;
}
function sendValues() {
var data = populateValues();
$.ajax({
type: 'POST',
url: '#Url.Content("~/Home/Save")',
data: $.json.encode(data),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function () { alert("1"); }
});
}
</script>
3- As you can see I've added all selected values to an Array and I've passed it to "Save" action of "Home" controller by ajax 4- in Controller you can receive the values by adding an array as argument:
[HttpPost]
public ActionResult Save(int[] val)
{
I've searched too much but apparently this is the only solution. Please let me know if you find a better solution for it.
when you have multiple items with the same name you will get their values separated with coma