MVC3: How to correctly call Ajax to update PartialView - ajax

I have 2 Actions in my controller:
// GET: /Directory/
public ActionResult Index()
{
ViewModels.DirectoryIndex model = new ViewModels.DirectoryIndex();
return View(model);
}
// POST: /Directory/Filter/[viewModel]
[HttpPost]
public ActionResult Filter(ViewModels.DirectoryIndex viewModel)
{
int distance = 0;
string state = string.Empty;
if (viewModel.SelectedDistance > 0)
distance = viewModel.SelectedDistance;
else if (viewModel.SelectedState > 0)
state = viewModel.States.Where(a => a.Value == viewModel.SelectedState.ToString()).FirstOrDefault().Text;
// TODO: Add filter activities here...
return PartialView("IndexPartial", viewModel);
}
I have a View and a PartialView (NOTE: I am not using Razor!)
The view looks like:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<RainWorx.FrameWorx.MVC.ViewModels.DirectoryIndex>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<div class="Column12">
<div class="Shadow"></div>
<h2 class="h2row"><%= Model.PageTitle %></h2>
<% using (Ajax.BeginForm("Filter", new AjaxOptions { UpdateTargetId = "filteredList" })) { %>
<div class="searchDirectory">
<label title="State">State: </label>
<%= Html.DropDownListFor(a => a.SelectedState, Model.States, "-- Select One --", new { #id = "ddlStates" })%>
-or-
<label title="ZipCode">Zip Code within: </label>
<%= Html.DropDownListFor(a => a.SelectedDistance, Model.Distance, "-- Select One --", new { #id = "ddlDistance" })%>
<input type="text" id="myZip" name="myZip" />
<input type="submit" value="Filter" />
</div>
<% } %>
<div id="filteredList" class="businessCard">
<% { Html.RenderPartial("IndexPartial", Model); } %>
</div>
<div style="height: 200px;"></div>
</div>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="head" runat="server">
<link type="text/css" href="Content/css/directory.css" rel="Stylesheet" />
<script src="Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript" />
<title><%= Model.PageTitle %></title>
</asp:Content>
The PartialView looks like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<RainWorx.FrameWorx.MVC.ViewModels.DirectoryIndex>" %>
<% foreach (var d in Model.Dealers) { %>
<div class="businessCard Outline">
<div class="businessCard Logo">
<img src="<%= Url.Content("~/Content/Images/Directory/logo01_150wide.png") %>" alt="Logo" />
</div>
<div class="businessCard Info">
<div class="businessCard Name"><%= d.Name %></div>
<div class="businessCard Address"><%= d.Address %></div>
<div class="businessCard City"><%= d.City %>, <%= d.State %> <%= d.ZipCode %></div>
<div class="businessCard Phone"><%= d.Phone %></div>
</div>
</div>
<% } %>
Now, for some reason, when I select a filter to use and submit the form it does call into the second action correctly. However, it does not refresh the PartialView, instead I get the PartailView rendered as a full view. In URL terms:
I start at http://mysite.com/Directory - select my filter, click submit.
I end at http://mysite.com/Directory/Filter when I expect to end at http://mysite.com/Directory !!
I am obviously missing something simple. I've done this before in Razor (love Razor over this mess BTW) and it all works there.
NOTE: This is a 3rd party product I am extending so don't have the luxury of converting everything to Razor.

You need to have both the following files referenced in your html. I think there is a jQuery alternative... but referencing both of these JavaScript files (which are probably already in your MVC solution) should solve your problem.
<script src="/Scripts/MicrosoftAjax.js" type="text/javascript"></script>
<script src="/Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>

Related

Access Div tag in Page from Masterpage codebehind

I need access div in a page.
page.aspx
<asp:Content ID="Content" ContentPlaceHolderID="ContentPlaceHolderBody1" runat="server">
<div class="table-responsive">
<div class="card card-authentication1 mx-auto my-5" id="div_Payment" runat="server"></div>
</div
</asp:Content>
masterpage
protected void Admin_Load(object sender, EventArgs e)
{
HtmlControl control = (HtmlControl)Page.FindControl("ContentPlaceHolderBody1").FindControl("div_Payment");
HtmlControl control = (HtmlControl)Master.FindControl("ContentPlaceHolderBody1").FindControl("div_Payment");
control.Style.Add("display", "none");
}
no luck.
This should work:
Markup:
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<asp:Label ID="Label1" runat="server" Text="This is fun"></asp:Label>
<div class="table-responsive">
<div class="card card-authentication1 mx-auto my-5" id="div_Payment" runat="server">xxxx</div>
</div>
</asp:Content>
code behind on master page:
System.Web.UI.WebControls.Label MyLabel1 =
(System.Web.UI.WebControls.Label)MainContent.FindControl("Label1");
Debug.Print("Value of Lable 1 on child page = " + MyLabel1.Text);
HtmlGenericControl MyDiv = (HtmlGenericControl)MainContent.FindControl("div_Payment");
Debug.Print("Inner text = " + MyDiv.InnerText);
so, you don't have to "find" the first "content" control - that will exist.
(you could, but it not required).
I found it
HtmlControl MyDiv = (HtmlControl)Page
.Master
.FindControl("ContentPlaceHolderBody1")
.FindControl("Panel1");

Rails Mailer messed up

I implemented a RoR mailer with my Ruby on Rails Application and it worked well. But to my surprise, every time a mail is sent, other attributes from my database table is populated in my sent email which I do not want.
To have a diagramatic view of my problem, see this Mailer Preview image:
model(job.rb)
class Job < ActiveRecord::Base
def self.jobs_posted_12hrs_ago
where.not('stripeEmail' => nil).where.not('payola_sale_guid' => nil).where('created_at > ?', Time.now - 12.hours)
end
end
app/mailer/job_notifier.rb
class JobNotifier < ApplicationMailer
def send_post_email(job)
#user = User.where(:email => true).all
emails = #user.collect(&:email).join("#{';'}")
#jobs = job
#job = job
mail(:to => emails, :bcc => User.pluck(:email).uniq, :subject => 'New job posted on FarFlungJobs')
end
end
email template/view(send_post_email.html.erb)
I did iterate over my scope and populated just Comapny Name, Job Title, and Date. but when the email is previewed/sent, other attributes in the database are populated with it.
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
</head>
<body>
<div>
<h3> Hi, new job just posted on FarFlungJobs.com! </h3>
</div>
<section>
<p>Fresh Job</p>
<hr>
<p>
<% jobs = Job.jobs_posted_12hrs_ago %>
<%= jobs.each do |job| %>
<section class="container">
<div class="row jobs">
<div class="col-md-4" style="font-size: 20px;"><strong><%= job.company_name %></strong></div>
<div class="col-md-4" style="font-size: 20px;"><%= link_to(job.title, job) %></div>
<div class="col-md-4 text-right" style="font-size: 20px; float: left;"><%= job.created_at.strftime('%d %B %y') %></div>
</div>
<%= render 'shared/two_breaks'%>
</section>
<% end %>
</p>
<p>Thanks for subscribing to FarFlungJobs once again. <%= jobs_url %> </p>
</section>
</body>
</html>
What can I do to make sure I only have just the specified attributes in my email template being sent, instead of it add all I dont want?
The problem is this line:
<%= jobs.each do |job| %>
Because of the <%= it will print out the result of the each statement, which is jobs.

form tag doesn't render in partial view with jquery dialog. mvc3 asp.net

i have a partial view "CreateJobLine.cshtml" that contains a form. this form when rendered using #Html.Action method creates the form fields without the form tag. i used the Html.BeginForm as well as hard coded the form (below), but in both situation its not generating the tag. I am also using jqueryui's dialog widget to display the form.
---Partial View ---
//filename: CreateJobLine.cshtml
#model Recruitment.Models.JobLine
#if(false){
<script src="#Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
}
<div id="addnewjoblinediv">
<form id="createjoblineform" action="#Url.Action("CreateJobLine")" method="post">
#Html.ValidationSummary(true)
<fieldset>
<legend>JobLine</legend>
#Html.Hidden("job_id", Model.JobId)
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TimeSpent)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.TimeSpent)
#Html.ValidationMessageFor(model => model.TimeSpent)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.JobId)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.JobId)
#Html.ValidationMessageFor(model => model.JobId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
</form>
</div>
In the edit view, I have Html.Action call to load the partial view.
---Edit View---
//filename Edit.cshtml
...
#Html.Action("CreateJobLine", "Job", new { job_id = Model.Job.JobId})
<a id="addnewjoblinelink" href="#">Add New JobLine</a>
</fieldset>
}
<script type="text/javascript">
$(document).ready(function () {
$("div#addnewjoblinediv").dialog({ autoOpen: false, modal:true, width:550, title:"Add New JobLine"});
$("a#addnewjoblinelink").click(function () {
$("div#addnewjoblinediv").dialog("open");
}
);
}
);
</script>
Here is the controller
---Job Controller---
//JobController.cs
...
[HttpGet]
public PartialViewResult CreateJobLine(int job_id)
{
var jobline = new JobLine();
jobline.JobId = job_id;
jobline.TimeSpent = 0;
return PartialView(jobline);
}
[HttpPost]
public ActionResult CreateJobLine(JobLine jobline)
{
if (ModelState.IsValid)
{
db.JobLines.Add(jobline);
db.SaveChanges();
return RedirectToAction("Index");
}
return RedirectToAction("Edit", new { id = jobline.JobId });
}
...
call to /Job/CreateJobLine/5 gets the form content with all the form elements, but the form tag itself is missing. I want to get that form action be set to /Job/CreateJobLine post method so that I can create a JobLine.
Thank you.
I think your problem is #Html.Action. I believe it's simpler and closer to what you want to just render a partial view like this:
#{ Html.RenderPartial("CreateJobLine", new MvcApplication1.Models.JobLine { JobId = 10 }); }
I say that because when I use RenderPartial like I would normally do, the form is rendered correctly inside the dialog (all the rest of the code is how you posted it). I can't use Html.Action with the code you posted (probably because you omitted something else), so that indicates to me your problem is around that method. Good luck.

MVC Remote Attribute - Issue with submit

I'm trying to check if the combination of typeId & supplementId already exists in my database. So I've added a remoteattribute to my supplementId which does this. My problem is that the validation should trigger on changing either dropdownlist. I kinda fixed this clientside with the javascript on the ddl onchange. But now I'm not able to post my form. When I click the button, it focuses the last dropdownlist but doesn't show any errors and my Post method in the controller doesn't get fired. If I execute a form.submit() in chrome console the method gets called but validation is ignored. Anyone had this issue before?
BTW this code is cleaned to a minimum so labels, errormessages, etc could be missing,
these shouldn't be the issue.
Partial view:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SupplementTypeClass>" %>
<script src="<%: Url.Content("~/Scripts/jquery-1.5.1.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.validate.min.js") %>" type="text/javascript"></script>
<script src="<%: Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js") %>"
type="text/javascript"></script>
<% using (Html.BeginForm("AddEditSupplementType", "Supplement"))
{ %>
<%: Html.ValidationSummary(true)%>
<fieldset>
<legend>
Add type
</legend>
<div class="editor-content">
<div class="editor-label">
<%: Html.LabelFor(model => model.SupplementId)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.SupplementId, new SelectList(ViewBag.Supplements, "SupplementId", "Name", Model.SupplementId), "Select supplement", new { onchange = "$('#ddl').removeData('previousValue');$('#ddl').valid();" })%>
<%: Html.ValidationMessageFor(model => model.SupplementId)%>
</div>
</div>
<div class="editor-content">
<div class="editor-label">
<%: Html.LabelFor(model => model.TypeId)%>
</div>
<div class="editor-field">
<%: Html.DropDownListFor(model => model.TypeId, new SelectList(ViewBag.Types, "TypeId", "Name", Model.TypeId), "Select type", new { id ="ddl" })%>
<%: Html.ValidationMessageFor(model => model.TypeId)%>
</div>
</div>
<div class="editor-buttons">
<input type="submit" value="Save" />
</div>
</fieldset>
<% } %>
Controller:
[HttpPost]
public ActionResult AddEditSupplementType(SupplementTypeClass sup)
{
if (ModelState.IsValid)
{
//code to insert to DB
}
return RedirectToAction("FicheAddEditSupplementType", new { supplementTypeId = sup.supplementTypeId});
}
Class:
public class SupplementTypeClass
{
#region Members
public int SupplementId { get; set; }
[RemoteAttribute("SupplementTypeCheck", "Supplement", AdditionalFields = "SupplementId")]
public int TypeId { get; set; }
#endregion
}
The Remote attribute does Ajax calls using the GET method by default, not POST.
Make your you specificy the POST method in your model
[RemoteAttribute("SupplementTypeCheck", "Supplement", AdditionalFields = "SupplementId", HttpMethod="POST")]

MVC - Using Ajax to render partial view

I have this markup in an MVC app.
<div id="ingredientlistdiv">
<% Recipe recipe = (Recipe)Model; %>
<% Html.RenderPartial("IngredientsListControl", recipe.Ingredients); %>
</div>
<div id="ingrediententrydiv" align="left">
<% using (Ajax.BeginForm("Add Ingredient", "Recipes/UpdateStep2", new AjaxOptions { UpdateTargetId = "ingredientlistdiv" }))
{ %>
<p>
<label for="Units">Units:</label><br />
<%= Html.TextBox("Units", 0)%>
<%= Html.ValidationMessage("Units", "*")%>
</p>
<p>
<label for="Measure">Measure:</label><br />
<%= Html.TextBox("Measure")%>
<%= Html.ValidationMessage("Measure", "*")%>
</p>
<p>
<label for="IngredientName">Ingredient Name:</label><br />
<%= Html.TextBox("IngredientName")%>
<%= Html.ValidationMessage("IngredientName", "*")%>
</p>
<p>Save Ingredient</p>
<%= Html.Hidden("RecipeID", recipe.RecipeID.ToString())%>
<% } %>
</div>
When this runs the IngredientsListControl.ascx displayas a new page
in the browser and does not update the ingredientlistdiv.
This is my controller action
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult UpdateStep2(FormCollection form)
{
var factory = SessionFactoryCreator.Create();
using (var session = factory.OpenSession())
{
Recipe recipe = GetRecipe(session, Convert.ToInt32(form["RecipeID"]));
Ingredient ingredient = new Ingredient();
ingredient.UpdateFromForm(form);
ingredient.Validate(ViewData);
if (ViewData.ModelState.Count == 0)
{
recipe.Ingredients.Add(ingredient);
session.Save(recipe);
return PartialView("IngredientsListControl", recipe.Ingredients);
}
return Content("Error");
}
}
Am I doing the right thing on this line?
return PartialView("IngredientsListControl", recipe.Ingredients);
Is that how I render the control into the div so it does
not load new page.???
Malcolm
When you use this:
<a href="javascript:document.forms[0].submit()">
...you should be aware that it's not the same as
<input type="submit" />
It doesn't raise the onsubmit event, and MVC's AJAX eventhandler is not called.
To confirm this is the issue, add
<input type="submit" />
inside the form and try it out.
Finally, just call onsubmit() from your link
<a href="#" onclick="document.forms[0].onsubmit()">
Might be worth ensuring that you have correctly referenced the ajaxmvc and jquery scripts in your page (master page). If these are incorrect a new page will be displayed instead of the correct output in the target div.
RenderPartial takes an action name, not the name of the user control, so replace "IngredientsListControl" with "UpdateStep2", your action name.

Resources