Ajax.BeginForm using ASP.NET MVC 3 - Nothing Happens - asp.net

All I need to do is create a simple search page that displays results in a partial view. I have a search text box and a search submit button. I followed a tutorial I found online that seems very easy and quick to implement, but I am missing something here. When I click the search button nothing happens. Any ideas on what I am doing wrong or missing would be greatly appreciated.
I include the following script files in the main layout page
#Script("jquery-1.5.1.min.js")
#Script("modernizr-1.7.min.js")
#Script("jquery-ui.min.js")
#Script("jquery.unobtrusive-ajax.js")
#Script("jquery.validate.min.js")
#Script("jquery.validate.unobtrusive.min.js")
#helper Script(string scriptName)
{
<script src="#Url.Content("~/Scripts/" + scriptName)" type="text/javascript"> </script>
}
The main search view is called AdminMenu. This is listed under a Area in my project called Admin.
The following code in my main view
#using (Ajax.BeginForm("AdminSearch", "AdminMenu", new {area = "Admin"}, new AjaxOptions { HttpMethod = "GET", InsertionMode = InsertionMode.Replace, UpdateTargetId = "searchResults"}))
{
<input type="text" name="q" />
<input type="submit" value="Search"/>
}
<div id="searchResults">
</div>
Code in my partial view _adminSearch
<div id="searchResults">
<div class="entitybox">
#{
var grid = new WebGrid(
Model,
defaultSort: "Name", canPage: false
);
}
#grid.GetHtml(
tableStyle: "_tableGrid",
columns: grid.Columns
(
grid.Column("Name", "Name", item => #Html.ActionLink((string)item.Name, "SelectRecord", new { controller = "Menu", agencyKey = item.Id, name = item.Name }))
)
)
</div>
</div>
Code for the Controller
public class AdminMenuController : Controller
{
public ActionResult AdminMenu()
{
return View();
}
public PartialViewResult AdminSearch(string q)
{
Records results = AgencyBusiness.GetAdminSearch(q);
return PartialView("_adminSearch", results);
}
}
When the search button is clicked nothing happens. If you put a break point on the AdminSearch method in the controller class it never gets hit.
Thanks in advance for your time.

I think the problem is that you have a div called "searchResults" in both your main view and partial view. Ajax is probably getting confused.

You need to include the MicrosoftAjax.js file when using Ajax.BeginForm.

I solved this issue. Odd thing. I used a shared view to show the current user at the top of the view using the following line.
#RenderPage("~/Views/Shared/_LoginBar.cshtml")
The main problem was that #Ajax.BeginForm function did not output any form tags to the browser.
By using the following line instead, the form tags appeared in the HTML source and the ajax function worked.
#Html.Partial("~/Views/Shared/_LoginBar.cshtml")

Related

Post a file from View to Controller

I have following code in view :
<div>
<input type="file" name ="file" onchange="location.href='<%: Url.Action("ChangeImage", new{Id = Model.Id}) %>'" />
</div>
And in Controller I have the ChangeImage method :
public ActionResult ChangeImage(FormCollection collection, int Id,Products products)
{
var file = Request.Files["file"];
//Do something
}
But the selected file does not post to the controller. What is the problem? How can I send the file content to the controller to use it?
Because you are not posting the form data is probably the reason.
When creating an MVC form for submitting files you must specify the "enctype", with the helpers you can do this:
#using (Html.BeginForm("MyAction", "MyController", new { #Id = Model.Id }, FormMethod.Post, new { name = "Form", enctype = "multipart/form-data" }))
{
//all form fields code in here
}
Then you will want to change your javascript to post the form, something like:
document.forms[0].submit();//assuming you only have one form
Also, your action parameters don't seem to match anything. Specifically ShopID and products. You will probably get an error because you don't have default values for them. I am not 100% sure on that part though. Or maybe you have then in other parts of your form, so it might be ok

Populate a viewmodel with a newly added database ID

This is a follow up to a question that was asked yesterday.
I have a viewmodel, which shows a list of objectives. Using jquery I can add a new objectives line to the screen (the ID is set to 0 for any new objectives listed). When I click on the Save button to Post the objective list back to the controller, the controller loops through the objective list, and checks the ID against the database. If the ID is NOT found, it creates a new objective, adds this to the DB context, and saves te changes. It then retreives the ID, and returns the View(model) to the View.
The problem is, although the ID in the model, is updated to the database ID - when the model is rendered in the View again, it's ID is still 0. So if I click Save again, it again, re-adds the "new objective added previously" to the database again.
My controller is shown below:
//
// POST: /Objective/Edit/model
[HttpPost]
public ActionResult Edit(ObjectivesEdit model)
{
if (model.Objectives != null)
{
foreach (var item in model.Objectives)
{
// find the database row
Objective objective = db.objectives.Find(item.ID);
if (objective != null) // if database row is found...
{
objective.objective = item.objective;
objective.score = item.score;
objective.possscore = item.possscore;
objective.comments = item.comments;
db.SaveChanges();
}
else // database row not found, so create a new objective
{
Objective obj = new Objective();
obj.comments=item.comments;
obj.objective = item.objective;
obj.possscore = item.possscore;
obj.score = item.score;
db.objectives.Add(obj);
db.SaveChanges();
// now get the newly created ID
item.ID = obj.ID;
}
}
}
return View(model);
}
My ID is being set in the controller:
EDIT: Another example here, showing model.Objectives1.ID being updated:
However when the view renders it, it reverts to 0:
The Objectives list is determined as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MvcObjectives2.Models
{
public class ObjectivesEdit
{
public IEnumerable<Objective> Objectives { set; get; }
public ObjectivesEdit()
{
if (Objectives == null)
Objectives = new List<Objective>();
}
}
}
The View has:
#model MvcObjectives2.Models.ObjectivesEdit
#using (Html.BeginForm())
{
#Html.EditorFor(x=>x.Objectives)
<button type="submit" class="btn btn-primary"><i class="icon-ok icon-white"></i> Save</button>
}
and in my EditorTemplate (objective.cshtml):
#model MvcObjectives2.Models.Objective
<div class="objec">
<div>
#Html.TextBoxFor(x => x.objective})
</div>
<div>
#Html.TextBoxFor(x => x.score})
</div>
<div>
#Html.TextBoxFor(x => x.possscore})
</div>
<div>
#Html.TextBoxFor(x => x.comments})
#Html.HiddenFor(x => x.ID) // This is the ID where it should now show the new ID from the database, but shows 0
</div>
</div>
I suspect the issue is somewhere in my controller - but I would appreciate any advise on how to get my View to render the new ID of the added objective.
After rewording my search, I came across several posts which say this is by design. A Posted form expects to display what it sent to the controller, if the same page is shown again.
However, you can add this, which will flush ModelState, and apparantly show the updated values from the model, updated in the controller:
ModelState.Clear();
return View(model);
I'm not certain if this has any other effect yet - but for now, it appears to work ok.
Thanks, Mark
The Html.HiddenFor has bitten me before in a similar scenario. The problem is when using this Html helper the hidden value is not updated on the re-post.
If you post something from the form and change it inside your controller, when you re-render the page using it will use the value which was originally posted to the action.
Instead use
<input type="hidden" name="ID" id="ID" value="#Html.Encode(Model.ID)" />

Acknowledge and Reload PartialView with Razor

I am new to MVC3 and Razor.
I have an "attention banner" on the master page as a Partial View that I want to "acknowledge" with a click on a link to close the banner (without reloading the page). I believe I need to use jQuery and an Ajax call, but I just can't seem to find the right combination.
Here is part of my _Layout.cshtml:
<section id="main">
<span id="attentionBar">#{ Html.RenderPartial("_AttentionBarPartial"); }</span>
#RenderBody()
</section>
This is my Partial View (just using Session as a shortcut for now to get it to work). I'm not sure what to use as the "link" to reload the view:
#{ this.Layout = null;}
#if(! String.IsNullOrWhiteSpace(#Session["Attention"].ToString()))
{
<div class="attentionPanel">
<span class="attentionLabel">Attention</span>
#Session["Attention"].ToString()
<span class="attentionLabel">
#* WHAT DO I PUT HERE *#
#Ajax.ActionLink("X", "AcknowledgeAttentionBar", "Home", new AjaxOptions{ UpdateTargetId="attentionPanel", InsertionMode=InsertionMode.Replace })
</span>
</div>
}
Here is my Home controller. Again, I am not sure that the code is quite correct, but essentially I will clear out the condition that shows the attention banner.
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Home Controller Updated At " + DateTime.Now.ToLongDateString()
+ " " + DateTime.Now.ToLongTimeString();
return View();
}
public PartialViewResult AcknowledgeAttentionBar()
{
Session["Attention"] = String.Empty;
return PartialView("_AttentionBarPartial");
}
}
2 things:
Make sure you have included the jquery.unobtrusive-ajax.js script to your page in order for Ajax.ActionLink helper to work and send an AJAX request when the link is clicked instead of a normal redirect:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
In your AjaxOptions you have specified UpdateTargetId="attentionPanel" but there's no element in your markup with id="attentionPanel". You have a div with class="attentionPanel" but that's not the same thing. On the other hand you have wrapped your banner in a <span id="attentionBar">, so you probably meant UpdateTargetId="attentionBar".

Asp.Net MVC Return to page on error with fields populated

I am starting a new project in Asp.net MVC 2.
I have been mostly a webforms developer and have limited exposure to Asp.Net MVC and hence this is probably a noob question.
My situation is as follows:
I have a create page for saving some data to the DB.
The view for this page is not strongly bound / typed - so the way I am extracting the data from the view is by looking at the POST parameters.
Incase there is an error (data validation, etc), I need to send the user back to the previous page with everything filled in the way it was and displaying the message.
On webforms, this got handled automatically due to the view state - but how can I go about doing the same here?
A code example can be as follows:
View:
<% using (Html.BeginForm("Create", "Question", FormMethod.Post)) { %>
<div>
Title: <%: Html.TextBox("Title", "", new { #style="width:700px" })%>
</div>
<div>
Question: <%: Html.TextBox("Question", "", new { #style="width:700px" })%>
</div>
<input type="submit" value="Submit" />
<% } %>
Controller:
[HttpPost]
[ValidateInput(false)]
public ActionResult Create() {
Question q = new Question();
q.Title = Request.Form["Title"];
q.Text = Request.Form["Question"];
if(q.Save()) {
return RedirectToAction("Details", new { id = q.Id });
}
else {
// Need to send back to Create page with data filled in
// Help needed here
}
}
Thanks.
You could simply return the View in case of error. This will preserve the context.
[HttpPost]
[ValidateInput(false)]
public ActionResult Create(Question q) {
if(q.Save()) {
return RedirectToAction("Details", new { id = q.Id });
}
else {
// Need to send back to Create page with data filled in
// Help needed here
return View();
// If the view is located on some other controller you could
// specify its location:
// return View("~/Views/Question/Create.aspx");
}
}
Also I would recommend you to use strongly typed views along with the strongly typed helpers. Notice how I used a Question object directly as action parameter. This is equivalent to the code you have written in which you were manually extracting and building this object. The model binder does this job automatically for you.

Retrieving data from Html.DropDownList() in controller (ASP MVC) | string returned?

I have the following problem:
I have a form in site/banen (currently local running webserver) which is using a SQL database. The link is made using ADO.net and is instantiated in the controller in the following way:
DBModelEntities _entities;
_entities = new DBModelEntities(); // this part is in the constructor of the controller.
Next, I use this database to fill a Html.DropDownList() in my view. This is done in two steps. At the controller side we have in the constructor:
ViewData["EducationLevels"] = this.GetAllEducationLevels();
and a helper method:
public SelectList GetAllEducationLevels()
{
List<EducationLevels> lstEducationLevels = _entities.EducationLevels.ToList();
SelectList slist = new SelectList(lstEducationLevels, "ID", "Name");
return slist;
}
In the view I have the following:
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Fields</legend>
<!-- various textfields here -->
<p>
<label for="EducationLevels">EducationLevels:</label>
<!-- <%= Html.DropDownList("EducationLevels", ViewData["EducationLevels"] as SelectList)%> -->
<%= Html.DropDownList("EducationLevels", "..select option..")%>
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
Now, the form is rendered correctly when I browse to the create page. I can select etc. But when selected I have to use that value to save in my new model to upload to the database. This is where it goes wrong. I have the following code to do this in my controller:
//
// POST: /Banen/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection form)
{
// set rest of information which has to be set automatically
var vacatureToAdd = new Vacatures();
//vacatureToAdd.EducationLevels = form["EducationLevels"];
// Deserialize (Include white list!)
TryUpdateModel(vacatureToAdd);
// Validate
if (String.IsNullOrEmpty(vacatureToAdd.Title))
ModelState.AddModelError("Title", "Title is required!");
if (String.IsNullOrEmpty(vacatureToAdd.Content))
ModelState.AddModelError("Content", "Content is required!");
// Update the variables not set in the form
vacatureToAdd.CreatedAt = DateTime.Now; // Just created.
vacatureToAdd.UpdatedAt = DateTime.Now; // Just created, so also modified now.
vacatureToAdd.ViewCount = 0; // We have just created it, so no views
vacatureToAdd.ID = GetGuid(); // Generate uniqueidentifier
try
{
// TODO: Add insert logic here
_entities.AddToVacatures(vacatureToAdd);
_entities.SaveChanges();
// Return to listing page if succesful
return RedirectToAction("Index");
}
catch (Exception e)
{
return View();
}
}
#endregion
It gives the error:
alt text http://www.bastijn.nl/zooi/error_dropdown.png
I have found various topics on this but all say you can retrieve by just using:
vacatureToAdd.EducationLevels = form["EducationLevels"];
Though this returns a string for me. Since I'm new to ASP.net I think I am forgetting to tell to select the object to return and not a string. Maybe this is the selectedValue in the part where I make my SelectList but I can't figure out how to set this correctly. Of course I can also be complete on a sidetrack.
Sidenote: currently I'm thinking about having a seperate model like here.
Any help is appreciated.
You can't return an object from usual <SELECT> tag wich is rendered by Html.DropDownList() method, but only string variable could be returned. In your case ID of EducationLevels object will be send to the server. You should define and use one more custom helper method to reconstruct this object by ID.

Resources