Asp.net MVC4 #Html.EditorFor .Where() Attribute - asp.net-mvc

In my view i am using editortemplate as below:
edit.cshtml
#model NetasCrm.Models.CRM_OPP_DETAILS
<table class="table table-hover">
<thead>
<tr>
<th>Çözüm</th>
<th>Üretici</th>
<th>Tarih</th>
<th>Tutar</th>
<th>Sil</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(model => model.CRM_SOLUTION_DISTRIBUTION, new { Solutions = ViewBag.Solutions, Vendors = ViewBag.Vendors })
#Html.HiddenFor(model => model.ID)
</tbody>
</table>
It is working but i am trying to do something(adding where clause.) as below to create an editor template for some of the items in my model.
#Html.EditorFor(model => model.CRM_SOLUTION_DISTRIBUTION.Where(p=>p.AMOUNT != 0), new { Solutions = ViewBag.Solutions, Vendors = ViewBag.Vendors })
I am getting the below error:
Templates can be used only with field access, property access,
single-dimension array index, or single-parameter custom indexer
expressions.

It's not how #Html.EditorFor() should be used, error message clear states about that.
To render what you want you may either use Html.Partial(), or create separate property in your model and move Where to it's getter.

Html.XxxFor expects a lambda expression that selects a property from the model. This is used to identify the property of the model which will be edited.
What you're trying to achieve is probably what you can do with an editor template.
Interesting articles on editor templates and their implementation:
Quick Tips About ASP.NET MVC – Editor Templates
Brad Wilson: ASP.NET MVC 2 Templates, Part 1: Introduction
In the second article you can see that if you have a custom class with the data you want to edit, you can create a template which is automatically used for your editor if you give it the right name and save it in the right place. You can make a class with a single field and include it in your model instead of the original property. This also allows to edit several properties at once (declaring a class with those properties)
Othe option would be a custom html helper:
Creating Custom HTML Helpers (NOTE: this technique will work perfectly with C#/Razor syntax)

Related

Asp.Net MVC validation & knockout foreach

I have a MVC 4 validation & Knockout issue.
I tried this solution :
Translate knockout into razor to keep it's validation working
But i have the same problem as listed in comment of the valid answer => the validation works only for the first element.
After several searches, i found this article on model binding to a list :
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
I am wondering how to merge those two solutions.
Sample with validation working only for the first element :
Dim dummy As ViewModels.ObjectViewModel = Model.MyObjects.FirstOrDefault
#<tbody data-bind='foreach: MyObjects'>
<td>
#Html.TextBoxFor(Function(model) dummy.Label, New With {.data_bind = "value: Label"})
</td>
</tbody>
Sample with validation working, but without the knockout foreach, i can't add items dynamically
<tbody>
#Code
Dim i As Integer = 0
For Each object In Model.MyObjects
#<tr>
<td>
#Html.TextBoxFor(Function(m) Model.MyObjects(i).Label)
</td>
</tr>
i+= 1
Next
End Code
</tbody>
Maybe something with knockout variable : $index() ?
In the past I’ve tried to force combining razor and knockout. But more recently I just opt to go one way or the other. If I’m going to render something on the client side, then I’ll just go ahead and define everything in terms of HTML directly instead of going through razor.
Probably your best bet here is to just define the HTML elements directly. If you need to have validation on place, then just make sure of two things:
Set the corresponding jquery validate attributes (e.g. data-val-true) so that the form validates on the client side.
If you’re submitting data to an ASP.NET MVC Controller make sure the elements have the same name/id as needed by the controller so that the binding takes place on the controller method parameters.
So, after many searches and tests, i have found the solution :
1° Step is to put a correct name for the validation.
Razor View Code :
Dim dummy As ViewModels.ObjectViewModel = Model.MyObjects.FirstOrDefault
<tbody data-bind='foreach: MyObjects'>
<td>
#Html.TextBoxFor(Function(model) dummy.Label, New With {.data_bind = "value: Label, attr: { name: 'MyObjects[' + $index() + '].Label'}"})
</td>
</tbody>
You get this HTML for the first item : name="MyObjects[0].Label"
Which is cool and makes validation work.
But if you add an item dynamically, the validation won't work for the new item.
2° Step is to make the unobstrusive validation re parse your form.
JavaScript
viewModel.addObject = function () {
viewModel.MyObjects.push(new object())
$("form").data("validator", null);
$.validator.unobtrusive.parse($("form"));
};
Those two answers helped me a lot :
Knockout MVC with existing C# code - looping
MVC Model Validation on a dynamic form?

EditorFor not rendering enumerable without #foreach

This is rather baffling. Imagine a Company entity with an .Employees enumerable property, for the sake of simplicity. I've seen elsewhere on SO that the trick to getting EditorTemplates to render enumerables sensibly is to use syntax like this:
In Index.cshtml:
#Html.EditorFor(company => company.Employees, "EmployeeEditorTemplate")
EmployeeEditorTemplate.cshtml expects a single employee:
#model MyNamespace.Models.Employee
//...
#Html.EditorFor(x => x.FullName)
// ...etc.
Posts like this one: Viewmodels List Is Null in Action ...indicate that the modelbinder is smart enough to figure out the binding and index the enumerable on the fly. I'm getting different results (exactly what I'd expect if the modelbinder wasn't supposed to be so mageriffic):
The model item passed into the dictionary is of type
System.Collections.Generic.List`1[MyNamespace.Models.Employee]',
but this dictionary requires a model item of type
'MyNamespace.Models.Employee'.
Enumerating it myself renders the collection just fine, but emits the same id for every row's controls (which is less than optimal, of course, but it tells me the EditorTemplate is functionally correct):
#foreach (var item in Model.Employees)
{
#Html.EditorFor(x => item, "EmployeeEditorTemplate")
}
This construct also fails to post the company.Employees collection back to my other controller action.
Any ideas on what's required to achieve the following?
Render the child collection with unique Ids per instance in the list
Post the child collection back with the model
I don't care if I have to enumerate it myself, nor whether it's inside or outside the EditorTemplate; I've just seen it said that this is unnecessary and that MVC works better if you let it handle things. Thanks.
Per #David-Tansey (from this answer - see for a much more detailed explanation):
(changed to suit this question):
When you use #Html.EditorFor(c => c.Employees) MVC convention chooses the default template for IEnumerable. This template is part of the MVC framework, and what it does is generate Html.EditorFor() for each item in the enumeration. That template then generates the appropriate editor template for each item in the list individually - in your case they're all instances of Employee, so, the Employee template is used for each item.
To sum up his explanation on when you use the named template, you are, in effect, passing the entire IEnumerable<Employee> to a template expecting a single Employee by using #Html.EditorFor(company => company.Employees, "EmployeeEditorTemplate").
note: I really only answered this because it had no answer and I stumbled here first. At least now someone doesn't close it and potentially miss an answer without having to go through the rigmarole of getting duplicate question votes, blah blah.
You can read about it here: Hanselman's article
In short, you should write in your view (index.cshtml):
int i=0;
#foreach (var item in Model.Employees)
{
#Html.TextBox(string.Format("Model[{0}].FullName", i), item.FullName)
i++;
}
foreach can be used with #HTML.EditorFor, for an example see below syntax:
#foreach(var emp in #Model)
{
#Html.EditorFor(d => emp.EmployeeName)
#Html.EditorFor(d => emp.Designation)
<br />
}

How can I edit child objects in an MVC4 form?

I have the following:
#foreach (var parent in Model.Parents)
{
#foreach (var child in parent.Children)
{
#Html.TextAreaFor(c => child.name)
}
}
How can I get editing to work for child objects? I tried something like this as well:
<input type="hidden" name="children.Index" value="#child.Id" />
<textarea name="children[#child.Id]" >#child.Name</textarea>
To pass an IDictionary to the controller but I get an error:
[InvalidCastException: Specified cast is not valid.]
System.Web.Mvc.CollectionHelpers.ReplaceDictionaryImpl(IDictionary`2 dictionary, IEnumerable`1 newContents) +131
This seems like a very common task... is there a simple solution to this? What am I missing? Do I need to use an Editor Template? If so, any MVC4-compatible examples would be fantastic.
is there a simple solution to this?
Yes.
What am I missing?
Editor templates.
Do I need to use an Editor Template?
Yes.
If so, any MVC4-compatible examples would be fantastic.
ASP.NET MVC 4? Man, editor templates exist since ASP.NET MVC 2. All you need to do is to use them.
So start by getting rid of the outer foreach loop and replacing it with:
#model MyViewModel
#Html.EditorFor(x => x.Parents)
and then obviously define an editor template that will be rendered automatically for each element of the Parents collection (~/Views/Shared/EditorTemplates/Parent.cshtml):
#model Parent
#Html.EditorFor(x => x.Children)
and then an editor template for each element of the Children collection (~/Views/Shared/Editortemplates/Child.cshtml) where we will get rid of the inner foreach element:
#model Child
#Html.TextAreaFor(x => x.name)
everything works by convention in ASP.NET MVC. So in this example I assume that Parents is an IEnumerable<Parent> and Children is an IEnumerable<Child>. Adapt the names of your templates accordingly.
Conclusion: everytime you use foreach or for in an ASP.NET MVC view you are doing it wrong and you should consider getting rid of it and replacing it with an editor/display template.

Why doesn't the Add View List Scaffolding wizard use the "DisplayName" data annotation

So I just spent a bunch of time annotating my domain entities with Required, StringLength, Range, Display etc.
I then went in and started creating my strongly typed views that have the correct domain entity set.
The first view I tried was a List Scaffolded view for my domain entity that has Display(Name="foo") attributes generously applied. When the view is created, the table headers still use the property name, rather than the displayname I set.
Does MVC3 with April Tools update ignore these data annotations?
Assuming you are using MvcScaffolding, then yes, these scaffolding templates ignore metadata.
But if you follow this article you can create you own template. When you have done that, you can modify your own template.
Look for this part in the template
<thead>
<tr>
<th></th>
<#
List<ModelProperty> properties = GetModelProperties(Model.ViewDataType, true);
foreach (ModelProperty property in properties) {
if (!property.IsPrimaryKey && !property.IsForeignKey && !property.IsEnumerable) {
#>
<th><#= property.Name #></th>
<#
}
}
#>
</tr>
</thead>
change <th><#= property.Name #></th> to <th>#Html.LabelFor(x => x.First().<#= property.Name #>)</th> and it will use the modelmetadata displayname instead. Be cautious though that this it just to illustrate quickly how you could handle this instead, based on the template for the index view (which has an IEnumerable<> as a model).

How can a list of objects (a part of a bigger Model) with with Add and Delete buttons in MVC be updated with AJAX calls?

The situation is as follows:
I have a ViewModel that has a property that's a List<Product>, where Product is a class with let's say properties Property1, Property2 and Property3.
I have to render the ViewModel and I wish to render the List<Product> in an HTML table each row of which has a "Delete" button for that row.
Underneath the afore-mentioned HTML table, there should be 2 buttons:
3.1 "Add" - used to add a new empty Product to the list
3.2 "Use default product list" - the List has to be loaded via an AJAX call to the GetDefaultProduct() action of the controller
Clicking on a "Delete", "Add" or "Use default product list" button should not post the entire page
The model contains some other lists of items as well - for the sake of example: List<Sales>, List<Orders> and so on. I'm hoping I can re-use the solution for the List for those lists as well.
Is there a way to do this with ASP.NET MVC?
If yes, what is the best way to do it with ASP.NET MVC?
I did this with jQuery templating and I managed to implement this with simple operations, but I have to do it in an ASP MVC solution and I'm still trying to get the hang of the technology.
I've been reading about the Editor template, RenderAction, Async action and partial views and I'm trying to compose a solution with them and I'll post it if it works.
Thanks in advance for any suggestions and comments!
UPDATE
The solution lies (as Darin pointed out) in Steve Sanderson's blog post.
However, it assumes that the reader is aware of under-the-covers way of how a List of objects should be rendered in a CRUD-friendly, indexed manner.
So, in order to help anyone who wants to have an indexed list of omplex objects, I suggest reading mr. Haacked's blog post: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx.
After you are done with it, you can move on to Sanderson's blog. By the way, take a good look at the BeginCollectionItem custom HTML helper - its implementation isn't a trivial one as one might think.
The demo project is a sight for sore eyes - it's spot on and easy to understand.
The proposed solution DOES use some jQuery.ajax() calls (for the Add link), but just out of bare necessity.
PS: It's a bit frustrating that one has to read an explicit article from one of the developers of ASP.NET in order to find out that there's an implicit CoC (Convention-over-Configuration) in the default model binder - it just knows how to work with Lists, but no out-of-the-box HTML helper (or anything similar) doesn't let you in on this.
Personally I think that CRUD-friendly rendering of List<object> is a very common scenario, not an edge case so it should be simpler to use and a part of the ASP.NET MVC out-of-the-box machinery.
I would recommend you reading the following blog post. It would definitely put you on the right track for implementing an editing scenario of a variable length list.
This is a very easy way of doing it if you want to do using Jquery.
ASP.Net MVC 3 JQGrid
Save yourself some pain and download the Telerik Extensions for ASP.Net MVC. It's open source ( though there's a paid option).
The Grid control (possibly in conjunction with the Window control) will give you all the UI functionality you need and there's plenty of online examples.
I've been doing a lot of master-detail UI work recently and Telerik's been an immense help.
Maybe this is not the answer you are looking for, but hey, try to create a default typed edit view for a model using folowing settings:
this will generate the folowing code for view (assuming Razor engine):
#model IEnumerable<MvcApplication2.Models.User>
#{
View.Title = "GetData";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>GetData</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th></th>
<th>
Name
</th>
<th>
Description
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
<td>
#item.Name
</td>
<td>
#item.Description
</td>
</tr>
}
</table>
The code wich will handle edit/update/details will accept Id of the entity as a parameter. These are paricualr other methods of your controller which will handle editting/adding/previewing of you item

Resources