I have an action who displays a PDF in a new browser tab.
public ActionResult Print()
{
var cd = new ContentDisposition
{
FileName ="something.pdf",
Inline = true
};
Response.AppendHeader("Content-Disposition", cd.ToString());
return File(reportResponse.Data.Document, MediaTypeNames.Application.Pdf);
}
The filename is working fine. When I download the file it has the name I want "something.pdf".
The problem is when google chrome opens the PDF in a new browser tab, it displays the controller action name (Print) as the title of the PDF. That's what I'm trying to change. I attached a picture for clarification.
View code:
Url.Action("Print", "Controller", new { area = "Area" }), new { #target = "_blank" }
To the action method pass parameter of the file name and make sure parameter name is 'id'.
View code:
Url.Action("Print", "Controller", new { id = "filename", area = "Area" }), new { #target = "_blank" }
Adding to kodandarami's answer,
When you're passing a PDF file back from ASP.NET MVC, the page title is set to the last url part of the route config used to get to your controller.
Knowing this, you can dynamically name the title by setting up a parameter as part of the route config for your controller eg:
routes.MapRoute(
"Print",
"print/{pdfName}",
new { controller = "Print", action = "Index", pdfName = UrlParameter.Optional }
);
Then MVC will use this value instead as it considers it a separate page.
Use it in the url as
"/print/this-is-my-pdf-title" not '/print?pdfName=this-is-my-pdf-title".
As a querystring parameter, MVC will just fall back to calling the PDF 'print'.
Note:
As mentioned in this related question,
IIS has more strict rules about forbidden characters when the text is before the query string '?' character. You are not allowed <,>,*,%,&,:,\ (See MS Reference)
Any of these characters, even when encoded will give you a 'Path is potentially dangerous' 400 error.
Make sure to remove/replace these forbidden characters.
.
I solved this problem by using a iframe.
Create an action which fills the title and pdf url.
public ActionResult ArticleSpecification(int ArticleID)
{
using (var context = new myEntities())
{
Article article = context.Article.FirstOrDefault(a => a.ArticleID == ArticleID);
ViewData["Title"] = article.Code + " - " + article.Description;
ViewData["PdfSource"] = "ArticleSpecificationPdf?ArticleID=" + article.ArticleID;
return View("~/Views/Specification/pdfview.cshtml");
}
}
pdfview.cshtml: with a iframe to view the pdf and title.
#{
Layout = "";
}
<!DOCTYPE html>
<html>
<head>
<title>#ViewData["Title"]</title>
<style>
html, body, iframe {
height: 100%;
width: 100%;
margin: 0;
border: 0;
}
body {
overflow-y: hidden;
}
</style>
</head>
<body>
<iframe src="#ViewData["PdfSource"]"></iframe>
</body>
</html>
The action to return the pdf content.
public FileResult ArticleSpecificationPdf(int ArticleID)
{
using (var context = new myEntities())
{
PdfFile file = null;
Article article = context.Article.FirstOrDefault(a => a.ArticleID == ArticleID);
if (article != null && article.SpecificationPdfID != null)
file = context.PdfFile.FirstOrDefault(a => a.PdfFileID == article.SpecificationPdfID);
return new FilePathResult(file.path, "application/pdf");
}
}
Try the following return statement:
return File(reportResponse.Data.Document, MediaTypeNames.Application.Pdf, "something.pdf");
Related
When i use Html.ActionLink without parameter values the destination view's bootstrap loads normally but when I try to pass pa parameter the destination view's bootstrap does not load it only displays simple html without bootstrap. I'm using sb-admin-2 btw.
I have already tried all the method overloading of #Html.ActionLink but nothing works.
When you click this link the page load and data are passed but the bootstrap fails to load.
#Html.Actionlink with parameter code:
#Html.ActionLink("Update", "AddOrEdit", "Receiving", new { #id = item.ReceivingDocumentNo }, new { #class = "btn btn-xs btn-info" })
#Html.ActionLink without parameter code:
#Html.ActionLink("Create New", "AddOrEdit", "Receiving", new { #class = "btn btn-success" })
Please refer to this link to the image results of the views.
https://imgur.com/a/6Jg09tV
Controller Code:
[HttpGet]
public ActionResult AddOrEdit(string id = "")
{
List<DTS.Models.DocumentType> documentTypeList = new List<DocumentType>();
List<Section> sectionList = new List<Section>();
documentTypeList = DapperORM.ReturnList<DocumentType>("ViewAllDocumentTypesReceiving").ToList<DocumentType>();
sectionList = DapperORM.ReturnList<Section>("ViewAllSections").ToList<Section>();
ViewData["DocumentTypeList"] = documentTypeList;
ViewData["SectionList"] = sectionList;
Receiving res = new Receiving();
if (id == "")
{
res.ReceivingDocumentNo = DapperORM.ReturnList<string>("GenerateReceivingTrackingNo", null).FirstOrDefault<string>();
res.ReceivingSections = sectionList;
}
else
{
DynamicParameters param = new DynamicParameters();
param.Add("#ReceivingDocumentNo", id);
res = DapperORM.ReturnList<Receiving>("GetReceivingDetailsForUpdateByReceivingDocumentNo", param).FirstOrDefault<Receiving>();
res.ReceivingSections = DapperORM.ReturnList<Section>("GetReceivingListForUpdateByDocumentNo", param).ToList<Section>();
}
return View(res);
}
The result should be the same with the bootstrap layout rendering normally.
Are your _Layout.cshtml being applied at all? I do believe the problem is not in the submitted code but rather in the view code, and that the information provided is not enough to get a specific answer. -regards.
Hi i am totally confused with file uploading. First of all any one explain me what is the difference between normal file uplaod and create thumbnail for image and save that path in db.
I checked the path of both normal and thumbnail. Moreover same only but i donno what is the differene between these two types of uplaod?.Can any one explain me these difference?
I tried both types. I paste that code here and any one tell me the difference between two types.
1) Normal Uplaod using AJAX
View
#{
ViewBag.Title = "FileUpload";
}
<head>
<title></title>
</head>
<body>
<input type="file" id="FileUpload1" />
<input type="button" id="btnUpload" value="Upload Files" />
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"> </script>
<script>
$(document).ready(function(){
$('#btnUpload').click(function () {
// Checking whether FormData is available in browser
if (window.FormData !== undefined) {
var fileUpload = $("#FileUpload1").get(0);
var files = fileUpload.files;
// Create FormData object
var fileData = new FormData();
// Looping over all files and add it to FormData object
for (var i = 0; i < files.length; i++) {
fileData.append(files[i].name, files[i]);
}
// Adding one more key to FormData object
fileData.append('username', 'Manas');
$.ajax({
url: '/ImageUplaod/UploadFiles',
type: "POST",
contentType: false, // Not to set any content header
processData: false, // Not to process data
data: fileData,
success: function (result) {
alert(result);
},
error: function (err) {
alert(err.statusText);
}
});
} else {
alert("FormData is not supported.");
}
});
});
</script>
Controller
public ActionResult FileUpload()
{
return View();
}
[HttpPost]
public ActionResult UploadFiles()
{
// Checking no of files injected in Request object
if (Request.Files.Count > 0)
{
try
{
// Get all files from Request object
HttpFileCollectionBase files = Request.Files;
for (int i = 0; i < files.Count; i++)
{
//string path = AppDomain.CurrentDomain.BaseDirectory + "Uploads/";
//string filename = Path.GetFileName(Request.Files[i].FileName);
HttpPostedFileBase file = files[i];
string fname;
// Checking for Internet Explorer
if (Request.Browser.Browser.ToUpper() == "IE" || Request.Browser.Browser.ToUpper() == "INTERNETEXPLORER")
{
string[] testfiles = file.FileName.Split(new char[] { '\\' });
fname = testfiles[testfiles.Length - 1];
}
else
{
fname = file.FileName;
}
// Get the complete folder path and store the file inside it.
fname = Path.Combine(Server.MapPath("~/Uploads/"), fname);
file.SaveAs(fname);
var imageupload = new imageupload();
imageupload.ImageUplaod = fname;
db.imageuploads.Add(imageupload);
db.SaveChanges();
}
// Returns message that successfully uploaded
return Json("File Uploaded Successfully!");
}
catch (Exception ex)
{
return Json("Error occurred. Error details: " + ex.Message);
}
}
else
{
return Json("No files selected.");
}
}
2) Craete Thumbnails for image using MVC and save that path in db
Model
public class ImageUploadModels
{
[Key]
public int ImgageID
{
get;
set;
}
[Required]
public string ImagePath
{
get;
set;
}
}
Controller
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult ImageUploadThumnail(ImageUploadModels image, HttpPostedFileBase file)
{
try {
if (file != null)
{
var fileName = Path.GetFileName(file.FileName);
var thumbName = fileName.Split('.').ElementAt(0) + "_thumb." + fileName.Split('.').ElementAt(1);
fileName = Path.Combine(Server.MapPath("/Images"), fileName);
thumbName = Path.Combine(Server.MapPath("/Images"), thumbName);
image.ImagePath = fileName; //to store into database, if we use DbContext
file.SaveAs(fileName);
Image img = Image.FromFile(fileName);
int imgHeight = 100;
int imgWidth = 100;
if (img.Width < img.Height)
{
//portrait image
imgHeight = 100;
var imgRatio = (float) imgHeight / (float) img.Height;
imgWidth = Convert.ToInt32(img.Height * imgRatio);
}
else if(img.Height < img.Width)
{
//landscape image
imgWidth = 100;
var imgRatio = (float) imgWidth / (float) img.Width;
imgHeight = Convert.ToInt32(img.Height * imgRatio);
}
Image thumb = img.GetThumbnailImage(imgWidth, imgHeight, () => false, IntPtr.Zero);
thumb.Save(thumbName);
var imageupload = new imageupload();
imageupload.ImageUplaod = thumbName;
db.imageuploads.Add(imageupload);
db.SaveChanges();
}
return View();
} catch (Exception ex)
{
ViewBag.Message = ex.Message.ToString();
return View();
}
}
View
#model ImageUpload.Models.ImageUploadModels
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("ImageUploadThumnail", "ImageUplaod", null, FormMethod.Post, new
{
enctype = "multipart/form-data"
})) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true);
<fieldset> <legend> Image </legend>
<div class = "editor-label" >
#Html.LabelFor(model => model.ImagePath)
</div>
<div class = "editor-field">
<input id = "ImagePath" title = "Upload an image" type = "file" name = "file"/>
</div>
<p> <input type = "submit" value = "Upload"/>
</p>
</fieldset>
}
Now i posted two typesof upload what i tried . i want to know the difference between these two types and i want to know which is better to upload image in server after deploying the project. And also any one tell me how to create thumbnails for image using ajax . Here in above mention method i didn't use ajax for thumbnails . But i need to uplaod and save the path of the thumnails image using ajax. I tried my level best to explain my issue.Any one understand my issue and give me solution for this problem
Advance Thanks..
First of all any one explain me what is the difference between normal file uplaod and create thumbnail for image and save that path in db.
What is a thumbnail image?
It is just an image that looks like another image but with a smaller file size.
Advantages of using thumbnails on web
This can play a major role in web applications. When you visit a web page, like this one, if there are images on the page they need to be brought to your computer so your browser can show them to you. In other words, they need to be downloaded to your computer. Web sites developed with that in mind, will just include a low quality, small size image of the actual image and send that when you view the page. Then when you click on the image, for example, if you want to look at the image more closely, then the browser will make another request to the server and get the high quality image.
This technique makes the initial loading (downloading to be exact) fast so the user is not setting there waiting for all the big images if all they want to do is read something.
I am not sure if you are using uploading incorrectly but uploading is the opposite of downloading. When you visit a page, you are essentially downloading the page (unless you have already visited the page and the browser has cached it.) Therefore, uploading is you sending something to the server and I am not sure how sending something to the server will benefit from thumbnails.
I think what you may be speaking of is having a thumbnail image and the path to the high quality image of the thumbnail is stored in the db with thumbnail data. You send the thumbnail when someone requests it, then if they want the higher quality image, you get the path from the database and serve the high quality image.
This technique is highly in use by commerce sites. For example, when you are browsing Amazon, eBay, car dealerships the little images are low quality but enough to give you a good idea of what the product is. Once you click it, then the better quality images are retrieved.
Advantages of using thumbnails in other type of applications
Web is not the only place this can be used. I worked on an iPad application and we used the same technique. However, instead of clicking the image we were waiting to see if the user will zoom (pinch and zoom) on the image. As soon as the user zoomed in, we would get a higher quality image. If they zoomed in again, we would get even a higher quality image. We had 4 different levels of quality for each image.
In conclusion there are two advantages to using thumbnails:
Faster load (performance)
Bandwidth-smaller size images (especially important to mobile users because data will cost them $$$)
Here is a page with thumbnails. And here are the better quality images of one of the thumbnails.
HTML:
<a href="mysite.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
Uploads get a unique file name while there real name is kept in database. I want to realize a simple file download. But the code above redirects to / because of:
$routeProvider.otherwise({
redirectTo: '/',
controller: MainController
});
I tried with
$scope.download = function(resource){
window.open(resource);
}
but this just opens the file in a new window.
Any ideas how to enable a real download for any file type?
https://docs.angularjs.org/guide/$location#html-link-rewriting
In cases like the following, links are not rewritten; instead, the
browser will perform a full page reload to the original link.
Links that contain target element Example:
link
Absolute links that go to a different domain Example:
link
Links starting with '/' that lead to a different base path when base is defined Example:
link
So in your case, you should add a target attribute like so...
<a target="_self" href="example.com/uploads/asd4a4d5a.pdf" download="foo.pdf">
We also had to develop a solution which would even work with APIs requiring authentication (see this article)
Using AngularJS in a nutshell here is how we did it:
Step 1: Create a dedicated directive
// jQuery needed, uses Bootstrap classes, adjust the path of templateUrl
app.directive('pdfDownload', function() {
return {
restrict: 'E',
templateUrl: '/path/to/pdfDownload.tpl.html',
scope: true,
link: function(scope, element, attr) {
var anchor = element.children()[0];
// When the download starts, disable the link
scope.$on('download-start', function() {
$(anchor).attr('disabled', 'disabled');
});
// When the download finishes, attach the data to the link. Enable the link and change its appearance.
scope.$on('downloaded', function(event, data) {
$(anchor).attr({
href: 'data:application/pdf;base64,' + data,
download: attr.filename
})
.removeAttr('disabled')
.text('Save')
.removeClass('btn-primary')
.addClass('btn-success');
// Also overwrite the download pdf function to do nothing.
scope.downloadPdf = function() {
};
});
},
controller: ['$scope', '$attrs', '$http', function($scope, $attrs, $http) {
$scope.downloadPdf = function() {
$scope.$emit('download-start');
$http.get($attrs.url).then(function(response) {
$scope.$emit('downloaded', response.data);
});
};
}]
});
Step 2: Create a template
Download
Step 3: Use it
<pdf-download url="/some/path/to/a.pdf" filename="my-awesome-pdf"></pdf-download>
This will render a blue button. When clicked, a PDF will be downloaded (Caution: the backend has to deliver the PDF in Base64 encoding!) and put into the href. The button turns green and switches the text to Save. The user can click again and will be presented with a standard download file dialog for the file my-awesome.pdf.
Our example uses PDF files, but apparently you could provide any binary format given it's properly encoded.
If you need a directive more advanced, I recomend the solution that I implemnted, correctly tested on Internet Explorer 11, Chrome and FireFox.
I hope it, will be helpfull.
HTML :
<i class="fa fa-file-excel-o"></i>
DIRECTIVE :
directive('fileDownload',function(){
return{
restrict:'A',
scope:{
fileDownload:'=',
fileName:'=',
},
link:function(scope,elem,atrs){
scope.$watch('fileDownload',function(newValue, oldValue){
if(newValue!=undefined && newValue!=null){
console.debug('Downloading a new file');
var isFirefox = typeof InstallTrigger !== 'undefined';
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
var isIE = /*#cc_on!#*/false || !!document.documentMode;
var isEdge = !isIE && !!window.StyleMedia;
var isChrome = !!window.chrome && !!window.chrome.webstore;
var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
var isBlink = (isChrome || isOpera) && !!window.CSS;
if(isFirefox || isIE || isChrome){
if(isChrome){
console.log('Manage Google Chrome download');
var url = window.URL || window.webkitURL;
var fileURL = url.createObjectURL(scope.fileDownload);
var downloadLink = angular.element('<a></a>');//create a new <a> tag element
downloadLink.attr('href',fileURL);
downloadLink.attr('download',scope.fileName);
downloadLink.attr('target','_self');
downloadLink[0].click();//call click function
url.revokeObjectURL(fileURL);//revoke the object from URL
}
if(isIE){
console.log('Manage IE download>10');
window.navigator.msSaveOrOpenBlob(scope.fileDownload,scope.fileName);
}
if(isFirefox){
console.log('Manage Mozilla Firefox download');
var url = window.URL || window.webkitURL;
var fileURL = url.createObjectURL(scope.fileDownload);
var a=elem[0];//recover the <a> tag from directive
a.href=fileURL;
a.download=scope.fileName;
a.target='_self';
a.click();//we call click function
}
}else{
alert('SORRY YOUR BROWSER IS NOT COMPATIBLE');
}
}
});
}
}
})
IN CONTROLLER:
$scope.myBlobObject=undefined;
$scope.getFile=function(){
console.log('download started, you can show a wating animation');
serviceAsPromise.getStream({param1:'data1',param1:'data2', ...})
.then(function(data){//is important that the data was returned as Aray Buffer
console.log('Stream download complete, stop animation!');
$scope.myBlobObject=new Blob([data],{ type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
},function(fail){
console.log('Download Error, stop animation and show error message');
$scope.myBlobObject=[];
});
};
IN SERVICE:
function getStream(params){
console.log("RUNNING");
var deferred = $q.defer();
$http({
url:'../downloadURL/',
method:"PUT",//you can use also GET or POST
data:params,
headers:{'Content-type': 'application/json'},
responseType : 'arraybuffer',//THIS IS IMPORTANT
})
.success(function (data) {
console.debug("SUCCESS");
deferred.resolve(data);
}).error(function (data) {
console.error("ERROR");
deferred.reject(data);
});
return deferred.promise;
};
BACKEND(on SPRING):
#RequestMapping(value = "/downloadURL/", method = RequestMethod.PUT)
public void downloadExcel(HttpServletResponse response,
#RequestBody Map<String,String> spParams
) throws IOException {
OutputStream outStream=null;
outStream = response.getOutputStream();//is important manage the exceptions here
ObjectThatWritesOnOutputStream myWriter= new ObjectThatWritesOnOutputStream();// note that this object doesn exist on JAVA,
ObjectThatWritesOnOutputStream.write(outStream);//you can configure more things here
outStream.flush();
return;
}
in template
<md-button class="md-fab md-mini md-warn md-ink-ripple" ng-click="export()" aria-label="Export">
<md-icon class="material-icons" alt="Export" title="Export" aria-label="Export">
system_update_alt
</md-icon></md-button>
in controller
$scope.export = function(){ $window.location.href = $scope.export; };
I'm working on an MVC project in which jsrender is used.
This is my first time working with jsrender (in fact I'm fairly new at javascript and C# too lol) and I've been struggling with one particular problem for a full day now.
I have the following javascript
$.post('#Url.Action("GetDocs","Place", new { placeID = Model.PlaceId})').done(
function (data) {
var template = $.templates("#doc-tmpl");
var htmlOut = template.render(data.documents);
$("#documentListContainer").append(htmlOut);
$(".docCount").html(data.count);
});
This gets all the data I need for the template below, but I need to create an Url.Action() using a piece of that data.
<script id="doc-tmpl" type="text/x-jsrender">
<div class="col-md-4">
<h5>{{:Name}}{{:test}}</h5>
<p id="DocId" class="hidden"><br />{{:DocId}}</p>
<img src="data:image;base64,{{:FrontCoverImg}}" width="140" height="230" />
Link
</div>
I need to supply the docId from the data in the routeValues of the #Url.Action("DisplayPDF","Place", new { docId = "{{:docId}}" }).
Obviously this isn't working in it's current state.
I've looked at the jsrender documentation and other Q&A to do with jsrender and MVC but I'm having trouble wrapping my head around the way it works.
one thing I have thought of is to create the #Url.Action() within the javascript and use a tag to pop it in the template, however I haven't been able to figure out how to add to the data from the $.post in order to make a tag available for it.
Edit:
What I mean from the above paragraph is, the data returned by the javascript/getDocs post is something like:
documents": [
{
"DocId": "86f86a32-5005-456c-8dd1-c023a66dd794",
"Name": "How to...",
"FrontCoverImg": "Base64String(docImg)"
},
{
"DocId": "d29f8afc-3191-47f1-9b88-1de08582ba27",
"Name": "A Document",
"FrontCoverImg": "Base64String(docImg)"
}
],
"count": 2
}
Which is then set up to fill in the template. I'm hoping there is a way to add the #Url.Action() statement to those key/value pairs, something like:
"viewdoc" : '##Url.Action("DisplayPDF", "Place", new {DocId = ' + DocId + ', ##class = "btn btn-default" })';
(not sure if the syntax is quite right there) so I could then put {{:viewdoc}} into the template.
Am I at least on the right track? lol
try this ,
var id = $('#docId').val();
var link = '#URL.Action("download file", "download", new { id = "-1" })';
link = link.replace("-1", id);
Source : How to access javascript variable within #URL.Action()
Ok so after leaving it alone for a week then much experimentation and googling, I found my solution.
I've created the link in the controller, where the JSON data is set.
I had to request the leftmost part of the URL and hardcode the controller/action part of the url, otherwise it crammed the new url on the end of the current page url.
So the solution is as follows:
The Controller:
foreach (Doc document in docs)
{
DocJson dj = new DocJson();
dj.DocId = document.DocId;
dj.Name = document.Comments;
//get base Url
var request = HttpContext.Request.Url.GetLeftPart(UriPartial.Authority);
dj.docLink = request + "/Place/DisplayPDF?DocId=" + document.DocId;
//get image bytes
var docImg = document.FrontCoverImg;
dj.FrontCoverImg = Convert.ToBase64String(docImg);
documents.Add(dj);
}
return Json(new { documents = documents, count = documents.Count() }, JsonRequestBehavior.AllowGet);
(in the view)
The Javascript getting the data:
//getDocs
$.post('#Url.Action("GetDocs","Place", new { placeID = Model.PlaceId})').done(
function (data) {
console.log(data);
var template = $.templates("#doc-tmpl");
var htmlOut = template.render(data.documents);
$("#documentListContainer").append(htmlOut);
$(".docCount").html(data.count);
});
(in the view)
And the template itself:
#* Document jsrender template *#
<script id="doc-tmpl" type="text/x-jsrender">
<div class="col-md-4">
<a href="{{:docLink}}" target="_blank">
<h5>{{:Name}}</h5>
<p id="DocId" class="hidden"><br />{{:DocId}}</p>
<img src="data:image;base64,{{:FrontCoverImg}}" width="140" height="230" />
</a>
</div>
</script>
Is there a way to add a Html.ActionLink through javascript?
For instance, I have this Edit function in my controller:
public ViewResult Edit(int companyID)
{
....
}
And I'd like to do something like this in javascript:
var id = $("#hdnID").val();
$("#editLink").html(<%: Html.ActionLink("Edit", "Edit", new { id }) %>);
A bit of a crude example, but it's basically what I'd like to do. Is it at all possible?
The id is a client script. You cannot mix server side script with client script. I am afraid that you are trying to submit HTML forms with action links instead of using submit buttons which is very bad. I see that you fetch the value of an input field with $("#hdnID").val() and then try to assign it to some action link and send to the server whereas if you used a simple submit button you wouldn't even need javascript. Your code would simply be:
<% using (Html.BeginForm("Edit", "Home")) { %>
<%: Html.HiddenFor(x => x.HdnId) %>
<input type="submit" value="Edit" />
<% } %>
Also it is clear that if you are using a hidden field it's because the user cannot change the value so an even simpler solution would be to directly generate the link you need:
<%: Html.ActionLink("Edit", "Edit", new { id = Model.SomeId }) %>
I haven't found a really good way yet. What I usually do is something like this:
var id = $("#hdnID").val();
var link = '<%: Html.ActionLink("Edit", "Edit", new { id = -999 }) %>';
$("#editLink").html(link.replace('-999', id));
The key is to select a value that id would never have in reality or exist otherwise in the link.
I found a handy way out of this problem thinking slighly out of the box. The reason I use ActionLink is really for an easy way to handle the routing. Simply supply Controller and action name and the helper generates the correct url. To get around this in JavaScript I first created an HtmlHelperExtender using the UrlHelper to resolve the url in proper context.
namespace System.Web.Mvc.Html
{
public static class HtmlHelperExtensions
{
public static string ResolveUrl(this HtmlHelper html, string url)
{
var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
return urlHelper.Content(url);
}
}
}
Now in JavaScript it's easy enough to get the proper Url
$(document).ready(function () {
var action = '<%= Html.ResolveUrl("~/Controller/JsonAction") %>';
// JSON controller call for model data
$.getJSON(action, null, function (models) {
// Do something with models
action = '<%= Html.ResolveUrl("~/Controller/Details/") %>';
for (var i = 0; i < models.length; i++) {
$('#modelList').append(
'<tr><td>' + models[i].Title + '</td></tr>');
}
});
});
This is how I did it. You can use javascript replace.
var ul = document.createElement('ul');
if (data.EvidenceList != null) {
for (var i = 0; i < data.EvidenceList.length; i++) {
var li = document.createElement("li");
var evidenceId = data.EvidenceList[i].EvidenceId;
var evidenceName = data.EvidenceList[i].Name;
var candidateProgrammeComponentId = data.CandidateProgrammeComponentId;
var str1 = '#Html.ActionLink("dummyEvidenceText", "DownloadFile", new { candidateProgrammeComponentId = "dummyCandidateProgrammeComponentId", evidenceId = "dummyEvidenceId", evidenceName = "dummyEvidenceName" })';
var str2 = str1.replace('dummyEvidenceName', evidenceName);
var str3 = str2.replace('dummyCandidateProgrammeComponentId', candidateProgrammeComponentId);
var str4 = str3.replace('dummyEvidenceId', evidenceId);
var str5 = str4.replace('dummyEvidenceText', evidenceName);
li.innerHTML = li.innerHTML +str5 ;
ul.appendChild(li);
}
}
var element = document.getElementById('evidenceList_' + data.guidId);
$('#evidenceList_' + data.guidId).empty();
document.getElementById('fileUploadFreeStructure_' + data.guidId).value = '';
$('#freeTextArea_' + data.guidId).val('');
element.appendChild(ul);
The server side code (the C#) is ran on the server, and the result is sent to the client, where the client then executes the JavaScript. So as weird as it is, you have two different code environments bumping into each other but can't interact with each other very well.
I usually do something like this, although I'm open to better ways:
function SetUrl(id) {
var url = '<%: Html.ActionLink("Bar", "Foo") %>' + '?id=' + id;
return url;
}
This takes advantage of the fact that
/Foo/Bar/{id} is usually equivalent to /Foo/Bar?id={id}, depending on how your routes are set up.