Here is my problem. I have a list of models that are displayed to the user. On the left is a checkbox for each model to indicate that the user wants to choose this model (in this case, we're building products a user can add to their shopping cart). The model has no concept of being chosen...it strictly has information about the product in question.
I've talked with a few other developers after having gone through and the best I could come up with is getting the formcollection and string parsing the key values to determine whether the checkbox is checked or not. This doesn't seem ideal. I was thinking there would be something more strongly bound, but I can't figure out a way to do it.
I tried creating another model that had a boolean property to represent being checked and a property of the model and passing a list of that model type to the view and creating a ActionResult on the controller that accepts a list of the new model / checked property, but it comes back null. Am I just thinking too much like web forms and should just continue on with parsing checkbox values?
Here's what I've done for wrapping the models inside a collection:
public class SelectableCollection[T] : IList[T] {}
public class SelectableTrack{
public bool IsChecked{get;set;}
public bool CurrentTrack{get;set;}
}
For the view, I inherit from
ViewPage[SelectableCollection[SelectableTrack]]
For the controller, I have this as the ActionResult:
[HttpPost]
public ActionResult SelectTracks(SelectableCollection sc) {
return new EmptyResult();
}
But when I break inside the ActionResult, the collection is null. Any reason why it isn't coming through?
You don't want to bind the entire page to the collection.
Create a class called MyViewModel (or whatever makes sense, use the name of the View in the name.) Make that class the basis of your strongly-typed View.
Add the SelectableCollection<T> as a property of the ViewModel (call it SelectedProducts or whatever,) and populate it in the Controller.
Bind the checkboxes to the SelectedProducts property.
Also, are you using a custom CheckBoxList helper? There is not one out-of-the-box with ASP.NET MVC. Use this post to build your checkboxes:
How to handle checkboxes in ASP.NET MVC forms?
Related
I have a model called Course and another model called SelectedCourse. These two models represent two different tables and have exclusive properties to their own and hence not the same type.
I would like to display List<Course> on my page in the form of multiple check-boxes. The courses that are available in the List<SelectedCourse> should be marked as checked.
How do I build my ViewModel to achieve this?
For Post, I would like to return the list of my ViewModel back to the controller and the POST action. And then be able to only delete/add the items that were modified (selected/un-selected) to the table representing List<SelectedCourse>.
How do I achieve this?
(Because I don't know how to create my ViewModel, I cannot provide cshtml or controller actions to prove effort)
Your ViewModel could contain a list of e.g. CourseViewModel objects, which contains the properties of the Course you are using in the view, but also a bool for representing whether the course is selected. See this question for an example.
Your action method (POST) could take the list of CourseViewModels as argument, which allows the form to post that list of ViewModels back to the controller. See this question for an example.
Using Razor Pages. I want a dropdown list in the header which is created in _Layout.cshtml. This will be populated by a EF database query based on the login user ID. This list will be a global filter for any of the queries. It needs to respond to selection change. It will use cookies to keep track from session to session. Then each page that displays data will be able to access this value and filter its results. Each page could just read the cookie value or have some access to the value in the dropdown list.
Tried using partial and view component. Either way doesn't work because it always tries to pass the Model of the calling page (Index, Create, Report) since it is loaded by each and not exactly by the _Layout which doesn't have a model. So, now I can't use a model in the Partial or View Component to bind the drop down list.
I also couldn't get the changing of the dropdown list to fire the OnPostAsync event.
This seems like it isn't even possible based on all the attempts I made. I'm assuming it probably requires javascript to do all of the work but I'm not sure the correct approach to use.
You could create a base class for your controllers, which adds the required data to the ViewBag on every request. Note: The following code is based on ASP.NET MVC, not ASP.NET Core, but afaik the process is similar.
public class ApplicationControllerBase : ControllerBase
{
protected override void OnResultExecuting(ResultExecutingContext filterContext)
{
// use ViewResultBase, if you need logic for both full and partial views. Since you want to add info for the _Layout page, ViewResult is better.
if (filterContext.Result is ViewResult viewResult)
{
// Give the ViewBag item a unique name, that will not be used elsewhere, so you don't overwrite anything by accident.
// Use the data from ViewBag to populate your dropdown.
viewResult.ViewBag.DropDownItems = GetDropDownItems(); // implement GetDropDownItems accordingly, preferrably with caching!
}
base.OnResultExecuting(filterContext);
}
}
As for the second part of your question about calling the OnPostAsync when the DropDownList changes its value: Yes, you can use JS for this, unless you want to add an extra form around it with an extra submit button. The form may make sense in any case, but you can use the onchange handler to submit the form immediately, when the dropdown's value changes, instead of requiring manual submission of the form.
Well I have a group controller and view in the project, in which the model binding is GroupViewModel. But the group page is complex, and users will be able to make discussion topics. On this group view page, I have forms that allow users to post topics/replies. The model used for these forms can be TopicViewModel or ReplyViewModel, but the original model binding is only for GroupViewModel. It is declared at the beginning of the cshtml page:
#model MyProject.ViewModels.GroupBrowseViewModel
So I wonder, is it possible to have forms bind to different view model from the one declared at the top? If so, how to achieve this?
Model binding really has nothing to do with the model used in your razor view. At least not technically.
The first thing you have to understand is that there is no magic here. This is straight HTTP posted values, and if you don't understand how HTTP posting works, I suggest you read up on it. It's just a series of name/value pairs.
When you post, the routing framework looks at the selected action method, and the parameters that method takes, then it creates new instances of those parameters, and tries to match them up with similarly named values from the posted values.
So, in other words, there is no direct connection here between the model you use on the page, and the model used in the posted controller action. It's all based on naming convention. This naming convention is "helped" by the model you declare on the page, and the Html helpers create form fields with names that match up to model entries so that the model binder can figure these out more easily.
So, what this means is that in order to post to a different action, with a different model, all you need are fields in your form that have the names that the new model expects.
This can be done in a number of ways, from defining those fields manually, to using Partial view in which you pass an instance of the model you intend to post to as the model parameter.
You can use 2 partial views in the same view, and switch from the controller which one to show.
Or you can make a new ViewModel and this view model will contain references to both of your views, and in the view html based on your logic your can switch reading from any child ViewModel.
I've been working on filtering a list of log entries, and I'm getting close to being complete.
I'm wondering if it's possible to update the current View's model asynchronously via $.ajax().
I currently have the $.ajax() working, however it returns the entire page's HTML as opposed to a partial view, or a model itself.
Is anybody aware of a way to simply update the model on the current view?
You'd have to return the model in json format and use js templating
functionality to replace the server rendered html in the dom. –
WestDiscGolf
The above is the solution, so I'll keep it simple and use a more conventional method.
This concept doesn't really make sense. The model doesn't really exist any more once the page is rendered, until it is reinstantiated on the following POST (assuming it is reinstantiated, i.e. your controller action accepts an argument of the same type). In the meantime, it is just manifested as form fields with name properties that correspond to what were the model's properties.
You can, however, dynamically create form fields that will (if possible) be mapped back to model properties again when the form is posted.
Create a field, whose name property matches the name of your model property:
<input type="hidden" id="hdnMyProperty" name="MyProperty" />
Then use jQuery to populate the field's value:
var property = /* Your returned value here */;
$('#hdnMyProperty').val(property);
There are a couple of common ways of achieving this:
Make an AJAX request to a controller action that returns a JsonResult and dynamically create the form field(s) in your Javascript (potentially - as has been mentioned - utilizing something like Knockout).
Create a controller action that returns a PartialViewResult and dynamically insert the returned markup in the appropriate place.
When you issue the next post request, the model binder will try to map this to an appropriate property in the newly-instantiated model.
You could simply use Knockout. No need to re-invent the wheel in this case.
MVC3 has entity framework that makes create, delete, edit methods within a controller.
I am making a control panel that allows to edit multiple tables. How do I incorporate a controller(the entity framework) within another controller(the control panel)?
Any clever work around?
For example http://example.com/Control_panel/Another_Controller
Ok for this, there are two ways lets say you have a default controlpanel action in your ControlPanel controller, you can have a variable that comes in and says what you are trying to control, lets call it controlID, you can then use RedirectToAction to go to that action instead, like this
public ActionResult controlPanel(object controlId){
if(controlId.equals(something)){
RedirectToAction(SomeAction, SomeController);
}
}
The other one is you can use the same idea and call the controller action directly. Like this:
var result= new SomeController().SomeAction();
Although this is breaking MVC design as you should have it be a more universal function rather than a controller, as controllers are designed to control datamovement between Models and Views. If I see some of the code I can give you a more specific response.
If you want to edit data from multiple tables from the same page, you accomplish this by use of view models. The data you present to the user in your view does not need to have a 1:1 relationship with a table or a model for that matter.
A view model will allow you to pick data from various sources, present the same to the user for viewing or editing and if the user saves the same, you can pick the view model from your controller action and use that data to update one or more tables.