For several days I just can not find the problem itself, which is really driving me crazy.
I have asp.net (mvc4) web application, where there are several index pages (showing list), when clicking on any item in the list, it returns edit view page.
In the edit page (in the view itself) - there is a submit button, which should update the db and redirect to the index page.
(At first, that "submit" was loaded with all html edit code via partial view, but I changed it so i can redirect to index page - because "child actions are not allowed to perform redirect actions").
So the problem is that controller does not redirect to the index page.
When I put a breakpoint in the post function in controller, I see that few threads runs the code although not asked for threads, and if i stand with the cursor on one of the processes debug arrows, I can see message "the process or thread has changed since last step".
Somehow, I don't know how, I solved the problem in one page (dont know how, because I dont know what caused this), but sometimes (randomly) it's appears again, and in the other page I did not manage to solve it.
Here is some code from controller and from view:
Controller:
[HttpPost]
public ActionResult Edit([ModelBinder(typeof(OpportunityBinder))] OpportunityModel draft)
{
try
{
if (Request.Params["cancel"] != null)
{
return RedirectToAction("index", Utils.CrmDB.GetOpportunities());
}
if (draft.IsValid())
{
if (Utils.CrmDB.UpdateOpportunity(draft))
return RedirectToAction("Index", Utils.CrmDB.GetOpportunities());
}
return View(draft);
}
catch
{
return View();
}
}
View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
/* Some divs */
<p>
<input type="submit" value="Update" />
</p>
</fieldset>
<fieldset>
/* Some partial views*/
/* loaded using #Html.Action() */
</fieldset>
}
#section Scripts
{
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryui")
}
Partial view code:
#model Genius_crm.Models.ActivityListModel
<p>
<button id="dlgAddActivity">
New
</button>
</p>
<div>
<table>
/* some tr and td */
</table>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('#dlgAddActivity').each(function () {
var $link = $(this);
var pathname = window.location.pathname;
var parts = pathname.split('/')
var sub = parts[3]
var $dialog = $('<div id="addDialog"></div>')
.load('#Url.Action("AddActivityToOppPartial", "Opportunity")?CustId=#ViewBag.CustId&OppId=#ViewBag.OppId')
.dialog({
autoOpen: false,
title: $link.attr('title'),
width: 758,
height: 265,
resizable: false,
//close: function (event, ui) { window.location.reload();}
});
$link.click(function () {
$dialog.dialog('open');
return false;
});
});
});
So - I Hope I have made my problem clear.
I've been through some posts on the subject, and none of them helped me.
The problem appears also in chrome, and in IE too.
EDIT #1 -
When commenting out the partial views the problem disappears in all pages!
EDIT #2 -
Seems that there is a problem with buttons loaded in partials which using other controller actions.
EDIT #3 -
I have added code of partial view loaded with #Html.Action(), which include one script for jquery-ui dialog.
Oh lord ! It was a tough week, But at least I learned a lesson.
The problem was composed of two parts:
(1) EF and DataContext management (I re-tag the question).
I used a single static instance (singleton) of DataContext, and it turned out to be ineffective and problematic.
So I was looking for some information and found that there are better implementations for DataContext management (you can read here) and now - everything seems right!
(2) jQuery validating all partials on form submit. I had to find a way to handle it.
A solution of one part without the other - did not yield a good result.
$link.click(function () {
$dialog.dialog('open');
return false;
});
Should be like
$link.click(***return*** function () {
$dialog.dialog('open');
return false;
});
Related
I've searched and searched and for the life of me cannot figure out what I'm doing wrong. I have a Kendo UI window like so:
<a id="#(item.POD_ID)" class="k-button btn-reminder" title="Add Reminder" onclick="$('#windowR#(item.POD_ID)').data('kendoWindow').open();"><span class="icon-reminder icon-only btn-reminder"></span></a
#(Html.Kendo().Window()
.Name("windowR" + item.POD_ID)
.Title("Set Reminder")
.Content("loading...")
.LoadContentFrom("_LoadReminder", "Purchasing", new { id = item.POD_ID })
//.Iframe(true)
.Draggable()
//.Resizable()
.Modal(true)
.Visible(false)
.Width(200)
.Height(80)
.Events(events => events
.Close("onCloseReminder")
.Open("onOpenReminder")
.Deactivate("function() { this.refresh();}")
.Activate("function(){ $('#empNumBox').focus(); }")
)
)
And, if the window is an Iframe, all of this works just fine, however I cannot have it as an Iframe, because that means reloading all of the scripts and styles within it and more difficult to reference parent.
So this window, loads content from the partial view like so:
#using (Ajax.BeginForm("SetReminders", "Purchasing", new AjaxOptions { UpdateTargetId = "result" }))
{
<div id="result"></div>
<input type="number" id="empNumBox" name="empNum" style="width: 70px" class="k-textbox" required autofocus="autofocus" value="#(ViewBag.EMP_NUM)"/>
<input type="hidden" value="#ViewBag.POD_ID" name="podID" id="POD_ID_Form_Field"/>
<input type="submit" id="submitReminder_button" style="width:auto;" class="k-button submitReminder_button" value="Remind" />
}
That partial view also renders fine. Here is the problem though, when you submit the ajax form, and the kendo window is not an iframe, it will render the whole page as whatever the controller returns (and I have tried several things, you can see in the commented out code below:
[HttpPost]
public ActionResult SetReminders(int empNum, int podID)
{
//some database stuff that works fine
string response;
if (existingReminder == 0)
{
//more db stuff that also works fine
db.SaveChanges();
response = "Success!";
}
else
{
response = "Reminder exists.";
//return PartialView("_LoadReminder", new string[] { "Reminder already exists!" });
}
// $('#submitReminder_button').closest('.k-window-content').data('kendoWindow').close();
//alert('Hello world!');
//return Content("<script type='text/javascript/>function(){alert('Hello world!');}</script>");
return PartialView("_SubmitSuccess");
//return Json(response);
//return Content(response, "text/html");
}
If anyone is curious, all that the _SubmitSuccess contains is the word "Success!".
Here's an example that I found with the ajax response being put in a div, which I followed:
http://pratapreddypilaka.blogspot.com/2012/01/htmlbeginform-vs-ajaxbeginform-in-mvc3.html
It seems the real issue here is the Kendo window, but I have yet to find something on their forums about this, doesn't seem that there's a lot of examples of using a kendo window to load a partial view that submits an form via ajax and returns a different partial view to be loaded within the same window and does not use an iframe.
Any suggestions welcome, even about other parts of the code, I'm always looking to improve.
Try changing the return type of SetReminders() to PartialViewResult
I dint find answers to this and tried several ways. any help would be appreciated thanks !!
I have view which updates the page without reloading on each click using ajax scripts. Below is the code. but after entire partial views are generated, I want user to redirect complete different view on clicking a link which is not associated to controller user is in now.
my View
#model IMONLP.Models.Search
#{
ViewBag.Title = "Search";
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
#using (Ajax.BeginForm("Search", new AjaxOptions() { UpdateTargetId = "results"
}))
{
<br />
#Html.TextBoxFor(m => m.search_text, new { style = "width: 200px;" })
<input type="submit" value="search" />
}
#Ajax.ActionLink("Try Demo", "PLNHK", "PLNHK", new AjaxOptions { })
// this ajax link should redirect to different view,
<div id="results">
#if (!String.IsNullOrEmpty(#Model.search_text))
{
Html.RenderPartial("Searchprocess", Model);
}
</div>
My controller:
public ActionResult Search(Search s)
{
//do something
return PartialView("Searchprocess", s);
}
public ActionResult Selected(Search s)
{
//DO something
return PartialView("Selected", s);
}
The above "TryDEMO" "PLNHK" ajax action link will have to be redirected to new controller and new action and return view thats returned by that action. everytime I click on that, I found it moving to that controller and then to corresponding view but again its getting back to old page. I used #html.actionlink instead of Ajax, but now I get this error
The "RenderBody" method has not been called for layout page "~/Views/PLNHK/PLNHK.cshtml".
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
EDIT : I did create PLNHK.cshtml. while I'm trying to debug this, the control goes to PLNHK controller then to PLNHK view(PLNHK.cshtml) parses each and every step in that page, but finally I would get the output to be the older page. I was thinking may be the Ajax scripts on before page is the reason.
I am used to ASP.NET web forms, and am slowly learning ASP.NET MVC.
My website has a little login form on the homepage. My natural thought is that this login form may be useful in other places, and it is not the primary action of the homepage, so I want to separate it off into a partial view. And because it is related to accounts, I want the login in my AccountController not my HomepageController.
Login form is a pretty basic strongly typed partial view:
#model Models.Account.AccountLogin
<h2>Login Form</h2>
#using (Html.BeginForm("_Login", "Account")) {
#Html.ValidationSummary()
<div>
<span>Email address:</span>
#Html.TextBoxFor(x => x.EmailAddress)
</div>
<div>
<span>Password:</span>
#Html.PasswordFor(x => x.Password)
</div>
<div>
<span>Remember me?</span>
#Html.CheckBoxFor(x => x.RememberMe)
</div>
<input type="submit" value="Log In" />
}
</div>
On the homepage, I have this:
#Html.Action("_Login", "Account")
Finally, in the account controller, this:
[HttpGet]
public PartialViewResult _Login()
{
return PartialView();
}
[HttpPost]
public PartialViewResult _Login(AccountLogin loginDetails)
{
// Do something with this
return PartialView();
}
Now when I load my homepage, it looks OK and contains the form. When I click the Log In button, it takes me to myurl/Account/_Login, which contains the form, but not within the _Layout master page, just basic plain HTML and it doesn't do anything at all when I click Log In.
I am pretty sure that I have just missed some fundamental aspect of what I am supposed to be doing here, can someone please point me in the right direction?
It's because you're returning a partial view, which strips away the master page and just returns the main content. Often actions starting with an underscore are used for partials (e.g. ajaxing in a bit of a page, but not the full page). It sounds like you want a full action, and not a partial, so
[HttpPost]
public ActionResult Login(AccountLogin loginDetails)
{
// Do something with this
return View();
}
The issue here is that you are doing a fullpage postback.
You have two options, really.
Firstly, you can use a full page postback, and then call Html.Partial to display your Partial.
Something like
[HttpGet]
public ActionResult Login()
{
return View();//this typically returns the view found at Account/Index.cshtml
}
And then create a View along the lines of
#{
ViewBag.Title = "Index";
}
<h2>Title</h2>
#Html.Partial("PartialNameGoesHere")
Your partial is then rendered where indicated, but this is done when the page loads (if you look at the generated HTML, it appears exactly as though you had written it inline).
Or you can use jQuery/AJAX to load the partial on demand. Let's say you have a homepage of some description
public ActionResult Home()
{
return View();
}
public ActionResult Login()
{
return PartialView("_Login");
}
Create the view
#{
ViewBag.Title = "Index";
}
<h2>Home</h2>
<div>
<p>Hey welcome to my pretty awesome page!</p>
</div>
Show me the login!
<div id="container">
</div>
You can then load the PartialView into the container div whenever you need it, using some JS.
$(function() {
$('.my-login-link').click(function() {
$.ajax({
url: 'account/login',
success: function(data) {
$('#container').html(data);
}
});
return false;//cancel default action
});
});
In that instance, the page loads as normal without the login part. When the user clicks the link, the Login on the controller Account is called using AJAX/jQuery. This returns the HTML of the PartialView, which you can then add to the page using jQuery in the Success handler.
Imagine I have a Partial View with a list of users ( loop ) where each user is another partial view with details about one.
foreach (var user in Model.Users)
{
<a href="#" onclick="JavascriptFunction(user.Id);">Details<a>
}
When I click the above Details link for one of the list items a popup (JQuery modal dialog() ) pops up with details about that selected user. Or at least that's the goal. I need to get the selected user details to a new popup that opened.
So now I need to populate the model behind the partial view that the popup will contain with user details before .dialog('Open') triggers.
Question: What's the best way, from within a Javascript function ( onclick JavascriptFunction function in the example above) to call an ActionMethod and populate the Partial View model before the dialog is displayed ?
Right now I'm doing it the following way but for whatever reason I'm getting major delays in data being rendered on the page. I see blank div for good 5-10 seconds before .html() finally displays data:
On the main list page:
<div id="userPopup"></div>
Javascript that suppose to load Partial view with User details from an ActionMethod:
$.post('#Url.Action("Details","User")', { id: userId},
function (data) {
$("#userPopup").html(data);
});
Possibly there is a way to pre-load a partial view on the page and then just load my data into its Model without re-writing the entire PartialView ?
That would be the ideal scenario but I don't think there is a way to do it, is there ?
Thank you in advance ! Don't hesitate to ask questions if anything sounds confusing.
I dont think you should preload all the user details on the main page, what if you have 1000+ users and the visitor is not clikcking the details link ! I would do it in this way. Whenever user clicks on the link, make a call to an action method which returns the data.
So in your main view,
#foreach(var user in Model.Users)
{
#Html.ActionLink(user.Name, "Details", "User",
new { Id = user.ID, }, new { #class ="popupLink" })
}
<script type="text/javascript">
$(function(){
$(".popupLink").click(function (e) {
e.preventDefault();
var url = this.href;
var dialog = $("#dialog");
if ($("#dialog").length == 0) {
dialog = $('<div id="dialog" style="display:hidden"></div>').appendTo('body');
}
dialog.load(
url,
{}, // omit this param object to issue a GET request instead a POST request, otherwise you may provide post parameters within the object
function (responseText, textStatus, XMLHttpRequest) {
dialog.dialog({
close: function (event, ui) {
dialog.remove();
},
modal: true,
width: 460
});
}
);
});
});
</script>
In User controller, have an action method called "Details which accepts the Id as parameter and return the View of User details
public ActionResult Details(int id)
{
var usre=repositary.GetUser(id);
return View(user);
}
Have your HTML markup for details in the DetailsView.
This code use jQuery UI model dialog. So you need to include that.
I have a partial view containing an ajax form. This partial view is loaded onto my page via an ajax call. I can edit the fields and submit the form and everything works normally. However, if I reload the form N times, the form will submit N times when the save button is clicked.
here is the code for the partial view....
#model blah blah...
<script src="#Url.Content("~/Scripts/jquery-1.4.4.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.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="modalForm">
#using (Ajax.BeginForm("Edit", "Info", new{id = Model.UserId}, AjaxOptions{OnSuccess = "infoUpdate" }))
{
//FORM FIELDS GO HERE
<input type="submit" value="Save" />
}
</div>
What am I doing wrong that is causing this behavior?
Each time you reload the form, a trigger is placed for submitting the form. Thus you have n submitting, if you reload the form n times.
Try to load the form only once, if it's possible.
You can try to unbind the submit trigger, when you click on your submit button:
<input type="submit" value="Save" onClick="submitForm()" />
var submitForm = function() {
$("#formAddressShipping form").trigger('submit');
$("#formAddressShipping form").unbind('submit');
return false;
};
Just incase someone is still looking for this - the issue can also occur if you have jquery.unobstrusive js referenced multiple times. For me, I had it in layout and partial. The form got submitted 4 times, may be the field count. Removing the js from partial fixed it. Thanks to this thread ASP.NET AJAX.BeginForm sends multiple requests
Moving this jquery.unobtrusive-ajax.js outside partial solved the issue in my case.
I have faced the same issue and solved it as follows. I have a list. From that list, I call New, Update, Delete forms in UI Dialog. Success will close dialog and will return to list and update the UI. Error will show the validation message and dialog will remain the same. The cause is AjaxForm is posting back multiple times in each submit click.
Solution:
//Link click from the list -
$(document).ready(function () {
$("#lnkNewUser").live("click", function (e) {
e.preventDefault();
$('#dialog').empty();
$('#dialog').dialog({
modal: true,
resizable: false,
height: 600,
width: 800,
}).load(this.href, function () {
$('#dialog').dialog('open');
});
});
//Form submit -
$('#frmNewUser').live('submit', function (e) {
e.preventDefault();
$.ajax({
url: this.action,
type: this.method,
data: $('#frmNewUser').serialize(),
success: function (result)
{
debugger;
if (result == 'success') {
$('#dialog').dialog('close');
$('#dialog').empty();
document.location.assign('#Url.Action("Index", "MyList")');
}
else {
$('#dialog').html(result);
}
}
});
return false;
});
The scripts should be in List UI. Not in partial views (New, Update, Delete)
//Partial View -
#model User
#Scripts.Render("~/bundles/jqueryval")
#using (Html.BeginForm("Create", "Test1", FormMethod.Post, new { id = "frmNewUser", #class = "form-horizontal" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.UserID)
<p>#Html.ValidationMessage("errorMsg")</p>
...
}
//Do not use Ajax.BeginForm
//Controller -
[HttpPost]
public ActionResult Create(User user)
{
if (ModelState.IsValid)
{
try
{
user.CreatedDate = DateTime.Now;
user.CreatedBy = User.Identity.Name;
string result = new UserRepository().CreateUser(user);
if (result != "")
{
throw new Exception(result);
}
return Content("succes");
}
catch (Exception ex)
{
ModelState.AddModelError("errorMsg", ex.Message);
}
}
else
{
ModelState.AddModelError("errorMsg", "Validation errors");
}
return PartialView("_Create", user);
}
Hope someone get help from this. Thanks all for contributions.
Credit to http://forums.asp.net/t/1649162.aspx
Move the jQuery scripts inside the DIV. This seemed to fix the problem.
The tradeoff is that every post will do a get for each script.
My first post, faced the same issue
here is the solution which worked for me..
#using (Html.BeginForm("", "", FormMethod.Post, new { enctype = "multipart/form-data", id = "MyForm" }))
{
//form fields here..
//don't add a button of type 'submit', just plain 'button'
<button type="button" class="btn btn-warning" id="btnSave" onClick="submitForm()">Save</button>
<script type="text/javascript">
var submitForm = function () {
if ($("#"MyForm").valid())
{
//pass the data annotation validations...
//call the controller action passing the form data..
handleSaveEvent($("#MyForm").serialize());
}
return false;
};
<script>
}