Ajax.BeginForm PartialView not refreshing - c#

I am using asp.net mvc 4. I've searched many other similar questions here, but they didn't help.
I want to refresh my partial view - FileList after uploading file.
Instead I see now redirecting to page with updated file list, but i want to refresh this list in partial view. :(. Can anybody help? Another solutions to do similar features are acceptable :)
My partial view is in another (index) partial view.
Here is FileController:
private static int folderId = 0;
public ActionResult Index(int id)
{
folderId = id;
this.GetFiles();
return PartialView();
}
public PartialViewResult FileList()
{
this.GetFiles();
return PartialView("FileList");
}
[HttpPost]
[ValidateAntiForgeryToken]
public PartialViewResult UploadFiles(IEnumerable<HttpPostedFileBase> filesToUpload)
{
this.UploadFilesToBase(filesToUpload, 1);
this.GetFiles();
return PartialView("FileList");
}
and here is Index.cshtml
<script src="#Url.Content("~/Scripts/jquery-1.8.2.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/modernizr-2.6.2.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/main.js")" type="text/javascript"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
#using (Ajax.BeginForm("UploadFiles", "File", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "FilesListDiv", InsertionMode = InsertionMode.Replace }, new { enctype = "multipart/form-data" }))
{
<div class="btn-upload-file">
#Html.AntiForgeryToken()
<span class="btn"><span>Upload file</span></span>
<input type="file" class="file" name="filesToUpload" multiple onchange="javascript:this.form.submit();"><br>
</div>
}
<div id="FilesListDiv">
#*#Html.Action("FileList", "File")*#
#Html.Partial("~/Views/File/FileList.cshtml")
</div>
and here is my FileList.cshtml
#{
Layout = null;
ViewBag.Title = "Files";
}
#foreach (MyProj.Web.DataContracts.File file in ViewBag.Files)
{
file.Name
}

Your ajax form doesn't work, probably because you haven't included jquery.unobtrusive-ajax.js into the page and as a result, it works like a regular html form.
As soon as you add this file, you will be able to refresh the content via ajax, but filesToUpload will be null in the controller. The reason for that is impossibility of uploading files via ajax, because it does not support multipart/form-data enctype.
You can try to use some jQuery upload plugins ot HTML 5 File API.

Use this plugin http://malsup.com/jquery/form/ and this will submit form without the refresh. When you got the file uploaded on server then you can make a callback on the success of upload.
Get the list of file from server as render as html (through partialresult) and update them on client side browser.

Related

How to send json object to razor model then angularjs

This is the way I was sending my model to an angular controller scope.
c# Controller:
public class AreaMenuController : RootController
{
// GET: Menu
public PartialViewResult Index()
{
var mod = Modules.Instance.ModuleList.FirstOrDefault(m => m.Prefix.Equals(base.GetArea(), StringComparison.CurrentCultureIgnoreCase));
return PartialView("_AreaMenu", mod.ModuleMenus);
}
}
View cshtml:
#using Nuclei.Models
#model IEnumerable<Nuclei.Models.Menu>
<script type="text/javascript">
#{ var serializer = new System.Web.Script.Serialization.JavaScriptSerializer(); }
window.areaMenus = #Html.Raw(serializer.Serialize(Model));
</script>
<script type="text/javascript" src="#Url.Content("~/Scripts/AngularControllers/_AreaMenuController.js")"></script>
<div ng-controller="AreaMenuController as vm" ng-init="vm.initializeController()">
<div id="accordion" ng-class="accordian-menu" style="visibility: visible;">
<ul>
<li ng-repeat="menu in vm.areaMenus">
...
</li>
</ul>
</div>
</div>
Angular Js file:
var NucleiApp = angular.module('NucleiApp');
NucleiApp.controller('AreaMenuController', ['$scope', '$http', '$location', function ($scope, $http, $location) {
"use strict";
var vm = this;
vm.initializeController = function () {
vm.areaMenus = window.areaMenus;
}
}]);
Question 1: Is there a smoother way to send your c# model through to angular other than through global window object?
You can use an $http get from angular, however because this is processed client-side there is always a bit of lag before it gets displayed, because it needs to call the c# controller and get the data. So I'm reserving $http get for updates only.
The other other way I was thinking was to send the view a Json object straight off:
c# controller:
public class AreaMenusController : RootController
{
// GET: Menu
public PartialViewResult Index()
{
return PartialView("_AreaMenu", GetAreaMenus());
}
public JsonResult GetAreaMenus()
{
var mod = Modules.Instance.ModuleList.FirstOrDefault(m => m.Prefix.Equals(base.GetArea(), StringComparison.CurrentCultureIgnoreCase));
return Json(new { areaMenus = mod.ModuleMenus }, JsonRequestBehavior.AllowGet);
}
}
View cshtml:
#using System.Web.Mvc
#model JsonResult
<script type="text/javascript">
window.areaMenus = #Model;
</script>
Question 2: I'm not really sure how to initialize the #model at this point and send it through to the angular file and again, if there is a better option than javascripts global window object... open to suggestions!
We currently do this to bootstrap a set of data that is later updated by a call into a WebAPI.
The reason we do this is we have found cases where the data, when bootstrapped via an API call, was coming back too slowly, which gave a bad experience to our users.
In our razor view:
<html>
<head>
<script>
window.areaMenus = '#Html.Raw(Model.SerializedJsonString)';
</script>
</head>
</html>
Then when our angular app is Run(), we deserialize the data, and use it from there:
var app = angular.module('myApp', ["stuff"])
.run(["menuService", (menuService) => {
// deserialize the json string into my object
var areaMenus = angular.fromJson(window.areaMenus);
// do something with it
menuService.Load(areaMenus);
}]);
This'll get the data available to angular immediately without having to wait for a $http request to complete, which should address your issue.

Updating layout part dynamically

C# asp.net MVC project: I have my index page with a button in it, I want to press it and update the same page with some results.
Here's some code:
The View: (with a button that calls the getConfig method in the controller)
#{
ViewBag.Title = "Home Page";
}
<form method="get" action="/Home/GetConfig/" >
<input type="submit" value="Get Config WS" />
</form>
<p>
#ViewBag.totalRecords
</p>
The controller:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
return View();
}
public void getConfig()
{
string totalRecords = string.Empty;
wsConfig.config_pttClient client = new wsConfig.config_pttClient();
wsConfig.getConfigInput gci = new wsConfig.getConfigInput();
wsConfig.getConfigOutput gco = new wsConfig.getConfigOutput();
gco = client.getConfig(gci);
totalRecords = gco.result.totalRecords.ToString();
ViewBag.totalRecords = totalRecords;
}
I want to press the view's button and show the totalRecords on the same page.
How can I achieve this?
Edit: There might be other solutions, (if you don't mind updating your entire page) but this how I generally do it.
Ok, there are a couple of things that you need to change in order to make it work:
Create a new partial view that contains just the part that you would like to update (and wrap it an element with an id). In this example, let's call it 'Partial_TotalCount'.
This partial view will contain the following code:
<div id="updated">
<p>
#ViewBag.totalRecords
</p>
</div>
Now, change your original view so that it includes the partial view:
#{
ViewBag.Title = "Home Page";
}
<form method="get" action="/Home/GetConfig/" >
<input type="submit" value="Get Config WS" />
</form>
#Html.Partial("Partial_TotalCount", #Model)
Now, update your controller to work with an ajax request. This would make your controller looks like:
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
if (Request.IsAjaxRequest())
{
getconfig();
return PartialView("Partial_TotalCount");
}
return View();
}
Now, you need to be able to submit the page when you click the button. This can be done through javascript:
First your javascript function that will update the contents:
<script type="text/javascript">
function Refresh() {
$.ajax({
url: '/Home/Index',
type: "GET",
dataType: "html",
success: function(data) {
$("#updated").html(data);
},
error: function() { alert('Refreshing error.'); }
});
}
</script>
You just need to add an onclick on your button. And you can remove the form tags from around your form aswell.
Edit: As requested by the questioner, I provide a bit of explanation on the Javascript function itself:
$.ajax means that we are doing an Ajax request. It means that we are doing some asynchronous requests with the server.
Then a couple of parameters are passed:
Url: The url that should be executed. In your example, the code behind the url "Home/GetConfig" get's executed.
Type: The type of submit that you want to do (POST, GET, ...)
dataType: The type we are expecting back from the server.
Success: The piece of javascript that needs to execute when complete. (In this case, update the DIV element with the id "WithCss" with the contents that are received with the url "Home/Getconfig".
Error: A function that is executed when the request failed for some reason.
There are a lot of other parameters you can pass (for example if you need to pass an id, and others.
For more explanation, please look at the original documentation.
Also, consider marking this answer as accepted.
I hope it works.
Try This:
Replace your input button code with the following code :
<input type="submit" id="btnSave" name="BtnSave" value="Get Config WS" />
Then in controller change the whole code for this code:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
return View();
}
public ActionResult getConfig()
{
return View();
}
[HttpPost]
public ActionResult getConfig(FormCollection Form)
{
if(Form["BtnSave"]!=null)
{
string totalRecords = string.Empty;
wsConfig.config_pttClient client = new wsConfig.config_pttClient();
wsConfig.getConfigInput gci = new wsConfig.getConfigInput();
wsConfig.getConfigOutput gco = new wsConfig.getConfigOutput();
gco = client.getConfig(gci);
totalRecords = gco.result.totalRecords.ToString();
ViewBag.totalRecords = totalRecords;
}
return View();
}
Hopefully it works...!

Simple Ajax call posting back entire page

I want to call and return data from a controller action asynchronously using Ajax.
In my example below, when clicking on the ActionLink it posts back to a new page with just "Hello!". How can I get this to just update the div?
Controller:
public class HelloAsyncController : Controller
{
public ActionResult Index()
{
return View();
}
public string Hello()
{
return "Hello!";
}
}
View:
#Ajax.ActionLink("Say Hello", "Hello", "HelloAsync",
new AjaxOptions()
{
UpdateTargetId = "HelloDiv"
})
<div id="HelloDiv"></div>
Includes in _Layout.cshtml:
<script src="~/Scripts/modernizr-2.6.2.js"></script>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
I am using MVC 5.
Have you tried using
#Ajax.ActionLink(
"Say Hello",
"Hello",
"HelloAsync",
new AjaxOptions
{
UpdateTargetId="HelloDiv",
HttpMethod = "Get",
InsertionMode = InsertionMode.Replace
})
I thing that issue might be
The contents of the UpdateTargetID must be in a partial view and that
partial view needs to be called from the Controller Action. . You need to use a
partial view.
Also check
Check if files MicrosoftAjax.js and MicrosoftMvcAjax.js are really
present in ../../Scripts folder.

redirect to different view after loading partial view in Main view

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.

ASP.NET MVC Form loaded via ajax submits multiple times

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>
}

Categories