Calling an action with parameter .Net Core - asp.net

I have a MyMessages model that I put data into when the user logs in. it includes all the data needed.
for every message that they have I do the following in view
for (int i = 0; i < Model.MyMessagesCount; i++)
{
<li class="list-group-item d-flex align-items-center mt-2">
<a>#Model.MessagesTitles[i]</a>
</li>
When the user clicks on each of the <a>, I want to show them that message in more details in a separate view where I pass MessageID to.
How can I achieve that? How can I have all the <a> call the same action but with different MessageID as a parameter? (Something like this /User/Usermessages?MessageID=20)

You can use anchor tag helper
<li>
<a asp-controller="user"
asp-action="messages"
asp-area=""
asp-route-messageId="#Model.MessagesTitles[i].MessageId">
#Model.MessagesTitles[i]
</a>
</li>
asp-route-{parameter}: the parameter there is the name of the parameter you define in your action.
You can read more on https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-5.0

In the Index.cshtml page, you could directly set the a tag href attribute.
Code sample as below:
public IActionResult Index()
{
List<MyMessages> messages = new List<MyMessages>()
{
new MyMessages(){ MessageId=1001, MessageTitile="AA"},
new MyMessages(){MessageId =1002, MessageTitile="BB"},
new MyMessages(){MessageId=1003, MessageTitile="CC"}
};
return View(messages);
}
public IActionResult Details(int messageId)
{
return View();
}
Index.cshtml page:
#model List<SignalRChatSample.Models.MyMessages>
<ul>
#for (int i = 0; i < Model.Count(); i++)
{
<li class="list-group-item d-flex align-items-center mt-2">
#Model[i].MessageTitile
</li>
}
</ul>
Then, the result like this (The url: Https://localhost:5001/Home/Details?messageId=1002):
Besides, as David said, you could also send the parameters via the route.

Related

Pagination Thymeleaf 3.0 Spring MVC

I would like to find a complete solution to Thymeleaf pagination using Spring PagingAndSortingRepository DAO. I got a partial solution working, but I can not get the final one. I think it would be interesting for everyone else as a code snipet, so I will ask for the whole thing. I could not find a solution on the web which is kind of strange for me (since I think it could be a quite common problem).
The final solution should behave like Google's pagination: with arrows on both sides only if it makes sense; with a maximun of 10 numbers (for example), and it should move from 1..10 --> 11..20 and so on, when you click the right arrow; and move to 5..15 when you click on 10. Just like google, you know. The size controls the number of items in each page, not the number of blocks or links in the pagination bar.
I have a DAO repository in Spring that extends PagingAndSortingRepository ...
package music.bolo.domain.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import music.bolo.domain.entity.Announcement;
#Repository public interface AnnouncementDao extends
PagingAndSortingRepository {
Announcement findFirstByOrderByDateDesc(); }
So my service can make a request and each page will get the totalPageNumbers (http://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Page.html)...
private final static int PAGESIZE = 2;
.. .. #Autowired annotations...
public Page<Announcement> readAnnouncementPage (int pageNumber){
PageRequest request = new PageRequest(pageNumber-1, PAGESIZE, Sort.Direction.DESC, "date");
return announcementDao.findAll(request); }
My Controller uses the data to send all the information to Thymeleaf
#RequestMapping(value = "/viewannouncements", method = RequestMethod.GET)
ModelAndView viewAnnouncements(ModelAndView modelAndView, #RequestParam(name = "p", defaultValue = "1") int pageNumber) {
Page<Announcement> page = announcementService.readAnnouncementPage(pageNumber);
modelAndView.getModel().put("page2th", page);
modelAndView.setViewName("viewannouncements");
return modelAndView; }
My solution is partial, it shows all the pages all the time, no arrow control (actually useless) and without any other funcionality, but it is the most I could make it work without bugs.
<div class="tag-box tag-box-v7 text-justify">
<!-- <h2>Pagination Centered</h2>-->
<div class="text-center">
<ul class="pagination">
<li>«</li>
<!--<li>«</li>-->
<li th:each="i : ${#numbers.sequence( 1, page2th.TotalPages)}">
<a th:href="#{'/viewannouncements?p='}+${ i }" th:text="${ i }">1</a></li>
<!--<li>»</li>-->
<li>»</li>
</ul>
</div>
</div>
This is an example of pagination with SpringBoot and Thymeleaf templates, you can try it.
It is self-explanatory.
Following you can find link to GitHub repo -
https://github.com/karelp90/control_asp
<div class="tag-box tag-box-v7 text-justify">
<div class="text-center">
<ul class="pagination" th:with="elementsperpage=2, blocksize=10, pages=${page2th.Number}/${elementsperpage}, wholepages=${format.format(pages)},
whole=(${page2th.Number}/${blocksize})+1, wholex=${format.format(whole)}, startnlockpage=${wholepages}*${blocksize+1}, endblockpage=${wholepages}*${blocksize+1},
startpage=${wholex-1}*${blocksize}, endpage=(${wholex}*${blocksize})+1">
<li>
<a th:if="${startpage gt 0}" th:href="#{${'/viewannouncements?p='}+${startpage}}"><<</a>
<a th:if="${startpage eq 0}" href="javascript:void(0);"><<</a>
</li>
<li th:each="pageNo : ${#numbers.sequence(endpage-11, (endpage lt page2th.TotalPages)? endpage-2 : page2th.TotalPages-1)}"
th:class="${page2th.Number eq pageNo}? 'active' : ''">
<a th:if="${page2th.Number eq pageNo}" href="javascript:void(0);">
<span th:text="${pageNo + 1}"></span>
</a>
<a th:if="${not (page2th.Number eq pageNo)}" th:href="#{${'/viewannouncements?p='}+${pageNo+1}}">
<span th:text="${pageNo + 1}"></span>
</a>
</li>
<li>
<a th:if="${(endpage*elementsperpage) le (page2th.TotalElements)}" th:href="#{${'/viewannouncements?p='}+${endpage}}">>></a>
<a th:if="${(endpage*elementsperpage) le (page2th.TotalElements)}" href="javascript:void(0);"></a>
</li>
</ul>
</div>
</div>

Create dynamic links in the navigation panel

I am trying to dynamically create my top navigation panel in ASP.NET Core MVC 6.
I know it's simple but I cannot figure out how to make it work. Here is what I do (simplified):
My Model:
public class IP_Category
{
public int id { get; set; }
public string DisplayName { get; set; }
}
in my controller:
public IActionResult Index()
{
//This way I dynamically pass data to my View
ViewBag.Categories = _repository.ReturnCategories();
return View();
}
in my cshtml page:
#{
//this info is in the top of the page, here I retrieve data passed from
//controller and save it as a local variable
var categories = (List<IP_Category>)ViewBag.Categories;
}
Then later in the _Layout where I take care of the navigation:
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-controller="Home" asp-action="About">About</a></li>
<li><a asp-controller="Home" asp-action="Contact">Contact</a></li>
#foreach (var category in categories)
{
<li><a asp-controller="Home" asp-action="#category.DisplayName">#category.DisplayName</a></li>
}
</ul>
The problem occurs with asp-action="#category.DisplayName" which does not generate appropriate href in my actual page.
So the question is what am I doing wrong? How can I pass category.DisplayName to my asp-action tag so the links work correctly?
Edit 1 - Adding more code:
Here is what was generated (note the missing href tag)
<ul class="nav navbar-nav">
<li>Home</li>
<li>About</li>
<li>Contact</li>
<li>Item1</li>
<li>Item2</li>
</ul>
if the controller and action don't match an existing controller and action then no href will be rendered. I suspect that #category.DisplayName does not match any actual action name on your home controller. Seems more likely that you have an action named Category that expects a parameter corresponding to the #category.DisplayName so it should be passed as a route parameter not as the action name
#foreach (var category in categories)
{
<li><a asp-controller="Home"
asp-action="Category"
asp-route-category="#category.DisplayName">#category.DisplayName</a></li>
}

Issue with pagination in PagedList MVC

I am using MVC PagedList to handle pagination in my project. Everything works fine except that in my controller I have to initialize pageNumber parameter with "1" (Default page number). The problem is the blue activated button on page 1 that remains there no matter which page button link you click. Moreover this button is also missing the actionLink.
One last thing I am integrating my search with pagination as you can see in the controller code.
public PartialViewResult List_Items(string keyword, int? page)
{
var newlists = from s in db.TrMs
orderby s.S1
select s;
int pageNumber = (page ?? 1);
int pageSize = 10;
var data = newlists.Where(f => f.S1.ToString().Contains(keyword) && f.S100 == vt).ToPagedList(pageNumber, pageSize);
return PartialView(data);
}
Here is the generated Html for PagedList in my view
<div class="pagination-container">
<ul class="pagination">
<li class="active">
<a>1</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=2">2</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=3">3</a>
</li>
<li>
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=4">4</a>
</li>
<li class="PagedList-skipToNext">
<a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#searchResult" href="/TrM/Search_Items?keyword=&page=2" rel="next">»</a>
</li>
</ul>
</div>
Here is how I am using the pagination helper.
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("List_Items", "TrM", new {keyword="", page }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "searchResult" }))
Your paging controls are most likely outside of the searchResult container. When you click on a page you're replacing the table but not the paging controls. Move your paging controls inside of your searchResult container!
Hope this helps.

Meteor + Iron Router to create breadcrumbs

Ok, so I found this post: Meteor breadcrumb
But lets say I have the following:
<template name="somePage">
<h1>Page Title</h1>
{{> breadcrumb}}
</template>
<template name="breadcrumb">
<ul class="breadcrumb">
<li>
Home
</li>
{{#each path}}
<li>
{{this}}
</li>
</ul>
</template>
Helper:
Template.breadcrumb.helpers({
path: function() {
return Router.current().path.split( "/" );
}
});
Ok so the linked question at the top got me the basics. I'm trying to understand how to do a few more things here that should be obvious. I want the first to be for the home page, and the result returned from the path: function() includes an empty "", "page", "page", etc. in the beginning of it.
I'd like to be able to incorporate the proper paths. To be clear, I'd love to pull this off:
<template name="breadcrumb">
<ul class="breadcrumb">
<li>
Home
</li>
~ pseudo logic
{{#each path that isn't current page}}
<li>
{{this}}
</li>
{{/each}}
<li>
{{ currentPage }}
</li>
</ul>
</template>
Has anyone done this or found a reference that I haven't stumbled across yet?
I'll give you my own recipe for breadcrumbs using iron:router.
It works by supplying additional options to your routes in order to establish a hierarchy between them, with parent-children relations. Then we define a helper on the Router to give us a list of parent routes (up to home) for the current route. When you have this list of route names you can iterate over them to create your breadcrumbs.
First, we need to define our breadcrumbs template which is actually very similar to your pseudo-code. I'm using bootstrap and font-awesome, as well as some newly introduced iron:router#1.0.0-pre features.
<template name="breadcrumbs">
<ol class="breadcrumb">
<li>
{{#linkTo route="home"}}
<i class="fa fa-lg fa-fw fa-home"></i>
{{/linkTo}}
</li>
{{#each intermediateRoutes}}
<li>
{{#linkTo route=name}}
<strong>{{label}}</strong>
{{/linkTo}}
</li>
{{/each}}
<li class="active">
<strong>{{currentRouteLabel}}</strong>
</li>
</ol>
</template>
The {{#linkTo}} block helper is new in iron:router#1.0.0-pre, it simply outputs an anchor tag with an href attribute which value is {{pathFor "route"}}.
Let's define the helpers from our breadcrumbs template:
Template.breadcrumbs.helpers({
intermediateRoutes: function() {
if (!Router.current()) {
return;
}
// get rid of both the first item, which is always assumed to be "home",
// and the last item which we won't display as a link
var routes = Router.parentRoutes().slice(1, -1);
return _.map(routes, function(route) {
// extract name and label properties from the route
return {
name: route.getName(),
label: route.options.label
};
});
},
currentRouteLabel: function() {
// return the label property from the current route options
return Router.current() && Router.current().route.options.label;
}
});
Notice that we rely on the existence of a special option named 'label' which represents what we're going to put in our anchors, we could also have used the name for testing purpose.
The parentRoutes method is something we need to extend the Router with:
_.extend(Router, {
parentRoutes: function() {
if (!this.current()) {
return;
}
var routes = [];
for (var route = this.current().route; !_.isUndefined(route); route = this.routes[route.options.parent]) {
routes.push(route);
}
return routes.reverse();
}
});
Again, this function assumes that every route (except "home") has a parent property which contains the name of its parent route, we then iterate to traverse the route hierarchy (think of a tree, like a file system structure) from the current route up to the root route, collecting each intermediate route in an array, along with the current route.
Finally, don't forget to declare your routes with our two additional properties that our code relies on, along with a name which is now mandatory as routes are indexed by name in the Router.routes property:
Router.route("/", {
name: "home"
});
Router.route("/nested1", {
name: "nested1",
parent: "home"
});
Router.route("/nested1/nested2", {
name: "nested2",
parent: "nested1"
});
// etc...
This example is pretty basic and certainly doesn't cover every use case, but should give you a solid start in terms of design logic toward implementing your own breadcrumbs.
Inspired by #saimeunt I created a meteor breadcrumb plugin which can be found here: https://atmospherejs.com/monbro/iron-router-breadcrumb. You also specify a parent route and a title for the route itself.
I used saimeunt answer but had to make small changes to the template and the template helpers because I have parameters in some of my route paths. Here are my changes.
Template changes: add data=getParameter to #linkTo for intermediate routes
<template name="breadcrumbs">
<ol class="breadcrumb">
<li>
{{#linkTo route="dashboard"}}
<i class="fa fa-lg fa-fw fa-home"></i>
{{/linkTo}}
</li>
{{#each intermediateRoutes}}
<li>
{{#linkTo route=name data=getParameters}}
<strong>{{label}}</strong>
{{/linkTo}}
</li>
{{/each}}
<li class='active'>
<strong>{{currentRouteLabel}}</strong>
</li>
</ol>
</template>
Template helper changes: add helper function getParameters to get parameters from current route.
Template.breadcrumbs.helpers({
intermediateRoutes: function () {
if (!Router.current()) {
return;
}
var parentRoutes = Router.parentRoutes();
var routes = parentRoutes.slice(1, -1);
var intermediateRoutes = _.map(routes, function (route) {
return {
name: route.getName(),
label: route.options.label
};
});
return intermediateRoutes;
},
currentRouteLabel: function () {
var currentRouteLabel = Router.current() && Router.current().route.options.label;
return currentRouteLabel;
},
getParameters: function(){
var currentRoute = Router.current();
var parameters = currentRoute.params;
return parameters;
}
});

Loading MVC 4 default view with jQuery load()

I have built an mvc 4 website, and I built it so that the main layout page doesn't refresh if a different section is loaded with jQuery. I put the navigator and jQuery script in _Layout.cshtml:
<ul id="menu" class="menu-items">
<li><a id="Item1" href="#" onclick="loadPage(this.id)">Item1</a></li>
<li><a id="Item2" href="#" onclick="loadPage(this.id)">Item2</a></li>
<li><a id="Item3" href="#" onclick="loadPage(this.id)">Item3</a></li>
<li><a id="Item4" href="#" onclick="loadPage(this.id)">Item4</a></li>
</ul>
</body>
<script>
function loadPage(action) {
$.post("/Home/" + action, function (data) {
$(content).html(data);
});
}
</script>
Then I have my controller:
namespace MyApp.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Item1()
{
if (Request.IsAjaxRequest())
{
return PartialView();
}
return View();
}
[HttpPost]
public ActionResult Item2()
{
if (Request.IsAjaxRequest())
{
return PartialView();
}
return View();
}
Etc, etc.
Everything works fine, except that I don't know how to use just one main content view (which is index.cshtml when the website loads in the browser). I'm forced to put the same content that's in index.cshtml into item1.cshtml so that when I trigger onlick for item1, it will go back to the main content. The only route config I have is for the Default, which initially set to Index:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
What I want, is to be able to use just one main content page, but have the ajax call still get me back to the main content when I click Item1. Does anyone know what I need to do? It seems to be a little overkill to have to update both views when I want to update the main content.
Also, I think other web devs will like this code. Especially if you're building a band's website like I'm doing. It allows me to put the demo song media player in the _layout.cshtml page so that it won't refresh when the user is clicking to the other sections (i.e. if it refreshes, the media player stops). With this design, the user can navigate the whole website while the songs continue to play.
I'm rather new to javascript, so I'm sure I could have made a better onclick handler rather than using anchor tags, so if anyone want to show me a better way, please do. But my main problem is the index.cshtml vs item1.cshtml dilemma.
Correct me if I'm wrong: you want to refresh part of your page when clicking on ItemX link and the controller methods ItemX are only used via Ajax (as you're building a single page app).
In this case you could do something like this:
Cshtml
<ul id="menu" class="menu-items">
<li><a id="Item1" href="#" onclick="loadPage(this.id)">Item1</a></li>
<li><a id="Item2" href="#" onclick="loadPage(this.id)">Item2</a></li>
<li><a id="Item3" href="#" onclick="loadPage(this.id)">Item3</a></li>
<li><a id="Item4" href="#" onclick="loadPage(this.id)">Item4</a></li>
</ul>
<div id="container">
</div>
</body>
<script>
function loadPage(action) {
$.post("/Home/" + action, function (data) {
$("#container").html(data);
});
}
// Will load Item1 via Ajax on page load
loadPage('Item1');
</script>
Home Controller
[HttpPost]
public ActionResult Item1()
{
return PartialView();
}
Your PartialViews should only contain the HTML specific to the current item.
Update
If you wish to avoid the Ajax call you could do this also in your cshml
...
</ul>
<div id="container">
#Html.Partial("Item1PartialView")
</div>
</body>
...

Resources