File upload partial view in a popup asp.net mvc - asp.net-mvc

I have a file upload control in a partial view(_Managefiles),
#model Framework.Views.FileUpload
...
#{
var grid = new WebGrid(Model.UploadFileList, ...);}
<div id="gridContent">
#grid.GetHtml(tableStyle: "webGrid",...)
#using (Html.BeginForm("UploadFiles", "PartialVw", FormMethod.Post,
new { enctype = "multipart/form-data", Id = "frmManageFiles", UpdateTargetId = "Grd" }))
{
..
<input id="uploadFile" name="uploadFile" type="file" />
<input type="button" id="btnSubmit" value="Upload File" onclick="javascript:StoreFormData()" />
}
this partial view is within a popup in a view(Expense.cshtml),
#model Framework.Views.Expenses
...
<div id="FileUploadModal" title="Upload File" style="display: none; overflow: auto;">
#Html.Partial("../Shared/_ManageFiles", Framework.Views.FileUpload.Current)
</div>
on click of web grid row item link in the view, upload popup is displayed and file is uploaded on upload click button below is the controller event
[HttpPost]
public ActionResult UploadFiles(FormCollection form)
{
HttpPostedFileBase File = Request.Files["uploadFile"];
...
File.SaveAs(FileUpload.Current.UploadFolderPath);
return View("../Expenses/Expenses", Expenses.Current);
}
After each upload the popup disappears, it should persist after download. I'm thinking of using ViewData for this, is there any workaround for popup to persist?
I dont want to use any upload controls like uploadify, blueimp. I want to keep it simple.

Instead of a partial view i created a normal view for the upload control and on click of web grid row item link, a new window is opened and in this way only the newly opened window will be refreshed on upload
function UploadExpenseFile(e) {
var l = (screen.width - 500) / 2;
var t = (screen.height - 500) / 2;
var f = window.open("#Url.Action("ManageFiles", "Tools", new { itemid = "_id" })".replace("_id",e), "_blank", 'resizable=0, height=500px,width=500px,top=' + t + ',left=' + l + 'w');
}

Related

DNN MVC Module not posting file back

I am building a small DNN MVC module whereby I need a user to upload file which will be processed server side.
When the form is posted back, the view model is posted back fine, but the file never is. Request.Files is always 0.
I even simplified it so all I had on the module was a simple file input and submit button but that failed as well.
I would hate to have to revert back to .ascx controls to get this to work.
I am testing this as an unregistered user, therefore there is no authentication checking in the controller.
See code below:
View
#inherits DotNetNuke.Web.Mvc.Framework.DnnWebViewPage<NM.Modules.FlexEventsCreate.Models.FlexEventViewModel>
#using DotNetNuke.Web.Mvc.Helpers
<input type="file" id="fileUp"/>
<input type="submit" id="btnSubmit" />
Controller
[DnnHandleError]
public class ItemController : DnnController
{
[HttpPost]
public ActionResult ShowForm(FlexEventViewModel flexEvent)
{
if (ModelState.IsValid)
{
var file = Request.Files;
if (file.Count != 0)
{
//do something
}
//return RedirectToDefaultRoute();
}
return View(flexEvent);
}
}
The rendered DNN HTML looks like this (I have simplified it)
<form method="post" action="/Test" id="Form" enctype="multipart/form-data">
<!-- Begin Content areas -->
<div>
<div class="row">
<div class="medium-9 columns">
<div id="dnn_LeftPane">
<div class="DnnModule DnnModule-DnnModule-747">
<a name="747"></a>
<div class="DnnF_Title_h1 SpacingBottom">
<h1><span id="dnn_ctr747_dnnTITLE_titleLabel" class="TitleH1"></span>
</h1>
<div id="dnn_ctr747_ContentPane">
<!-- Start_Module_747 -->
<div id="dnn_ctr747_ModuleContent">
<div id="dnn_ctr747_ShowForm_Prog" class="RadAjax RadAjax_Default" style="display:none;">
<div class="raDiv">
</div>
<div class="raColor raTransp">
</div>
</div>
<div class="RadAjaxPanel" id="dnn_ctr747_dnn_ctr747_ShowForm_UPPanel">
<div id="dnn_ctr747_ShowForm_UP">
<!-- 2013.2.717.40 -->
<div id="mvcContainer-747">
<input type="file" id="fileUp">
<input type="submit" id="btnSubmit">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
I did do an upload in an MVC module using the dropzone jquery component - which may help you. See my sample Restaurant Menu project on github.
First, include the dropzone script and css:
#using DotNetNuke.Web.Client.ClientResourceManagement
#{
ClientResourceManager.RegisterStyleSheet(Dnn.DnnPage, "~/DesktopModules/MVC/DotNetNuclear/RestaurantMenu/Resources/dropzone/css/dropzone.css");
ClientResourceManager.RegisterScript(Dnn.DnnPage, "~/DesktopModules/MVC/DotNetNuclear/RestaurantMenu/Resources/dropzone/js/dropzone.min.js", 100);
}
Then place a container div for the upload component:
<div id="dZUpload" class="uploadform dropzone no-margin dz-clickable">
<div class="dz-default dz-message"></div>
</div>
Initialize the component and tell it what type and how many files can be uploaded:
$("#dZUpload").dropzone({
acceptedFiles: "image/jpeg,image/png,image/gif",
url: '#Url.Action("Upload", "Menu")',
maxFiles: 1, // Number of files at a time
maxFilesize: 1, //in MB
addRemoveLinks: true,
maxfilesexceeded: function (file) {
alert('You have uploaded more than 1 Image. Only the first file will be uploaded!');
},
success: function (response) {
}
});
Change the acceptedFiles to the mimetypes you are restricting ("application/pdf", etc). Change the maxFiles to limit how many files they can upload at a time.
Write an MVC controller action to respond to the Dropzone file upload url. You can see it expects an action method "Upload" on the controller "Menu" (MenuController.Upload):
public JsonResult Upload()
{
string imageUrl = string.Empty;
string imgPath = Server.MapPath("~/Portals/0/Restaurant/");
if (!Directory.Exists(imgPath))
{
Directory.CreateDirectory(imgPath);
}
foreach (string s in Request.Files)
{
var file = Request.Files[s];
if (file.ContentLength > 0)
{
string fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(imgPath, fileName);
file.SaveAs(path);
imageUrl = string.Format("/Portals/0/Restaurant/{0}", fileName);
}
}
return Json(new { img = imageUrl, thumb = imageUrl });
}

asp.net mvc ajax.beginform being sent as html.beginform

I have a partial view from which I would like to display a modal dialog with updated data. User clicking the div would trigger both the display of the modal and the ajax call for the content of the modal to be updated.
<div class="nMmenuItem" >
#using (Ajax.BeginForm("editItem","nMrestaurant",new { id = Model.ID },
new AjaxOptions
{
HttpMethod = "get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "myModalDocument"
}, new { id = "ajaxEditItem" }))
{
<div data-toggle="modal" data-target="#myModal"
onclick="$('form#ajaxEditItem').submit();">
<div class="text-center">
#Model.name
</div>
</div>
}
</div>
I have a placeholder for the modal inside the parent view:
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document" id="myModalDocument">
#Html.Partial("_editItem", new nMvMmenuItem())
</div>
</div>
But while the controller action is expecting an AjaxResquest, the controller is evaluating Request.IsAjaxRequest() as false.
public async Task<ActionResult> editItem(int? id)
{
if (Request.IsAjaxRequest())
{
return PartialView("_editItem", await db.nMmenuItems.FindAsync(id));
}
return View();
}
Which refreshes the whole view and prevents the modal from working.
I am bundling the following scripts in the _Layout.cshtml page:
"~/Scripts/jquery-{version}.js",
"~/Scripts/jquery-ui-{version}.js",
"~/Scripts/jquery.unobstrusive*",
"~/Scripts/jquery.validate",
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js"
Thanks for your help!
Check that you've got the unobtrusive ajax client scripts installed - your bundle pattern looks like it will pick them up if they are there, but I don't believe they are installed in the default project:
Install-Package Microsoft.jQuery.Unobtrusive.Ajax
While the Ajax.BeginForm is included in the standard MVC project, the client scripts are not and these are what is responsible for loading the content without refreshing the whole page.
I found that attaching submit() to the form's onclick event would not perform an ajax request.
My solution is thus to remove Ajax.SubmitForm and instead deal with the click event in my js:
The updated view looks like this:
<div class="nMmenuItem">
<form method="get" action="#Url.Action("editItem","nMrestaurant",new { id = Model.ID })"
data-nM-ajax="true" data-nM-target="#myModalContent">
<div>
<div class="text-center">
#Model.name
</div>
</div>
</form>
In the js I will bind the form submission to the click event of the parent div:
$('.nMmenuItem').click(ajaxFormSubmit);
And the function that handles the form submission and opens the resulting modal dialog:
var ajaxFormSubmit = function () {
var $form = $(this).children('form:first');
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize()
};
$.ajax(options).done(function (data) {
var $target = $($form.attr("data-nM-target"));
$target.replaceWith(data);
$("#myModal").modal(dialogOpts);
});
return false;
};

How to have a button in a form post to a different action

Let's say I have a form listing some items:
#using (Html.BeginForm("Index", "SagePayServerInframe", FormMethod.Post))
{
if (Model.Tokens.Any())
{
<h2>Select an existing card</h2>
for (int i = 0; i < Model.Tokens.Count; i++)
{
<div class="sagepay-wrapper">
<div><span>Card Type:</span> #Model.Tokens[i].CardType</div>
<div><span>Last 4 Digits:</span> #Model.Tokens[i].Last4Digits</div>
<div><span>Expiry Date:</span> #Model.Tokens[i].ExpiryDate</div>
<div>
#Html.RadioButtonFor(m => m.SelectedTokenId, Model.Tokens[i].Id, new { #id = "SelectedTokenId" + i })
<label for="SelectedTokenId#(i)">SELECT</label>
</div>
</div>
}
}
<input type="submit" value="Continue" class="uppercase"/>
}
Now, I want to put a Delete button against each entry as well. I can't seem to have another form within the existing form (it wouldn't show on the page when I tried a new Html.BeginForm).
How would I achieve this? Ideally, I'd like to be able to post back to a DeleteToken action. I get the feeling I'm missing something simple but not sure what it is.
Use a Jquery hack like (Code not tested, may have syntax error, sorry for that)
When button1 is pressed, access the form object and reset the form url.
$("#button1").click(form(){
$(this).form.URL = "../Controller1/Action1";
});
AND when button2 is clicked
$("#button2").click(form(){
$(this).form.URL = "../Controller2/Action2";
});

Kendo Window - LoadDataFrom finds argument value inline?

I have a kendo window which I want to populate depending on a selection made in a dropdown. I've tried refreshing the window upon open, but I can't figure out how to make that work. Changing gears, I'm wondering if I can instead send a variable parameter to the controller within window declaration itself, and then do a simple window.refresh (instead of coding the refresh to hit a specific controller, which isn't working).
I mean something like this:
#(Html.Kendo().Window()
.Name("EditWindow")
.Title("Edit Contact")
.LoadContentFrom("_ContactEdit", "Contacts", new { selectedContact = $("#ContactId").data("kendoComboBox").value() })
.Content("Loading...")
.Visible(false)
.Draggable()
.Resizable()
.Width(400)
.Modal(true)
.Actions(actions => actions.Pin().Minimize().Maximize().Close())
)
Or this:
#(Html.Kendo().Window()
.Name("EditWindow")
.Title("Edit Contact")
.LoadContentFrom("_ContactEdit", "Contacts", new { selectedContact = getContact() })
.Content("Loading...")
.Visible(false)
.Draggable()
.Resizable()
.Width(400)
.Modal(true)
.Actions(actions => actions.Pin().Minimize().Maximize().Close())
)
Obviously neither of these work, but I'm wondering if there's another way to fill in this field?
Thank you!
edit: Adding relevant code from controller and window/partial view. My controller is now being hit, but my window is not pulling the correct data. Any ideas?
Window:
#model [taking out company info].Contact
#using Kendo.Mvc.Extensions
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset id="infoForm">Hello, world.
#Html.HiddenFor(model => model.ContactId, new { id = "EditWindowId" })
<br />
<label id ="ContactNameID" style="width: 130px;">Contact Name</label>
<span>
#Html.TextBoxFor(model => model.FullName, new { type = "text", id = "EditWindowName", #class = "k-textbox form-control", style = "width: 200px; cursor:default" })
</span><br />
</fieldset>
}
Controller:
[HttpGet]
public ActionResult _ContactEdit(int selectedContact)
{
var entities = from r in dbContext.Contacts
where r.ContactId == selectedContact
select r;
if (entities.Any())
{ return PartialView(entities.First()); }
else
{ return HttpNotFound("Contact does not exist."); }
}
You can leverage the change event of your dropdown list to grab the selected value. Once you have the selected value you can programmatically refresh the window with the appropriate action on your controller. For example, the code below defines a Kendo DropDownList with a subscription to the change event. In the change, the value is used to build a dynamic url, and the kendo window is refreshed with that url:
<%= Html.Kendo().DropDownList()
.Name("dropdownlist")
...
.Events(e =>
{
e.Change("onChange")
})
%>
<script type='text/javascript'>
function onChange(){
var value = this.value(),
window = $("#EditWindow").data("kendoWindow");
window.refresh({
url: "/Contact/_ContactEdit?selectedContact=" + value
});
}
</script>

Problem binding action parameters using FCKeditor, AJAX and ASP.NET MVC

I have a simple ASP.Net MVC View which contains an FCKeditor text box (created using FCKeditor's Javascript ReplaceTextArea() function). These are included within an Ajax.BeginForm helper:
<% using (Ajax.BeginForm("AddText", "Letters",
new AjaxOptions() { UpdateTargetId = "addTextResult" }))
{%>
<div>
<input type="submit" value="Save" />
</div>
<div>
<%=Html.TextArea("testBox", "Content", new { #name = "testBox" })%>
<script type=""text/javascript"">
window.onload = function()
{
var oFCKeditor = new FCKeditor('testBox') ;
var sBasePath = '<%= Url.Content("~/Content/FCKeditor/") %>';
oFCKeditor.BasePath = sBasePath;
oFCKeditor.ToolbarSet = "Basic";
oFCKeditor.Height = 400;
oFCKeditor.ReplaceTextarea() ;
}
</script>
<div id="addTextResult">
</div>
<%} %>
The controller action hanlding this is:
[ValidateInput(false)]
public ActionResult AddText(string testBox)
{
return Content(testBox);
}
Upon initial submission of the Ajax Form the testBox string in the AddText action is always "Content", whatever the contents of the FCKeditor have been changed to. If the Ajax form is submitted again a second time (without further changes) the testBox paramater correctly contains the actual contents of the FCKeditor.
If I use a Html.TextArea without replacing with FCKeditor it works correctly, and if I use a standard Post form submit inplace of AJAX all works as expected.
Am I doing something wrong?
If not is there a suitable/straight-forward workaround for this problem?
The problem is unrelated to MVC but caused by using FCKeditor in conjunction with AJAX. To fix in the code above I added the following to the submit button's onclick event:
<input type="submit" value="Save" onclick="FCKeditorAPI.GetInstance('TestBox').UpdateLinkedField();" />
For more information see here.

Resources