Retrieving postback from Dynamically created controls in MVC without using FormCollection - c#

I'm passing a List to an MVC view and generating checkboxes for each object in the list (The checkboxes are named t.Name).
I'd like to be able to tell which checkboxes were checked once the form is posted. However, I'd like to avoid using the FormCollection object. Is there any way to do this?

Set the name of your checkboxes to something like "MyObject[" + index + "].Checked", and for each checkbox also put a hidden input field named something like "MyObject[" + index + "].Name" with the value set to t.Name.
If you name your fields like that, the default model binder can take your form values and map them to a list of objects with a Name property and a Checked property.
I would try something like the following:
<% foreach(var t in Model)
{ %>
<div>
<%= Html.Hidden("MyObject[" + index + "].Name", t.Name, new { id = "MyObject_" + index + "_Name" }) %>
<%= Html.Checkbox("MyObject[" + index + "].Checked", false, new { id = "MyObject_" + index + "_Checked" }) %>
</div><%
} %>
I use the anonymous type with id property so that the MVC framework components don't generate HTML elements with invalid id values, but it isn't really necessary.
Your action handling the post would look something like this:
[HttpPost]
ActionResult MyAction(IList<MyObject> objects)
{
foreach (MyObject obj in objects)
{
if (obj.Checked)
{
// ...
}
else
{
// ...
}
}
return View();
}

Related

Post javascript generated select option

Here's the code in the view:
<select id="SelectOptions"></select>
And here's the javascript:
$.ajax({
url: '/PriseRendezVous/GetDispos/',
data: { dateText: selected },
success: function (listDispos) {
var myArray = listDispos.split(',');
for (var i = 0; i < myArray.length; i++) {
$('#SelectOptions').append('<option value="' + myArray[i] + '">' + myArray[i] + '</option>');
}
}
});
Say that the Model is of type Car. I want to post the selected value as Car.Color.
How can I associate the value with my Model property?
If you look at how DropDownListFor renders HTML, assume your view looks something like this (assume you have a ColorSelectList property on your Car model that is of type SelectList that contains SelectListItems of all of your colors):
#model Car
#Html.DropDownListFor(m => m.Color, Model.ColorSelectList)
Your HTML would come out looking something like this:
<select id="Color" name="Color">
<option value="Blue" selected="selected">Blue</option>
<option value="Red">Red</option>
</select>
So when you POST the form to your controller, it should be expecting your model:
public JsonResult GetDispos(Car car) { ... }
Then, the DefaultModelBinder will take your values and translate them based on the names of the properties in your form to the object in your action method.
So you simply need to give the names of the elements in your form the corresponding names in your model's property. To find out more about this, search for information on model binders, and in particular, DefaultModelBinder.
The MVC model binder works by matching the name attribute associated with an HTML input to properties of the Model it is expecting to receive.
So you'd need to build your select like:
<select id="SelectOptions" name="Color"></select>
However, HTML helpers will do all the work for you:
#Html.DropDownListFor(x => x.Color, new List<SelectListItem>())
will generate:
<select id="Color" name="Color"></select>

MVC EditorFor Remove Indexed Name

I have model that is a list of another model such that ModelList : ModelSingle
In my razor view I am using
#model somenamespace.ModelList
#Html.EditorForModel()
This iterates though each ModelSingle and returns an EditorTemplate that is strongly typed to ModelSingle.
#model somenamespace.ModelSingle
#using(Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "formname" + Model.ID}))
{
#Html.AntiForgeryToken()
#Html.EditorFor(p => p.SomeField)
#Html.EditorFor(p => p.AnotherField)
}
Each of these templates contains a form that can be used to edit the single model. These are posted individually with my controllers method expecting
public ActionResult(ModelSingle model)
The problem I'm having is that the model is not binding correctly. With a Model as such
public class ModelSingle()
{
public string SomeField { get; set; }
public string AnotherField { get; set; }
}
the EditorTemplate is being told that it was part of a list so I get
<Form>
<input name="[0].SomeField"/>
<input name="[0].AnotherField"/>
<input type="submit" value="Update"/>
</Form>
I can't simply bind to the ModelList as it's not naming ModelList[0].SomeField and even if it was I don't think that would work for anything but the first item.
Is there anyway to make the EditorTemplate ignore the fact that it's model was part of a list or force a DropDownListFor, EditorFor etc.... to just use the field name without prepending the [i].
I know I can force a Name="SomeField" change but I'd rather have a solution that will reflect any changes made in the Model class itself.
EDIT - As Requested added a simplified example of the View and EditorTemplate being used.
The problem is related to a mismatch between the input names generated by your page model (which is a list), and the model expected by your action, which is a single item from your list.
When rendering a list, the default behavior is to render the indexed names like you've shown to us (the [#] notation). Since you want to be able to post any arbitrary item from the list, you won't know ahead of time what index is used. When the model binder looks at the request for your single object, it does not attempt to use the index notation.
I don't know what your requirements are from the user perspective - e.g. whether or not a page refresh is desired, but one way to accomplish this is to provide a jQuery post for the specific item being posted:
// pass jquery form object in
var postItem = function($form) {
var postBody = {
SomeField: $form.find('input selector') // get your input value for this form
AnotherField: '' // another input select for this item
}
$.ajax({
url:'<your action url>',
type: 'POST',
contentType:"application/json; charset=utf-8",
data: JSON.stringify(postBody),
dataType: 'json',
success: function(response) {
// do something with returned markup/data
}
});
}
You are manually serializing a single instance of your model with a json object and posting that. What you return from the action is up to you: new markup to refresh that specific item, json data for a simple status, etc.
Alternately, you can consider manually looping over the items in your collection, and using Html.RenderPartial/Html.Partial to render each item using your View template. This will short-circuit the name generation for each item, and will generate the names as if it's a single instance of ModelSingle.
Finally, a quick (but kind of ugly) fix would be to have your action method take a list of ModelSingle objects. I don't suggest this.
Edit: I missed some important aspects of posting json to an mvc action
Edit2: After your comment about hardcoded names, something like this could help:
var inputs = $form.find('all input selector');
var jsonString = '{';
$.each(inputs, function(index, element) {
var parsedName = element.attr('name').chopOffTrailingFieldName();
jsonString += parsedName + ":'" + element.val() + "',";
});
jsonString += '}';

ASP .NET MVC - Getting object template string result out of a view

I am re-opening my question as it has been set as duplicate while it is not - or people who tagged it as duplicate should explain me why it is a duplicate..........
https://stackoverflow.com/questions/13227988/html-displayfor-result
How can I get the result of the method Html.DisplayFor() in a C# Class, like in a View model or even in a Controller ? And not in the View Aspx or Razor.
[Edit]
In fact I have a table to display and depending on the number of record I use a Telerik table or a simple HTLM table.
For the moment I have a function in my view to get the string to display for each column so I use the same format for both tables.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ViewModels.OrderViewModel>" %>
<script runat="server" type="text/C#">
public string GetCellValue (String columnName, Order order)
{
string value = "";
switch (columnName)
{
case "Ref":
value = order.order.Reference.ToString(); break;
case "Etc":
value = Html.DisplayFor(p => order.order.Etc).ToHtmlString();break;
case "Payment date":
foreach (Executions ex in order.executions)
{
value += ex.Date.Date.ToString("yyyy-MM-dd") + " ";
}
break;
I want to move this function out of my view in the ViewModel for example, but I do not know how I can call the function Html.DisplayFor() out of a view.
Don't understand why would you want to do it, but...
using System.Web.Mvc;
using System.Web.Mvc.Html;
class Example {
void Method()
{
HtmlHelper<TModel> Html = new HtmlHelper<TModel>();
MvcHtmlString result = Html.DisplayFor(prop => Model.Prop);
}
}
After your edit, if you move GetCellValue to another place, maybe you will only need to do
MvcHtmlString result = new MvcHtmlString(order.order.Etc);
as, it should only display its value as string (unless you have set up a template for it).

how to get the value of a kendoui dropdown list selected value in a listview

am having Some kendoui listviews which consists of kendoui dropdown lists and i want to get those dropdown list selected values. To do this am trying,
$("#cnty1").val();
and here is my dropdownlist,i.e., list of countries coming from Database table,
<input select STYLE="width:90px;height:auto" id ="cnty1" data-bind="value:cnty1"
name="cnty1" data-type="string" data-text-field="cnty"
data-value-field="cntyid" data-source="sourcedata1" class="k-d"
data-role="dropdownlist" />
<span data-for="cnty1" class="k-invalid-msg"></span>
here cnty1 is the id of the dropdown list, but am not getting the value instead am getting "id" of the slected value but not the selected value.
And also if the value is not selected am getting the first value id by using $("#cnty1").val();
So, please suggest me a solution so that,
1) I should get only the Selected value and
2) Value of the dropdown list Only if the user selects a value from the list, but don't get the value of the list without selecting.
try this one.
<select STYLE="width:90px;height:auto" id ="cnty1" data-bind="value:cnty1"
data-text-field="cnty" data-value-field="cntyid" data-source="sourcedata1" data-role="dropdownlist" data-change="cntySelect" data-option-label="Select"></select>
function cntySelect(e) {
var dropDownVal = $("#cnty1").val();
alert(dropDownVal);
}
Use the following jquery to get selected value/text:
For value:
$("#cnty1 option:selected").val();
For text use:
$("#cnty1 option:selected").text();
Although this code is being used for FK JSON objects in KendoUI grid, the idea is similar. You have to bind the object on dropdown value selection. The dropdown essentially contains options that are your value ID's, not the objects themselves. Therefore, you have to iterate through the data source to find which object has been selected and then do the replacement in data model.
/**
* KendoDropDownEditor Class
* */
var KendoDropDownEditor = Class({
initialize: function (schema, gridId, readUrl) {
var readUrl = readUrl || base + schema.entityName + "/read";
this.dataSource = DataSourceGenerator.crudDS(schema, gridId, readUrl);
this.dataTextField = schema.model.dropDownTextField;
this.dataValueField = schema.model.id;
},
/**
*
* */
do:function (container, options) {
var self = this;
var a = $('<input data-text-field="' + self.dataTextField + '" data-value-field="' + self.dataValueField + '" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
autoBind:false,
dataSource:self.dataSource,
close:function (e) {
$.each(self.dataSource.data(), function(key, value) {
if (value[self.dataValueField] == e.sender.value()) {
options.model[options.field] = value;
return false;
}
});
}
});
}
});
Also look at Knockout-Kendo, it could make your life easier.

Beginner MVC question - Correct approach to render out a List and details?

I'm trying to set up a page where I display a list of items and the details of the selected item. I have it working but wonder whether I have followed the correct approach. I'll use customers as an example
I have set the aspx page to inherit from an IEnumerable of Customers. This seems to be the standard approach to display the list of items. For the Details I have added a Customer user control which inherits from customer.
I think i'm on the right track so far but I was a bit confused as to where I should store the id of the customer whose details I intend to display. I wanted to make the id optional in the controller action so that the page could be hit using "/customers" or "customers/1" so I made the arg optional and stored the id in the ViewData like this:
public ActionResult Customers(string id = "0")
{
Models.DBContext db = new Models.DBContext();
var cList = db.Customers.OrderByDescending(c => c.CustomerNumber);
if (id == "0")
{
ViewData["CustomerNumber"] = cList.First().CustomerNumber.ToString();
}
else
{
ViewData["CustomerNumber"] = id;
}
return View("Customers", cList);
}
I then rendered the User control using RenderPartial in the front end:
<%var CustomerList = from x in Model
where x.CustomerNumber == Convert.ToInt32(ViewData["CustomerNumber"])
select x;
Customer c = (Customer)CustomerList.First(); %>
<% Html.RenderPartial("Customer",c); %>
Then I just have an actionLink on each listed item:
<%: Html.ActionLink("Select", "Customers", new { id = item.CustomerNumber })%>
It all seems to work but as MVC is new to me I would just be interested in others thoughts on whether this is a good approach?
In regards to proper MVC and separations of concerns, you shouldn't be calling LINQ queries in your view. To get around that, change your controller action code from what you have to this:
if (id == "0")
{
ViewData["CustomerDetails"] = cList.First();
}
else
{
ViewData["CustomerDetails"] = From x in db.customers where x.id = cInt(id);
}
then your partial
<% Html.RenderPartial("Customer",ViewData["CustomerDetails"]); %>
Are you showing the customer information on the same screen that you have your list of customers and not a separate view?
In this case I would take the following approach.
Display a list of customer's, be it a listbox or drop down list.
Let's assume it's a drop down list, probably not very user friendly
You would have the text as the customer name and then the value as the customer id
<select title="Customers">
<option label="Pieter" value="001"></option>
</select>
and using JQuery's $.getJSON you could load the new data via a call to an asp.net MVC action.
Note that your Action should return JsonResult

Categories