I am loading partial view with Jquery UI dialog. In partialview post submit I want capture results in updateSuccess function. But function was never called and results was showing on page.
Parent page
<script type="text/javascript">
function display_dialog() {
$('#my-dialog').dialog({
resizable: false,
modal: true,
show: "blind",
hide: "blind",
open: function (event, ui) {
$(this).load("/ContactSubmission/Index" );
}
});
function updateSuccess(data) {
if (data.Success == true) {
alert("Inside Update");
//now we can close the dialog
$('#my-dialog').dialog( "close" );
//twitter type notification
$('#commonMessage').html("Update Complete");
$('#commonMessage').delay(400).slideDown(400).delay(3000).slideUp(400);
} else {
$("#update-message").html(data.ErrorMessage);
$("#update-message").show();
}
}
</script>
controller
public ActionResult Index()
{
var contact = new Contact
{
Countries = Context.GetCountries()
};
return PartialView(contact);
}
[HttpPost]
public JsonResult Index(Contact contact)
{
if (ModelState.IsValid)
{
if (contact != null)
{
//Some business logic is here
var result = new { Success = "True", Message = "No Error" };
return Json(result, JsonRequestBehavior.DenyGet);
}
else{
var result = new { Success = "False", Message = "Contact is Null" };
return Json(result, JsonRequestBehavior.DenyGet);
}
}
else
{
var result = new { Success = "False", Message = "Invalid state" };
return Json(result, JsonRequestBehavior.DenyGet);
}
}
Partial view
#using (Ajax.BeginForm("Index", "ContactSubmission", new AjaxOptions{
InsertionMode = InsertionMode.Replace, HttpMethod = "POST",
OnSuccess = "updateSuccess" },new { enctype = "multipart/form-data",
#class = "form-horizontal", role = "form" }))
{
// Html code is here
<div class="form-group">
<div class="col-sm-4 col-md-offset-5">
<button type="submit" class="btn btn-primary">Submit</button>
<button type="button" class="btn btn-default" id="cancel">Cancel
</button>
</div>
</div>
}
after submit is showing like this on browser
How can I handle the issue and how to call function after submit results?
You need to reference jquery Unobtrusive otherwise the view will change.
http://www.nuget.org/packages/jQuery.Ajax.Unobtrusive/
This has caught me out before and as a result I find it much easier to write my own ajax calls in jQuery so I dont need this reference.
Good Luck
Related
maybe it was a simple question but 2 day I worked on it.
it was work for me in another view, but now not work for me
I want show second dropdownlist by change of first but not work how can I resolve that
I use chrome inspect to show
and use debug mode and breakpoints , the debugger didn't go to control
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script>
$(document).ready(function() {
$(document).on("change","#ProvinceId",function() {
var pid = this.value;
$.ajax({
type: "POST",
url:'#Url.Action("ReturnCity", "Account")',
dataType:"json",
data:{provinceId:pid},
contentType:'application/json; charset=utf-8',
success: function(data) {
$('#CityId').empty();
$.each(data,
function (index, item) {
$('#CityId').append($('<option></option>').text(item.Name).val(item.Id));
});
}, error: function (data)
{ alert(data) }
});
});
});
</script>
}
and my control is
public ActionResult Register()
{
//return PartialView("_Login");
ViewBag.ProvinceId = new SelectList(_db.Provinces, "Id", "Name");
ViewBag.CityId = new SelectList(_db.Cities, "Id", "Name",_db.Cities.Where(x => x.ProvinceId == 1));
return View("");
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email,CountryId = 55,ProvinceId = model.ProvinceId,CityId = model.CityId};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
MigrateShoppingCart(model.Email);
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
// For more information on how to enable account confirmation and password reset please visit https://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "" + callbackUrl + "\">link</a>");
// Uncomment to debug locally
// TempData["ViewBagLink"] = callbackUrl;
ViewBag.Message = "";
return View("Info");
//return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
for return city this is code in control
[HttpPost]
public JsonResult ReturnCity(int provinceId)
{
_db.Configuration.ProxyCreationEnabled = false;
var data = _db.Cities.Where(x => x.ProvinceId == provinceId);
return Json(data.ToList(), JsonRequestBehavior.AllowGet);
}
in view i use this for show two related dropdownlist
<div class="form-group">
#Html.LabelFor(model => model.ProvinceId, "استان", htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#*#Html.DropDownListFor(model=>model.ProvinceId, (SelectList)ViewBag.ProvinceId, "Select", new { htmlAttributes = new { #class = "form-control" }})*#
#Html.DropDownList("ProvinceId", "Select")
#Html.ValidationMessageFor(model => model.ProvinceId, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CityId,"City", htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#*#Html.DropDownListFor(model => model.CityId, (SelectList)ViewBag.CityId, "Select", new { htmlAttributes = new { #class = "form-control" } })*#
#Html.DropDownList("CityId", "Select")
#Html.ValidationMessageFor(model => model.CityId, "", new { #class = "text-danger" })
</div>
</div>
I see few issues with your code. First, in your ajax call, you specify the contentType contentType:'application/json; charset=utf-8',. But you are trying to send a javascript object in the data property. So jQuery will send Content-Type:application/json; charset=UTF-8 in the request header and provinceId=1 as the request payload in the request body. The server code uses the contentType header to determine how to deserialize and model bind the posted form data/request body to the parameter of your action method. Usually you specify the content type as json when you send a stringified json version of a javascript object. The Model binder will be able to map this to your method param (a view model object matching with the structure of your js object)
Since your method parameter is a simple int, you do not need to specify the contenttype as application/json. Simply remove that line and it will hit the action method in server . You can also remove the datatype param as well.
This should work as long as you do not have any other script error in the page(check browser console).
$(document).ready(function() {
$(document).on("change","#ProvinceId",function() {
var pid = this.value;
$.ajax({
type: "POST",
url:'#Url.Action("ReturnCity", "Account")',
data:{provinceId:pid},
success: function(data) {
$('#CityId').empty();
$.each(data,
function (index, item) {
$('#CityId').append($('<option></option>')
.text(item.Name).val(item.Id));
});
}, error: function (data)
{ alert(data) }
});
});
});
Also since you want user to select the city based on selected province, there is no need to load all cities. You can simply render a select element using vanilla html with Id and Name set to CityId
See this post for some sample cascading dropdown code.
Change your code as following.
Script
#section Scripts {
<script>
$(document).on("change","#ProvinceId",function() {
var pid = this.value;
$.ajax({
url: '/Account/ReturnCity',
type: "POST",
dataType: "JSON",
data: { provinceId: pid },
success: function (data) {
$("#CityId").html(""); // clear before appending new list
$.each(cities, function (i, city) {
$("#CityId").append(
$('<option></option>').val(city.CityId).html(city.CityName));
});
}
});
)}
</script>
}
Controller
public ActionResult ReturnCity(int provinceId)
{
_db.Configuration.ProxyCreationEnabled = false;
var data = _db.Cities.Where(x => x.ProvinceId == provinceId);
return Json(data , JsonRequestBehavior.AllowGet);
}
I'm trying to write CRUD operations using ajax. Here some code:
These are my View classes:
//PhotoSummary
#model PhotoAlbum.WEB.Models.PhotoViewModel
<div class="well">
<h3>
<strong>#Model.Name</strong>
<span class="pull-right label label-primary">#Model.AverageRaiting.ToString("# stars")</span>
</h3>
<span class="lead">#Model.Description</span>
#Html.DialogFormLink("Update", Url.Action("UpdatePhoto", new {photoId = #Model.PhotoId}), "Update Photo", #Model.PhotoId.ToString(), Url.Action("Photo"))
</div>
//Main View
#model PhotoAlbum.WEB.Models.PhotoListViewModel
#{
ViewBag.Title = "My Photos";
}
#foreach (var p in #Model.Photos)
{
<div id=#p.PhotoId>
#Html.Action("Photo", new {photo = p})
</div>
}
The sript:
$('.dialogLink').on('click', function () {
var element = $(this);
var dialogTitle = element.attr('data-dialog-title');
var updateTargetId = '#' + element.attr('data-update-target-id');
var updateUrl = element.attr('data-update-url');
var dialogId = 'uniqueName-' + Math.floor(Math.random() * 1000)
var dialogDiv = "<div id='" + dialogId + "'></div>";
$(dialogDiv).load(this.href, function () {
$(this).dialog({
modal: true,
resizable: false,
title: dialogTitle,
close: function () { $(this).empty(); },
buttons: {
"Save": function () {
// Manually submit the form
var form = $('form', this);
$(form).submit();
},
"Cancel": function () { $(this).dialog('close'); }
}
});
$.validator.unobtrusive.parse(this);
wireUpForm(this, updateTargetId, updateUrl);
});
return false;
});});
function wireUpForm(dialog, updateTargetId, updateUrl) {
$('form', dialog).submit(function () {
if (!$(this).valid())
return false;
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$(dialog).dialog('close');
$(updateTargetId).load(updateUrl);
} else {
$(dialog).html(result);
$.validator.unobtrusive.parse(dialog);
wireUpForm(dialog, updateTargetId, updateUrl);
}
}
});
return false;
});
}
And here my Tag builder:
public static MvcHtmlString DialogFormLink(this HtmlHelper htmlHelper, string linkText, string dialogContentUrl,
string dialogTitle, string updateTargetId, string updateUrl)
{
TagBuilder builder = new TagBuilder("a");
builder.SetInnerText(linkText);
builder.Attributes.Add("href", dialogContentUrl);
builder.Attributes.Add("data-dialog-title", dialogTitle);
builder.Attributes.Add("data-update-target-id", updateTargetId);
builder.Attributes.Add("data-update-url", updateUrl);
builder.AddCssClass("dialogLink");
return new MvcHtmlString(builder.ToString());
}
So, I have major problem if the dialog was called twice without the calling page being refreshed:
it just redirects me to the action page.
The question is how to update #Html.Action without reloading the page?
Could anyone help me?
Your #foreach loop in the main view is generating a partial view for each Photo which in turn is creating a link with class="dialogLink".
Your script handles the click event of these links and replaces it with a new link with class="dialogLink". But the new link does not have a .click() handler so clicking on the new (replacement) link does not activate your script.
Instead you need to use event delegation to handle events for dynamically generated content using the .on() method (refer also here for more information on event delegation). Note also that your current use of $('.dialogLink').on('click', function () { is the equivalent of $('.dialogLink').click(function () { and is not using event delegation. It attaches a handler to elements that exist in the DOM at the time the page is loaded, not to elements that might be added in the future.
Change your html to
<div id="photos">
#foreach (var p in #Model.Photos)
{
<div class="photo">#Html.Action("Photo", new { photo = p })</div>
}
</div>
and then modify the script to
$('#photos').on('click', '.dialogLink', function() {
....
});
Side note: There is no real need to add an id=#p.PhotoId to the containing div element and you could use <div class="photo"> as per above, and then reference it by using var updateTargetId = $(this).closest('.photo'); and delete the builder.Attributes.Add("data-update-target-id", updateTargetId); line of code from your DialogFormLink() method
I am trying to create a sample MVC4 webpage with partialViews
on my parent page ,eg., Index.cshtml page I am displaying a partialView page which will allow the user to view/update profile photo
When the index page loads ,I need this partial page to show up the photo if photo is available
once the page is loaded ,when the user uploads a new photo,I need only the partialView page to do an ajax postback and show up the new photo .
I am able to load the page with photo fetched from DB,
I am able to Save new photo to db by clicking "#btnPhotoUpload" button.
But after saving the photo ,the partialview is not getting refreshed automatically.Please help me how to get my partialview page to refesh and display the updated photo.
Here is my index page ie., "Index.cshtml"
#model MvcSamples.Models.ViewModels.UserInfoViewModel
#{
ViewBag.Title = "Ajax Partial Postback demo";
ViewBag.UserId = 1;
}
<h2>PersonalInfo example</h2>
<div id="photoForm">
#Html.Partial("_UserPhoto")
</div>
<div id="OtherDetails">
#Html.Partial("_UserDetails")
</div>
Here is my PartialView, i.e. _UserPhoto.cshtml
#model MvcSamples.Models.ViewModels.UserInfoViewModel
#using (Ajax.BeginForm("SaveProfilePhoto", "Example", new { id = "1" }, new AjaxOptions { UpdateTargetId = "photoForm", OnSuccess = "onSuccess" }, new { encType = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<a>
<img id="imgPhoto" width="100px" height="100px"/>
<label for="photo">Photo:</label>
<input type="file" name="photo" id="photo" />
<input id="btnPhotoUpload" type="button" value="Apply" />
</a>
<script type="text/javascript">
$(document).ready(function () {
$("#imgPhoto").attr('src', "#Url.Action("GetProfileImage", "Example", new { id = ViewBag.UserId })");
$("#btnPhotoUpload").click(function (event) {
//on-click code goes in here.
event.preventDefault();
SavePhotoToDb();
});
function SavePhotoToDb() {
var json;
var data;
$.ajax({
type: "POST",
url: "/Example/SaveProfilePhoto",
data: new FormData($("#form0").get(0)),
dataType: "html",
contentType: false,
processData: false,
success: saveItemCompleted(data),
error: saveItemFailed
});
}
function saveItemCompleted(data) {
$("#photoForm").html(data);
}
function saveItemFailed(request, status, error) {
}
});
</script>
}
Here is my controller ExampleController:
namespace MvcSamples.Controllers
{
public class ExampleController : Controller
{
IUserDetails usr = new UserDetails();
// GET: /Example/
[HttpGet]
public ActionResult Index()
{
//usr.GetProfilePhoto(WebSecurity.GetUserId(User.Identity.Name));
if (!string.IsNullOrWhiteSpace(User.Identity.Name))
{
ViewBag.UserId = WebSecurity.GetUserId(User.Identity.Name);
}
UserInfoViewModel model = new UserInfoViewModel();
model.GenderList = usr.FillGenderTypesDropDownList();
return View(model);
}
[HttpPost]
public ActionResult SaveProfilePhoto(HttpPostedFileBase photo, UserInfoViewModel model)
{
string path = #"C:\Temp\";
if (photo != null)
{
model.UserId = 1;//WebSecurity.GetUserId(User.Identity.Name);
ViewBag.UserId = model.UserId;
var binary = new byte[photo.ContentLength];
photo.InputStream.Read(binary, 0, photo.ContentLength);
UserPicModel upModel = new UserPicModel();
upModel.UserPhoto = binary;
upModel.UserId = model.UserId;
usr.InsertProfilePhoto(upModel);
}
return PartialView("_UserPhoto", model);
}
public FileResult GetProfileImage(int id)
{
byte[] barrImg = usr.GetProfilePhoto(id);
return File(barrImg, "image/png");
}
}
}
Update:
As #David Tansey suggested ,I added code to refresh image inside SaveCompleted(data).
function RefreshImage() {
$("#imgPhoto").attr('src', function () {
// the datetime portion appended to the url avoids caching issues
// and ensures that a fresh image will be loaded every time
var d = new Date();
return this.src + '?' + d.getTime();
});
}
But the above code is refreshing the image only after I click the upload button twice .
Actually I need this to refresh the image immediately after the $("#btnPhotoUpload").click. Any suggestions?
I also tried disabling cache at the controller but no luck:
[OutputCacheAttribute(VaryByParam = "*", Duration = 0, NoStore = true)]
I am pretty sure the problem is that the browser is caching the image file and does not 'perceive' the need to bring it across the wire again after you upload a new one.
Look at the following post for a description of how to attach a dummy (yet dynamic) query string value to prevent the caching from occuring. I think this approach will solve your problem.
asp.net mvc jquery filling image
Hope that helps.
I have a DIV (tenant-reference-photos) that holds a partial view that display photos. Beside each photo is a delete button. When it's clicked, I want the photo to be removed from the list and only the DIV to be updated by Ajax.
I'm using an Ajax.ActionLink for the delete action:
<div>
#Ajax.ActionLink("Delete", "DeleteReference",
new { id = photo.ImageId },
new AjaxOptions { InsertionMode = InsertionMode.Replace, HttpMethod = "POST",
UpdateTargetId = "tenant-reference-photos" },
new { #class = "btn btn-primary" })
</div>
Controller actions:
[HttpGet]
public ActionResult DeleteReference(int id)
{
return View(refPhotoRepository.Find(id));
}
[HttpPost, ActionName("DeleteReference")]
public ActionResult DeleteReferenceConfirmed(int id)
{
try
{
refPhotoRepository.Delete(id);
refPhotoRepository.Save();
return PartialView("_TenantReferencePhotosPartial");
}
catch (Exception e)
{
// handle exception
}
return View();
}
When I click delete, the action fires and record is deleted from the database. The problem is with return PartialView("_TenantReferencePhotosPartial");. When the action tries to return the partial, I get a NullReferenceException at #if (Model.ReferencePhotos.Count == 0).
_TenantReferencePhotosPartials.cshtml
<div>
#if (Model.ReferencePhotos.Count == 0)
{
<h3>You haven't uploaded any references!
#Ajax.ActionLink("Upload now?",
"TenantUploadReference",
new AjaxOptions
{
UpdateTargetId = "tenant-reference-photos",
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
LoadingElementId = "ajax-loader"
})</h3>
}
else
{
foreach (var photo in Model.ReferencePhotos)
{
<ul class="thumbnails">
<li class="span8">
<a href="#" class="thumbnail">
<img src="#Url.Action("GetReference", "Tenants", new { id = photo.ImageId })" alt="#photo.Name") />
</a>
</li>
<li class="span4 btn-group btn-group-vertical">
Edit
#Ajax.ActionLink("Delete", "DeleteReference",
new { id = photo.ImageId },
new AjaxOptions { InsertionMode = InsertionMode.Replace, HttpMethod = "POST", UpdateTargetId = "tenant-reference-photos" },
new { #class = "btn btn-primary" })
</li>
</ul>
}
}
</div>
Even if there are several photos in the collection and one is deleted, the exception is still thrown at the line mentioned previously. Some help would be appreciated.
How do I resolve the above error?
I've had some trouble with jQuery $ not being defined in partials even
though it's there in the source
I believe this is in connection with your problem. When I encounter this on a partial view, what always works for me is to include it in a script section. So on your _Layout.cshtml where you write your scripts you can add this:
// Do this after you referenced jquery
#RenderSection("scripts", required: false)
<script>
// some script references
</script>
Then on your view you do this:
#section scripts {
$(function() {
<script>
function onDeleteReferenceSuccess(data, status, xhr) {
if (data.error) { /* handle error */ }
else {
window.location.reload(true);
}
}
</script>
});
}
Once above is resolved, how do I update the only the DIV?
Since you deleted the item I would assume you would want to delete the div - that represents the item.
If my assumption is correct then why not give it an Id so you can delete it afterwards in your else statement:
else {
// instead of this -> window.location.reload(true);
$("#id_of_the_div").remove();
}
UPDATE:
Your updated question throws off my original answer. But let me include the updated answer here first (and then clean-up afterwards). So the reason you are having a null reference error is because you are not returning the model:
refPhotoRepository.Delete(id);
refPhotoRepository.Save();
// build the model here and pass it to the partial view
// this will most probably involve querying your data store again
var model = goBuildTheModel();
return PartialView("_TenantReferencePhotosPartial", model;
In the code below, I have a form with some informations about an employee. I'd like feel in the password and post. If the password is correct the user is redirected to /Dashboard that it's ok.
When the password is wrong, I'd like show the error (_ErrorPartial) in MyError div and still see the form. I'd like see the form and the message in the div (MyError). With the code below, when the password is wrong, I see the error message but on a blank page and not a page with the layout + the form + the error message
Any idea ?
Thanks,
My page :
#model MyApp.EmployeeModel
<script type="text/javascript">
$(document).ready(function () {
$(".").click(function () {
$.ajax({
url: '/Account/Login',
type: "Post",
data: $('#MyForm').serialize(),
success: function (result) {
alert('Im here');
$("#MyError").html(result);
//Here is code to detect error or not but removed
}
});
});
});
</script>
<div id="MyError"></div>
#using (Html.BeginForm("Login", "Account", FormMethod.Post, new { id = "MyForm" }))
{
#Html.AntiForgeryToken()
<div>
#Html.LabelFor( m => m.FirstName)
<div>
#Html.HiddenFor(model => model.Username)
#Html.LabelFor( m => m.Password)
#Html.PasswordFor(m => m.Password)
<input type="submit" class="jqClick" />
</div>
</div>
}
Controller :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(EmployeeModel employeeModel)
{
var Errors = new List<string>();
var employee = .... //Get employee from DB
if (employee == null)
{
Errors.Add("Employee trouble");
return PartialView("_ErrorPartial", Errors.AsEnumerable());
}
return RedirectToAction("Index", "Dashboard");
}
My _ErrorPartial view :
#model IEnumerable<string>
<div id="DisplayError">
#{ var error = string.Empty; }
#foreach (var err in Model){
error += err + "<br>";
}
#Html.Raw(error)
</div>
You have to make some changes to your javascript code. First of all, replace jQuery selector $(".") with specific one, like $(".jqClick"). Second of all, never hardcode urls like /Account/Login in your code, use UrlHelper for that. And the third thing is, you have to prevent a default behavior of the submit button. See the changes:
$(document).ready(function () {
$(".jqClick").click(function (e) {
e.preventDefault();
$.ajax({
url: '#Url.Action("Login", "Account")',
type: "Post",
data: $('#MyForm').serialize(),
success: function (result) {
alert('Im here');
if (result.redirectUrl)
window.location.href = result.redirectUrl;
else
$("#MyError").html(result);
//Here is code to detect error or not but removed
}
});
});
});
Also you need to change the Login action a little in order to make a redirect if a login is success:
public ActionResult Login(EmployeeModel employeeModel)
{
var Errors = new List<string>();
var employee = .... //Get employee from DB
if (employee == null)
{
Errors.Add("Employee trouble");
return PartialView("_ErrorPartial", Errors.AsEnumerable());
}
return Json(new { redirectUrl = Url.Action("Index", "Dashboard") });
}
The probable error that you throw from the server side, won't appear in success function. Instead you should have below
error:function(response)
{
//your code here
}
Simply throw exception from the controller.