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.
Related
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.
I still don't get the primary purpose of Html.Action in asp.net mvc. I have been using Html.Partial every time I need to load up a partial view or wanted to split up some code in a view to clean it up.
Where does Html.Action fit into all of this (e.g. where would you want to use Html.Action and not use Html.Partial)?
Edit
The answers seem to be use Html.Action for dynamic data. I don't get this as you can use Partial Views for Dynamic data as well.
For instance if a user on my site edits a row. A ajax call is made to a method and I go grab that row from the db. I then return a parital view of a form that has all the data on it ready for editing. If an error occurs then I return a json result with the error method and my javascript consumes it and alerts the user.
If all is good then the rendered html is put into a jquery dialog and displayed to the user.
Is it because you can use the "ChildActionOnlyAttribute" that makes people use Action instead?
Ankur has the right idea but I find you can really simplify the concept down further.
For me it comes down to What versus How
If you know what you want to render but not how it's likely you'll use a partial to let it determine how to render the information.
For example, maybe your view model is for an invoice. Your invoice view model probably already has all the information you need about the invoice itself, including an enumerable of the line items on the invoice perhaps. A partial might be a good choice for the line items so that it's self contained. You already have the line items details (the what), but a partial will handle how it gets rendered (the how)
On the flip side, maybe your invoice view model has a customer ID on it but no actual customer details. Here you don't have the what, so you'd pass in the customer ID to an Action and it'll get what data it needs and pass it off to the view to render how it seems fit.
So in summary if you already have all the data you want to work with, just stick with a Partial, but if you are missing information that you need to obtain, Action would be better.
Where this get really fuzzy around the edges is when a Partial view includes the ability to retrieve it's own data via Ajax (or other technologies). In which case you might be able to get away with making that Customer details portion in my example, a Partial, and have it retrieve the data it needs Using Ajax after the client get's the response. But that's more up to you if that sort of thing even makes sense for your implementation.
Addendum:
It's worth noting that if you decide to try out ASP.NET MVC Core, ChildActions are no longer available. In which case your choices will be limited to partial views, ajax, or the newly introduced feature of Components. The last of which is similar to ChildActions, but slightly different in how they are implemented.
Perhaps an example will make this clearer.
Let's say you have a menu which appears on every page, so you put it in your layout. The menu will never change - there is just some basic navigation links, Home, About, Contact us etc, so you just use a normal partial view. This will work fine - as the content is static - you don't need to go to a database to get the data. You can just use #Html.Partial("Menu");.
Later you decide you need to change the menu so that it gets all the links from a database. You update your partial view to have a model that is a List<string> - one for each link.
Now, if you still want to just use a Partial View, every action would need to query the database to get the list of links, and every Model for every View would need to have a List<string> property for the links, so that it could pass this to the Menu Partial View. This would be a bad idea.
Instead, you would make a new Child Action GetMenuLinks() - this would query the database to get the links as a List<string>, and pass this to the Partial View. This puts the Child Action in charge of getting it's own data. This means you only need to have this query in one place, the 'About Us' action for example doesn't need to worry about getting the list of links for the menu.
Partial views
Use for sharing subsections of view markup between views. Partial views can
contain inline code, HTML helper methods, and references to other partial
views. Partial views do not invoke an action method, so they cannot be used
to perform business logic.
Child actions
Use for creating reusable UI controls or widgets that need to contain business
logic. When you use a child action, it invokes an action method, renders a
view, and injects the result into the response stream.
I use Html.Action() to load dynaimc content that I do not wish to contain in the view model (for instance, user information in a sidebar). It is very useful for keeping input and output view models identical.
Note that I always use Html.Action() in conjunction with applying the ChildActionOnlyAttribute to the controller method that I am calling so that the HTML fragment is not accessible via the URL.
Use Html.Partial when you require a subset of your view model to render the section in question--usually it is something that has to do with what you're working on. If could be a subsection of a form, a relevant content piece related to the main view etc. A partial receives its model information from the parent view.
Otherwise use Html.Action to render content that is independent of your main view, such as a navigation piece, an aside, or other distractions. Html.Action uses its own model provided by its controller, rather than provided by the parent view.
This question is answered (and elected for 149 times!) here:
Html.Partial vs Html.RenderPartial & Html.Action vs Html.RenderAction
Update
Sorry, meant to send you these postings rather
MVC Html.Partial or Html.Action\
#Html.Partial() Vs #Html.Action() - MVC Razor
Hope this helps.
I have a view model with a list of items. These items are rendered using a partial view within a for loop.
I want to be able to click on some text within the partial view and post back to the controller the item and all properties that I clicked on.
I can't simply pass an Id as once I've passed the item to the view I cannot look it up again.
What options do I have to do this?
Now, I see. I'd implement this this in another way.
1st controller - to list items,
2nd controller - to manipulate items
jQuery for UI.
Client side selecting, editing - on jQuery,
Save button goes to 2nd controller. Which internally may cause refresh of list.
Refreshing items to 1st.
Also some Ajax to make client work more convenient. It seems to be perfect match.
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?