MVC3 Ajax.BeginForm with PartialView and persistent routedata issue - asp.net-mvc-3

I have a main view and the URL for this view has a Action/Controller/Area and id value, something like:
http://localhost:56513/Incident/IncidentHome/Index/8c02a647-a883-4d69-91be-7ac5f7b28ab7
I have a partialview in this main view, one that calls methods in the controller via Ajax. This partial view needs to know the ID value of the url for the parent page. I found how to do this is through 'ParentActionViewContent'. Something like:
using (Ajax.BeginForm("UpdatePersonalStatusPanel", "Status", new { area = "Tools" , id = ViewContext.ParentActionViewContext.RouteData.Values["id"].ToString() }, new AjaxOptions { UpdateTargetId = "divPersStatus" }))
{
<p style="text-align: center;">
<span class="editor-label">#Html.LabelFor(m => m.StatusText)</span> <span class="editor-field">#Html.EditorFor(m => m.StatusText)</span>
<input type="submit" value="Change Current Status" />
</p>
}
Now, this works fantastic for calling the controller method. The ID is passed correctly so that the controller can then see it in the routedata. I use the id to perform a database call, and then return the partialview again. The problem is on the return. I get a 'Object reference not set to an instance of an object' on the ViewContext.ParentActionViewContext.RouteData.Values["id"].ToString() bit in the ajax.beginform , and my targetid doesn't refresh.
Clearly I must be doing something wrong. Does someone else have a better way to see the parent view's routedata through Ajax?

If I'm understanding you correctly, this partial view calls itself. So ParentActionViewContext works the first time because the first time your main view calls an action using this partial view. However, later an ajax call directly returns this partial view. When the partial view is invoked directly there is no Parent View action hence the null reference on ParentActionViewContext.
Rather than deal with with route data I recommend including the id in the model of your partial view.
new { area = "Tools" , id = Model.Id }

Related

Using ajax ActionLink in place of Html.ActionLink MVC

All,
I have an Html.Actionlink that calls a method in my controller and should return a partial view. My partial view is displayed within Index.cshtml, the partial view is _ServerStatusList.cshmtl.
View
#using (Html.BeginForm())
{
#Html.ActionLink("Start",
"StartServer",
null,
new { #class = "startButton" })
}
Controller
[HttpGet]
public PartialViewResult StartServer(Model model)
{
model.StartServer("server01");
return PartialView("~/Views/Home/_ServerStatusList.cshtml", model.Servers);
}
Right now upon clicking the start button all of the functionality works correctly as far as starting the server goes, but it returns the incorrect view. After clicking I get redirected to localHost/home/StartServer and it says "running" (as a started server should say in my server list) on a blank page. Then if I manually navigate to my server status page via the address bar it shows the server is running (as it should say) in my _ServerStatusList.cshtml.
I used an Ajax ActionLink in another part of my project to click a button and return a partial view. I tried it for this button too using this code.
<input id="StartButton" type="image" value="submit" src="~/Images/start.png" alt="Start" height="25" />
#Ajax.ActionLink("Start", "StartServer",
new AjaxOptions
{
HttpMethod = "GET",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "CurrentView"
}
)
Clicking the button does not work but clicking on the word "start" does something similar to the Html.ActionLink. If I click the Start link it takes me to Index.cshtml, displays running in the area where the partial view should be, but does not load _ServersStatusList.cshtml. Again upon manual redirection everything is as it should be, running and correctly formatted.
How can I have the Ajax ActionLink use the image as the button, and upon clicking the image, return the correct partial view?
Thanks
MVC is smart enough to find the view you need, so change your return PartialView from:
PartialView("~/Views/Home/_ServerStatusList.cshtml", model.Servers);
//To
PartialView("_ServerStatusList", model.Servers);
This should return the correct view :).

ASP.NET MVC3 passing data between primary view and a search view via Ajax link

I have just started learning ASP.NET MVC3.
I have the following scenario. In a create view for a certain model the user can lookup code/description by clicking on a link (rendered with Html.ActionLink helpers). The lookup values are retrieved from lookup tables in a database and presented in a separate view. The two views are handled by two different controllers. When the user selects a lookup value in the latter view that value (code+description) should be copied back to the create view.
How can data be passed between the two views? Is this not possible due to the stateless nature of Http requests?
I tried that with an Ajax link, but it didn't worked out.
code snippet Create view:
<fieldset>
<legend>Z-Info</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ZZL_U_CODE)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ZZL_U_CODE)
#Html.ValidationMessageFor(model => model.ZZL_U_CODE)
</div>
<div class="editor-label">
#Ajax.ActionLink("Land code test", "Index", "Domein", new {name = "lan" },
new AjaxOptions {
HttpMethod = "Get",
Url = Url.Action("Index", "Domein", new {name = "lan" }),
OnBegin = "OnBegin",
OnSuccess = "InsertCodeNaam",
OnFailure = "OnFailure",
OnComplete = "OnComplete"
})
</div>
When the user select a code/description the following Select action is called which returns Json data back.
Select action:
public class DomeinController : Controller
{
private ZZLEntities db = new ZZLEntities();
//
// GET: /Domein/
public ViewResult Index(string name)
{
DomeinViewModel model = DomeinRepositry.GetAll(name);
return View(model);
}
GET: /Domein/Select/5
public JsonResult Select(int id, string naam)
{
return Json(new DomCodeNaam { codeValue = id, naamValue = naam }, JsonRequestBehavior.AllowGet);
}
Are there other solutions possible? Can partial views be an option?
Well you have two options:
Just post back lookup values and then internally redirect to the
first ("create") view, but this time passing (internally) the values
chosen by user so the view can be rendered with chosen values. Maybe
not fancy but very easy to implement. You will loose data that user have already entered into first form though, unless you post it too or you make this a 2 step process.
If you want to use Ajax, you need update appropriate parts of the
form in the first "create" view on the client side, depending on the
actions of user (i.e. what lookup values they have chosen).
I am however a bit confused with what you exactly mean by "separate view"

View with multiple partial views posting back

I'm new to MVC (MVC3) so not sure about the best way to implement this.
I want to create a single "main" view (not strongly-typed). This "main" view will contain multiple strongly-typed partial views that each contain a form. Each partial view will therefore post back to their own POST action that does whatever. The problem I see is that when a partial view posts back, it needs to only update the partial view itself and not affect the other partial views on the page.
When I postback from a partial view now, it just returns the partial view alone back, rather than the entire "main" page.
How can this functionality be achieved in MVC3? (from a high-level perspective)
Thanks
You can post data by AJAX.
In my example I use jQuery:
<div id="first-form" class="form-container">
#Html.Partial("FirstPartial")
</div>
<div id="second-form" class="form-container">
#Html.Partial("SecondPartial")
</div>
// and here go rest forms
Your partial view may be following:
#model YourModelClass
#using (Html.BeginForm())
{
// some fields go there
}
<input type="button" value="Save Form Data" class="save-button"/>
Js would be following:
$("input.save-button").on("click", function () {
var button = $(this);
var container = button.closest("div.form-container");
var url = container.find("form").attr("action");
container.busy($.post(url, function (response) {
container.html(response);
}));
return false;
});

Using model data in a form in a partial view

I have the following code in a partial view:
#model MyOrganization.MyApp.Models.ProductListing
#using (Ajax.BeginForm("TagProduct", new AjaxOptions() { UpdateTargetId = "FormContainer" , OnSuccess = "$.validator.unobtrusive.parse('form');" }))
{
<p>
#Html.LabelFor(m => m.ModelNumber):
#Html.EditorFor(m => m.ModelNumber)
Tag Product with This Model Number
#(Html.ValidationMessageFor(m => m.ModelNumber))
</p>
}
The viewmodel that this partial view gets is instantiated and many of its properties are hydrated by the view that contains this partial view. However, when the submit is called here, the viewmodel that the controller gets has only the ModelNumber property hydrated. All the other properties are null as if a new instance is created by the partial view with only the property that was edited (ModelNumber) getting a value.
I know that the viewmodel instance passed to the partial view has all the other property values, because if I add an #Html.EditorFor(m => m.SerialNumber) I can see the SerialNumber value that the containing view had rendered in the browser's textbox and I also get it back in the controller when the form is submitted. However, I don't want an editor for the SerialNumber property on the form - I just want it back in the controller when it is submitted.
How can I can I get the entire model back to the controller as it was passed in to the partial view with only the changes that the partial view made?
When it posts the form, it DOES create a new copy of the model with whatever values you posted to it. If you need the other values, put #Html.HiddenFor the other elements you need posted.

MVC 3 POST data and the Id field

I have a strongly typed razor view for a model in my MVC 3 project. Basically its for editing the model.
The model contains an Id field for the database key and some other string fields (Its a viewModel and all but thats not the point of the question).
In the view I just have a form and a submit button and nothing else. When the View is posted to the controller the model in the controller has all fields empty EXCEPT for the Id field which seems to have been auto-magically filled up.
How and where does the Id field gets populated in the model without there being a corresponding 'input' element for it in the view.
This is probably a dumb question but I would appreciate even just a link to what I should read up on. Thanks.
I bet it comes from the url as route parameter.
For example you have the following controller:
public class HomeController: Controller
{
public ActionResult Index(int id)
{
vqr model = GetModel(id);
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// the model.Id property will be automatically populated here
// because the request was POST /home/index/123
...
}
}
and the following view:
#model MyViewModel
#using (Html.BeginForm())
{
<button type="submit">OK</button>
}
Now you navigate to GET /home/index/123 and you get the following markup:
<form action="/home/index/123" method="post">
<button type="submit">OK</button>
</form>
Notice the action attribute of the form? That's where the id comes from. Basically the Html.BeginForm() helper uses the current url when generating the action attribute, and since the current url is /home/index/123 it is what gets used.
And because if you have left the default routes in your Global.asax, the {id} route token is used at the end of the url, the default model binder successfully binds it to the Id property of your view model.
You are probably hitting a URL similar to the following: /MyObject/Edit/15
This is then returning the page that you have your blank form on.
What happens next is you have an HTML.BeginForm() which is posting BACK to /MyObject/Edit/15
Now because of the post back having the same format your routing rules are picking up the '15' and binding it back to your id.
Have you added the ID field as a hidden field?
e.g.
#Html.HiddenFor(x=> x.ID)

Resources