MVC3 RenderPartial and the ViewBag - asp.net-mvc-3

I'll try to keep this brief:
In the view
#Html.RenderPartial("myview", Model.SubModel,
new ViewDataDictionary()
{
{ "thing", Model.Thing }
})
In the myview we see that "thing" is avaiable, i.e. this produces the value of Model.Thing in the myview view:
#ViewBag.thing
Great! Simple
But I need to do something with thing (and thing can't be part of SubModel by the way), i.e. access this in my view engine or ideally in the controller, e.g.:
public ActionResult myview(SubModelType vm)
{
var thing = ViewBag.thing; // oh dear this doesnt exist.. but is there when the view is rendered
So my question is, if the ViewBag is available in the resulting myview, it must be being passed around somehow in the httpcontext, or in the controllercontext somewhere right? Does anyone know why it's not available in the controller but is in the view and how I might be able to access this?
Edit
Sorry I missed a vital point here! It's when "myview" is posted back to the controller, invoking an action called myview where I would expect the ViewBag rendered to myview to be available. But of course it's not, it's been used in "myview" and that's it. So if I want to use it in the myview action I'm going to need to store in the ViewBag in that view OR set some value of the viewmodel so that it can be posed back to the action.
Does that make sense?

Sorry I missed a vital point here! It's when "myview" is posted back
to the controller, invoking an action called myview where I would
expect the ViewBag rendered to myview to be available.
Oh no, you cannot be possibly expecting anything like that. That's not how ASP.NET MVC works. When you send an HTTP request to a controller action the default model binder will intercept this request and look in the posted values from the request and bind them to your action argument:
[HttpPost]
public ActionResult myview(SubModelType vm, ThingViewModel thing)
{
...
}
This obviously assumes that those thing values were part of the original request. So for example if you submit a form you should include corresponding fields inside this form that the model binder could use.
Think of it that way: an ASP.NET MVC controller action could be invoked from any client. For example from an iPhone application. And as you know there's no such notion as ViewBag in iOS. All that will happen is that the default model binder will look at the POSTed values and attempt to hydrate the view models that your action is taking as arguments.
If on the other hand you cannot make those thing values as part of the request (by including corresponding input fields in the form) you could only send the ID of this thin from a hidden field and then inside your controller action use this ID to query your underlying data-store to retrieve the thing from the same place you retrieved it initially when you first rendered this form.
Some people might also suggest you storing the Thing inside the Session and then reading the value back from the Session in your POST action. I am not from those people. It's an alternative approach though.

Related

MVC 3 post model and additional parameter to HttpPost action method using Ajax form

Using ASP.NET MVC 3 and Razor, I have a strongly typed view against MyViewModel class. Within the view I have an AJAX form that consists of a group of radio buttons. Below it, I have a normal HTML form that collects data for MyViewModel. Depending on which radio button is selected in the AJAX form, I want to update the HTML form with one set of default values or another. In the AJAX form, I'm trying to post two pieces of data: 1) a value that represents the option chosen (basedon the radio button value parameter), and 2) the Model from the view. I want the controller action to update the model based on the option received, and then return a partial view with the updated model object as parameter. How do I do this? Here's the code for the AJAX form for my attempt:
#using (Ajax.BeginForm("MyAction", "MyController",
new AjaxOptions {
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "createForm"
}))
{
<div id="formOptions">
#foreach (Option op in Model.GetOptions()) {
<div class="editor-field">
#Html.RadioButton("option", op.OptionType, false, new { #id = op.ID, #name = op.ID, #title = #op.Description, #onfocus = "javascript:$(this).closest('form').find(':submit').first().click()" })
<label for="#op.ID">#op.Name</label>
</div>
}
</div>
#Html.Hidden("model", Model)
<input type="submit" value="Select" style="display:none;" />
}
My problem is that the model parameter in the HttPost action method is null. However, the option parameter seems to get passed correctly. I'm not sure if I'm using the Html.Hidden input in a way it's not supposed to be used or what the problem is. I can post more code if needed.
This is my first attempt at doing something like this, so after reading a lot of (seemingly) similar questions I still cannot decipher the solution for what I want to do. I see a lot of different things, like JSON encoding, using JQuery, etc., but I'm not sure if I need those things, or if I can accomplish this using MVC features (I'd rather not recode things that are already built into MVC 3). If anyone can point me in the right direction or possibly give a little code example, it would be appreciated. And, given what my end goal is, if there's a better way to asynchronously update a form based on option controls, I'd be very interested to hear about it. Thanks!
EDIT:
I also noticed that the request using HttpPost does not make it to the controller, but a HttpGet does. Anyone out there? This is driving me nuts!
ADDED CONTROLLER METHOD:
public PartialViewResult CreateForm(OptionType opType, MyViewModel model) {
model.ApplyOptionValues(opType);
return PartialView("_CreateForm", model);
}
I would not post the entire model back to the controller which you are attempting to do with #Html.Hidden("model", Model) simply place the specific items you need in the form with names/types that match your controller. You can use the selected radio button's value as well as a hidden input's values to pass identifying information to the controller and perform whatever logic you need there.
That being said, I think the best solution going forward would be to use some javascript framework like JQuery to handle all AJAX requests. Asp.net MVC makes it really easy to do simple operations with the built in pieces, but once you need to perform more complicated operations, it definitely falls short. You end up putting in more effort to work within the limitations than if you just used the correct tool (JQuery).
Make sure that you annotate your POST action methods with [HttpPost] to differentiate from GET methods.
Also use a detailed web debugger to examine exactly what is being sent to your application. I like Fiddler, which is extremely popular.
http://www.fiddler2.com/fiddler2/
I would agree with Mattbo: posting the whole model round in a circle is unnecessary overhead. You don't say why you are but I suspect it's so you can compare 'old' and 'new' values. Given the model originates in the controller, you could include a unique identifier for the model (e.g. GUID) in the ViewModel, put that in a hidden field to include in your POST data, then on the return POST your 'new' data will be auto mapped to the strongly typed ViewModel. You can then re-get the original model and do whatever you need to with them both.
Dealing with the AJAX form is a separate issue/form then: you have your radio buttons which fill out default values in the (view model) form (including a hidden field to record which radio was selected), the user fills out the other data and the whole of the (non ajax) form gets posted to the MyController.MyAction method and the default binders will automatically map the form values to the MyViewModel, if they follow the right naming convention. So the AJAX has nothing to do with the form that is actually posted. Alternatively you could do the whole thing with AJAX as Mattbo also suggests.
[Aside] Forgive me if you already know but you can use the razor Html helpers to create your fields like:
#Html.EditorForModel()
#Html.EditorFor(model => model.[field name])
In the Controller you would create the actions like:
public ActionResult MyAction()
{
MyViewModel
}
[HttpPost]
public ActionResult MyAction(MyViewModel myModel)

MVC3 Finding a control by its Name

I have a C#.Net web app and I am trying to access one of the HTML/ASP Text Boxes in the Controller for the Edit View of my Proposal model. In a non-MVC app, I was able to do this using Control.ControlCollection.Find(). Is there an equivalent for a MVC3 project?
You ask for an equivalent of Control.ControlCollection.Find() in MVC?
In MVC your controller is not aware of controls.
The controller just receives data via parameters and returns data via the function result.
What do you want to do with the control in your controller code?
If you want to access the value, you should bind it to a parameter:
View:
<input name="MyControl" type="text" />
Controller:
public ActionResult MyAction(string MyControl) {
// MyControl contains the value of the input with name MyControl
}
The MVC pattern was designed to keep things separated.
The View has no knowledge of the controller at all
The Controller only knows that a view exists and what kind of data that it needs. It do not know how the data is render.
Hence, you can never get information about controls/tags in the view from the controller. You need to use javascript/jQuery in the view and invoke the proper action in the controller.
In an MVC-application you don't have controls like in a webform-application.
In MVC you collect your required data in the controller and pass it to the view.
Typicaly the view is a HTML-page with embedded code.
In opposite to controls in webforms which produce HTML and handles the post-backs in MVC you have to do all this manually. So you don't have controls with properties and events wich you can access easily in the controller and you have to handle all your posts with your own code.
Thats sounds as it is a lot of more work - and indeed it could be if you implement the behaviour of complex controls - but MVC applications are much better to maintain and you have 100% influence to the produced HTML.
Well probably i am late for this but it should help others in future...u can store ur value in hidden field in view and then access that value in controller by following code..
Request.Form["hfAnswerOrder"].ToString();
Point - hfAnswerOrder is the ID of the hidden field
My Control in cshtml page..
#Html.Hidden("hfAnswerOrder", Model.Answers.ToList()[0].AnswerOrder)

ASP.NET MVC Redirect to action without a physical redirect

Are it in any way possible to execute another action in the same on in another controller from an action, action filter or in any other way without doing a physical redirect.
The reason for this is that I have a dynamic paging system, where the user will load a url, for an example
/1/some-page-title
This url is maped to the controller “Home” and the action “Element”, this action will then load a row from the database where the element id is “1”. Depending from the data on the element from the database will the page be rendered as a contact form, an image gallery and so on.
Now I could map the paths so
/Page/1/some-title/ will render a normal html page,
/Contact/1/some-title/ will render a contact form
/Gallery/1/some-title/ will render a gallery
But I would prefer the paths to be simple.
There are problems with this answer, it's been a long time since I did anything thing with ASP MVC, so I'm not actually aware of what the problems are.
Unfortunately I can't delete an accepted answer.
So, I'm striking through the answer as it was, if you can actually answer this, or make it better, please do so.
Yes, very simple really :)
Say you're in controller C action A. You want to "redirect" to controller B action Z, just call the other controller action from the current one, returning it's result.
public ActionResult A()
{
return B.Z()
}
You may be looking for Html.RenderAction or Html.Action. However, these are used in the view and not the controller.

How to redirect users based on what page they came from?

I have a page (Controller Action that renders a View) that a user could navigate to from 3 different pages. Basically, a user gets there, does a few selections and clicks on Save button. At this point, I need to redirect the user to where he came from.
I'm wondering, what's the best practice to do that?
I know, for example, I could look in Request, figure out where he came from, then redirect back to there... But that doesn't look like the ideal approach to me.
I'm wondering, what's the best practice to do that?
Pass a returnUrl parameter when invoking this action. Store it in a hidden field if necessary. Make sure that the controller action that performs the validation and needs to redirect gets this parameter as action argument somehow and when the time comes return Redirect(returnUrl);
(Posted on behalf of the question author).
This is what I ended up doing.
Controller:
public ActionResult Index()
{
ViewBag.Referrer = Request.UrlReferrer.LocalPath;
//.....
return View();
}
View (Razor syntax):
Back

How to return a MVC View to a $.Ajax JSON POST

I am sending a $.Ajax POST to a MVC Controller function with parameters and returning a JasonResult successfully. What I need to happen is that the current View be returned (as if it was not a JSON request and I was returning the Viewdata). The Viewdata has been updated and the page needs to be redrawn.
In short, I want the MVC Action to respond back to the $Ajax request correctly, and then have the page redrawn using the updated Viewdata. Hope this makes sense, coming down with a bad cold.
Jason result, awesome.
It doesn't work like that i'm afriad, either you need to not use ajax, or you need to return data and handle it in jquery, or you need to return a partial view.
Partial view is probably the best solution, you can just return a chunk of html and stick it in ur site, very simple to use.

Resources