Build Menu Items From Controller - c#

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.

Related

Redirect to Page but specific Tab

I have used this as an example of what I am trying to do.
I have a tabbed page.
In my Controller I want to redirect to a page but a specific tab on that page.
Now when I am on that page, and hover over the tab the link is http://localhost:xxxxx/OInfoes/Details/2#phases
So in my controller I did this to try and recreate the same link:
return new RedirectResult(Url.Action("Details", "OInfoes", new { id = phase.OID }) + "#phases");
This gives me the correct link but it doesn't put me on the correct tab.
How do I get this to work?
My HTML for the tabs is below:
<ul class="nav nav-tabs">
<li class="active">Information</li>
<li>Previous Reports</li>
<li>Previous/Current Phases</li>
</ul>
You should update your action method to take a parameter to represent the tab to be selected.
public ActionResult Details(int id,string tab="")
{
if (id != null)
ViewBag.ActiveTab = id.ToString();
// to do : Return a view
}
When you return the redirect result, send a querystring with name tab
return new RedirectResult(Url.Action("Details", "OInfoes", new { id = phase.OID ,
tab="phases"}));
Now in your document ready, use the value of ViewBag.ActiveTab value, generate the jQuery selector from that and use that to call .tab('show').
$(function () {
var selector = '#ViewBag.ActiveTab';
if(selector)
{
$("#link-tab"+selector).tab('show');
}
});
Make sure your tab's has id's matching with our above code.
<ul class="nav nav-tabs">
<li class="active">Info</li>
<li>Prev Reports</li>
<li>Prev/Cur Phases</li>
</ul>

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/

How could i change layout page from viewpage in mvc

I am working on asp.net mvc 3 with razor. I have a layout(master) page in my project. It contains a side panel with 4 links and place for viewpage(#RenderBody). when user clicks on link1 it redirects to viewpage1 and link1 should be selected, and when he clicks link2 it redirects to viewpage2 and link2 should be selected so on. It redirecting very well to required pages but it always selects the link1 only though i clicked link2,link3,link4. How could i select the appropriate link in layout page from the individual viewpage. guide me.
By selected I guess you mean highlight using CSS, don't you? If this is the case I would propose you to write a custom HTML helper to generate those links:
public static IHtmlString MenuItem(
this HtmlHelper htmlHelper,
string text,
string action,
string controller
)
{
var li = new TagBuilder("li");
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.GetRequiredString("action");
var currentController = routeData.GetRequiredString("controller");
if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
{
li.AddCssClass("active");
}
li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
return new HtmlString(li.ToString());
}
and then inside your layout use the helper:
<ul>
#Html.MenuItem("link 1", "Action1", "Controller1")
#Html.MenuItem("link 2", "Action2", "Controller2")
...
</ul>
and now all that's left is to define the .active rule in your CSS class:
.active {
... something fancy to pop the currently selected link from the others
}

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

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" }) %>

Categories

Resources