How to manipulate Html.ActionLink to show a link to another controller? - c#

In the Details view of the HomeController, I'd like to create a link to the Email view on the MiscController. In addition, I need to add an item to the QueryString.
I'd like to create a link that goes something like:
<a href="http://www.blah.com/misc/SendMail?id=6">
<font size="1">Report problems</font>
</a>
I've tried the following:
<% Html.ActionLink("<font size=\"1\">Report</font>", "SendMail", "Misc", Model.ImageID, new object()); %>
It returned no link. What am I missing?

First of all, you missed the = after the <%. That's why it didn't output anything.
Also, the way you passed routeValues parameter was wrong.
It should be :
<%=Html.ActionLink("<font size=\"1\">Report</font>", "SendMail", "Misc",
new { id = Model.ImageID }, null /*htmlAttributes*/) %>
Please keep in mind though the text argument will be encoded in the output, so there's no point in sending HTML with that argument.
It's best to use CSS to style your HTML.
For example :
a.myLink {font-size: 0.5em;color:yellow;}
And to set the class attribute for the anchor element :
<%=Html.ActionLink("Report", "SendMail", "Misc",
new { id = Model.ImageID }, new { #class = "myLink" }) %>

Related

Build Menu Items From Controller

I am creating HTML Menus from controller. Menus are stored in database and I make html tag as below :
foreach (UIMenuModel item in list)
{
if (item.Controller != "Home")
{
string line = string.Format(#"<li><a asp-area=""{0}"" asp-controller=""{1}"" id=""{1}""
asp-action = ""{2}"" style = ""font-size:16px;;"" > {3} </a></li>", item.Area, item.Controller, item.Action, item.LinkText);
sb.Append(line);
}
}
which gives me below HTML :
<li><a asp-area="" asp-controller="CrossApproval" id="CrossApproval" asp-action="Index" style="font-size:16px;;"> Cross Approval </a></li>
Other Menu Item, Which is written in HTML itself, gives below HTML in browser.
<li><a id="CrossRequest" style="font-size:16px" href="/CrossRequest">Cross Request</a></li>
On UI, it looks perfect. However, I am not able to click and navigate to desired controller and action methods. Can someone please help me to identify while this anchor tag is not allowing me to navigate.
Use RazorLightEngine to convert plain string as rendered Razor string:
string content = "Hello #Model.Name. Welcome to #Model.Title repository";
var model = new
{
Name = "John Doe",
Title = "RazorLight"
};
var engine = new RazorLightEngine();
string result = engine.ParseString(content, model);
And then add it any place in razor view like encoded string
<div>
#Html.Raw(result)
</div>
As posted in Question, HTML with href was working fine. So, I decided to mimic the same behaviour from the controller and changed my code as below :
string line = string.Format(#"<li><a asp-area=""{0}"" id=""{1}"" href=""/{1}/{2}""
style=""font-size:16px"">{3}</a></li>", item.Area, item.Controller, item.Action, item.LinkText);
This generated a link which I can click and navigate.

use a jsrender tag to supply routevalue in #Url.Action()

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>

Reloading Partial View with JQuery

I have a page with a video at the top and a list of videos you can choose from. Currently, clicking a link in the video list will reload the entire page. I need it to only refresh the partial view I have containing the video at the top of the page.
I saw several posts here on SO showing how to reload partial views with JQuery, but couldn't get it to work correctly in my situation. I'm unsure how to pass the correct id of the video along.
Controller:
public ActionResult Videos(int topVideo = 0)
{
VideosModel model = new VideosModel();
model.Videos = StatsVideoService.GetEntityList(new Lookup(TableStatsVideo.IsDeleted, false)).OrderByDescending(x => x.DateCreated).ToList();
if (topVideo == 0)
model.TopVideo = model.Videos.First();
else
{
model.TopVideo = model.Videos.Where(x => x.StatsVideoId == topVideo).FirstOrDefault();
if (model.TopVideo == null)
model.TopVideo = model.Videos.First();
}
return View(model);
}
View:
#model Project.Models.VideosModel
<section class="videos">
<div id="top_video">
#{Html.RenderPartial("StatsVideo", Model.TopVideo);}
</div>
<ul>
#foreach (var item in Model.Videos)
{
<li>
<div class="videoList">
<a href ="#Url.Action("Videos", "Home", new { topVideo = item.StatsVideoId })">
<img src="#Url.Content("~/Content/img/video-ph.png")" />
</a>
<p class="videoTitle">#item.Title</p>
</div>
</li>
}
</ul>
</section>
If there's any more information needed, please let me know.
After several hours of bashing my head against the wall, I got it to work! Just as a reference to anyone else in the future who's viewing this article, here's how I got it to work:
I set the onclick of the link to point to a javascript method, passing in the id of the video as a parameter:
#foreach (var item in Model.Videos)
{
<li>
<div class="videoList">
<a href ="#" onclick="updateTopVideo(#item.StatsVideoId)">
<img src="#Url.Content("~/Content/img/video-ph.png")" />
</a>
<p class="videoTitle">#item.Title</p>
</div>
</li>
}
And then I included this script in the view at the bottom:
<script>
var updateTopVideo = function (itemId) {
var url = '#Url.Content("~/Home/StatsVideo/")';
url = url + itemId;
$.get(url, "", callBack, "html");
};
var callBack = function (response) {
$('#top_video').html(response);
};
</script>
Finally, I added a method to my controller that would return the partial view needed for the video at the top of the screen:
public ActionResult StatsVideo(int Id)
{
IStatsVideo vid = StatsVideoService.GetEntity(new Lookup(TableStatsVideo.StatsVideoId, Id));
if (vid == null)
vid = StatsVideoService.GetEntityList(new Lookup(TableStatsVideo.IsDeleted, false)).OrderByDescending(x => x.DateCreated).FirstOrDefault();
return PartialView(vid);
}
This code should be fairly easy to understand. Basically, the onclick calls the first javascript method, which then calls the controller. The controller builds the partial view and returns it. The first javascript method passes it to the second javascript method which sets the html of the div "top_video" to be the returned partial view.
If anything doesn't make sense, or anyone's having trouble with this in the future, let me know and I'll do my best to offer some help.
I think there may be several confusing and inconsistent elements here.
First, you are returning a full view instead of a partial view. This reloads all containing elements, not just the part that is relevant to your partial view.
Second, you are using Url.Action, which only generates the url. I would recommend using Ajax.ActionLink, which allows you to do fully ajax calls, refreshing the content of your partial div and updating a target div element.
instead of:
<div class="videoList">
<a href ="#Url.Action("Videos", "Home", new { topVideo = item.StatsVideoId })">
<img src="#Url.Content("~/Content/img/video-ph.png")" />
</a>
<p class="videoTitle">#item.Title</p>
</div>
try the more modern solution
<div class="videoList">
#Ajax.ActionLink(
"Videos",
"Home",
"new { topVideo = item.StatsVideoId },
new AjaxOptions {
HttpMethod = "GET",
OnSuccess = "handleSuccess"
}
)
</div>
This way you can be very specific on what you want each link to do, and you can pass along multiple parameters as well as define a callback function. You can also use "UpdateTargetId" in your ajax options to load your newly refreshed partial view into a DOM element.
You can remove the around the image and just store the url generated by the Url.Action in a data-href attribute.
Then you can use the jquery load method to load the data:
$(".videolist>img").click(function () {
$("#content").load($(this).data("href"));
});
I created a fiddle that loads content dynamically here, so you can play with it if you want: http://jsfiddle.net/bTsLV/1/

Posting two and more lists in asp.net mvc

I'm using asp.net mvc 2 and i found this behavour which i can't understand.I have following view:
<% using (Html.BeginForm("Index", "BlackListGrabber", FormMethod.Post) )
{
<%= Html.DropDownListFor(m => m.selectedArea, new SelectList(Model.areaList, "value", "text")) %>
<% if (Model.districtList != null) { %>
<%= Html.DropDownListFor(m => m.selectedDistrict, new SelectList(Model.districtList, "value", "text")) %>
<% } %>
<% if (Model.townList!= null) { %>
<%= Html.DropDownListFor(m => m.selectedTown, new SelectList(Model.townList, "value", "text")) %>
<% } %>
<input type="submit" value="post" />
<% } %>
and a controller's method like this:
[HttpPost]
public ActionResult Index(BlackListGrabberModel postedModel)
{
BlackListGrabberModel model = new BlackListGrabberModel(postedModel);
return View(model);
}
And, last but not least, my model:
BlackListGrabberModel(BlackListGrabberModel model)
{
if (string.IsNullOrEmpty(model.selectedArea))
{
areaList = GetRegions();
}
else if (string.IsNullOrEmpty(model.selectedDistrict))
{
areaList = model.areaList;
districtList = GetRegions(model.selectedArea);
}
else if (string.IsNullOrEmpty(model.selectedTown))
{
areaList = model.areaList;
districtList = model.districList;
districtList = GetRegions(model.selectedDistrict);
}
}
Idea is that then i load page, i see list of all possible areas.(And i see it - it's my first dropdownlistfor) When i select area, after clicking "post" button, i see list of all districts, they loaded from external source and this part works fine.
So i select district from list, and click "post". After thar i see list of all towns located in selected district, but districtList disappears. Then i traced it in my controller, i found that property postedModel.districtList is null. But postedModel.areaList is fine! Does that mean that i can post only one SelectList, or i'm missing something? Can somebody please give me any help?
P.S. Properties "selectedArea", "selectedDistrict", "selectedTown" are posted as expected.
EDIT. Thanks to everybody, i missed some important things, and you gave me direction to them.
My problem appeared to be areaList. It was filled by default constructor. I forgot about that, so then i saw postedModel.areaList filled, i thought it was magically posted by asp.net mvc mechanisms, and complained that all other lists are not filled because of some strange glithces.
You will have to repopulate your list properties in your model for every request.
The won't get posted back automatically. Just the selected value is posted back and bound to the property in your model (i.e. selectedArea is bound but not areaList).
The lists should not post, only the values of the select elements in your html form will. If you need to hold onto the list values, you might try placing them in TempData in you GET for Index, which will keep them for the next request.

Generating HTML from server-side block in ASP.NET MVC

This is a very newbie kind of ASP.NET question: I simply don't know and can't work out the correct syntax to use.
In my view I want to generate an action link if a certain condition is true on my model. I know how to generate a link using this syntax:
<%: Html.ActionLink("Do Something", "DoSomething", new { id = Model.ID }) %>
But for some reason that syntax doesn't work in this code:
<%
if (Model.CanDoSomething)
Html.ActionLink("Do Something", "DoSomething", new { id = Model.ID });
%>
I really am a newbie to ASP.NET, so I don't even know what the semantic name is for the different syntaxes <% and <%:; all I can tell is that <% is to void as <%: is to string. And clearly executing a line of code that just returns a string (Html.ActionLink()) is not going to have any effect. But what, pray what is the correct method to make my page render the action link?
It's a great pity I can't Google on "<%"! Any links or explanations of this subject will also be much appreciated.
This will do the trick
<% if (Model.CanDoSomething) { %>
<%: Html.ActionLink("Do Something", "DoSomething", new { id = Model.ID }) %>
<% } %>
<%: writes to the output buffer but encodes the string. You could also use <%= for unencoded output because ActionLink returns an encoded MvcHtmlString.
EDIT: This may also work
<%
if (Model.CanDoSomething)
Response.Write(Html.ActionLink("Do Something", "DoSomething", new { id = Model.ID }));
%>
<% - this by itself has no output. You would include code with no output in this block such as an if statement. If you want output - you must use it in conjunction with <%=
The difference with the : is that
<%: means it will output to the response stream, not = required however the : means the output will be htmlencoded.
<%:"sometest&text" %> //will emit "sometesttext" on the page.. htmlencoded.
<%="sometest&text" %> //will give you the same result without the '&' htmlencoded
<% SomeFunction() %> //will just run that function - there is no output
//you want
<%if (Model.CanDoSomething){%>
<%:Html.ActionLink("Do Something", "DoSomething", new { id = Model.ID })%>
<%}%>

Categories

Resources