This question is locked. New answers and comments are not allowed.
I am trying to figure out how to use an MVC Upload control in an Ajax-bound MVC Grid, which is using pop-up edit mode.
I've managed to get the upload control to display successfully in the pop-up window, when I am in edit mode. The uploaded files themselves are being successfully uploaded and saved to my hard drive file structure great via the upload control. Now, however, I am simply trying to save the name of the file that is uploaded to my database, but can't figure out how to associate the uploaded file name with the column in the grid, called ""ProductImagePath," so that it can be returned via ModelBinding to my controller action. The rest of the values in the row being edited are changed and persisted great. It's just the Upload field that I am having trouble with.
Does anyone know how to accomplish this, or to get around this problem?
Here is what I think is the relevant code:
Grid Controller Edit Action:
Grid and Upload onSuccess JavaScript:
Upload Editor Template:
Upload Controller Save Action:
I've managed to get the upload control to display successfully in the pop-up window, when I am in edit mode. The uploaded files themselves are being successfully uploaded and saved to my hard drive file structure great via the upload control. Now, however, I am simply trying to save the name of the file that is uploaded to my database, but can't figure out how to associate the uploaded file name with the column in the grid, called ""ProductImagePath," so that it can be returned via ModelBinding to my controller action. The rest of the values in the row being edited are changed and persisted great. It's just the Upload field that I am having trouble with.
Does anyone know how to accomplish this, or to get around this problem?
Here is what I think is the relevant code:
Grid Controller Edit Action:
//
// POST: /Product/Edit/5
[HttpPost]
[GridAction]
public ActionResult Edit(int id)
{
if (ModelState.IsValid)
{
try
{
var product = _productService.GetProductByID(id);
if (product != null)
{
TryUpdateModel(product); // "ProductImagePath" is always NULL
_productService.Save();
}
}
catch
{
throw new Exception("POST: /Product/Edit failed.");
// TODO: log error
}
}
return View(new GridModel<
ProductPresentationModel
>
{
Data = _mapper.MapAsList(_productService.GetProducts().ToList())
});
}
Grid and Upload onSuccess JavaScript:
@(Html.Telerik().Grid<
ProductPresentationModel
>()
.HtmlAttributes(new { style = "width: 100%;" })
// Give the Grid an HTML id attribute value
.Name("ProductGrid")
// Establish the promiry key, to be used for Insert, Update, and Delete commands
.DataKeys(dataKeys => dataKeys.Add(p => p.ProductID))
// Add an Insert command to the Grid Toolbar
.ToolBar(commands => commands.Insert().ButtonType(GridButtonType.Image))
// Using Ajax Data Binding to bind data to the grid
.DataBinding(dataBinding => dataBinding
// Ajax Binding
.Ajax()
.Select("_Index", "Product")
// Home.Insert inserts a new data record
.Insert("Create", "Product")
// Home.Update updates an existing data record
.Update("Edit", "Product")
// Home.Delete deletes an existing data record
.Delete("Delete", "Product")
)
.Columns(columns =>
{
columns.Bound(p => p.ProductImagePath).Width(120) //Using ClientTemplate to display the image, once it is uploaded and saved to database
.ClientTemplate(@"<
img
alt
=
'Product Category Image'
src='" + Url.Content("~/Content/Images/ProductImages/") + "<#= ProductImagePath #>' />");
columns.Bound(p => p.ProductName).Width(150);
columns.Bound(p => p.ProductDescription).Width(150);
columns.Bound(p => p.PricePerMonth).Width(100);
columns.Bound(p => p.ProductActive).Width(60)
.ClientTemplate("<
input
type
=
'checkbox'
disabled
=
'disabled'
name
=
'Active'
<#= ProductActive ?
checked
=
'checked'
: '' #> />");
columns.Bound(p => p.ProductCategoryID).Width(150);
columns.Command(commands =>
{
commands.Edit().ButtonType(GridButtonType.Image);
commands.Delete().ButtonType(GridButtonType.Image);
}).Width(70);
})
.Editable(editing => editing.Mode(GridEditMode.PopUp))
.ClientEvents(events => events.OnEdit("onEdit")) // Controls are swapped out for EditorTemplates
.Pageable()
.Scrollable()
.Sortable()
.Filterable()
)
@section HeadContent {
<
script
type
=
"text/javascript"
>
/*** ProductImagePath control ***/
var lastUploadedFile;
function onUploadSuccess(e) {
var fileName = e.files[0].name; // This gets the filename perfectly, but now what?
// e.dataItem['ProductImagePath'] = fileName; // Not valid with the upload control?
}
</
script
>
Upload Editor Template:
@(Html.Telerik().Upload()
.Name(ViewData["uploadTemplateName"].ToString())
.Multiple((bool)ViewData["multiFileUpload"])
.Async(async => async
.Save("Save", "Upload", new { folder = ViewData["uploadFolder"] })
.Remove("Remove", "Upload", new { folder = ViewData["uploadFolder"] })
.AutoUpload(true)
)
// JavaScript "onUploadSuccess" is on the grid page, not in this editor template page
.ClientEvents(e => e.OnUpload("onUpload").OnSuccess("onUploadSuccess"))
)
Upload Controller Save Action:
public ActionResult Save(IEnumerable<
HttpPostedFileBase
> files, string folder)
{
// The Name of the Upload component is "files"
foreach (var file in files)
{
// Some browsers send file names with full path. This needs to be stripped.
var fileName = Path.GetFileName(file.FileName);
if (fileName != null)
{
var physicalPath = Path.Combine(Server.MapPath("~/Content/Images/" + folder), fileName);
// Save the file
file.SaveAs(physicalPath);
// Save the filename in the database. I can't get a hold of the correct row item here,
// so this doesn't seem to work ...
//SaveUploadedFileInDatabase(fileName, folder);
}
}
// Return an empty string to signify success
return Content("");
}