Create href to subpage in Blazor - asp.net-core

My page has this directive #page "/sales/reports" so it loads at https://localhost/sales/reports route.
I want to create link Report 1 that will lead to a sub-page /sales/reports/{id} - for example https://localhost/sales/reports/8c5b8c1c-12b5-43ee-92c9-8d3bcb8644a4 but not sure what do I put in href of my anchor. When I simply put Report 1 link has a form of https://localhost/8c5b8c1c-12b5-43ee-92c9-8d3bcb8644a4. Do I need to hard-code Report 1 or there is a smarter way?

The term 'subpage' does not really exist.
There are just 'pages' and they have 'routes'. Sometimes the route appears nested, as in your example, but this does not make it a 'subpage'.
The answer to your question is that, yes, you need to include the route to the 'page' you want to go to.
<a href=#($"sales/reports/{#myGuid}")>Report 1</a>
That doesn't necessarily mean hardcoding in the page itself. You might create a helper class that does that for you. For example:
class ReportPathCreator
{
public static string ReportRouteFor(Guid reportGuid) => $"sales/reports/{reportGuid}";
}
Then use:
<a href=#(ReportPathCreator.ReportRouteFor(myGuid))>Report 1</a>
Then, if you choose to change the route where reports are hosted, you only need to change it in the helper class and all anchor elements in your site will automatically pick up that new route.
UPDATE
You can also use the static class to generate a template for you to use instead of #page directive:
class ReportPathCreator
{
public static string ReportRouteFor(Guid reportGuid) => $"sales/reports/{reportGuid}";
public static string ReportTemplate = "sales/reports/{reportGuid:guid}";
}
And then, instead of #page directive, use:
#attribute [Route(ReportPathCreator.ReportTemplate)]

Related

How do I allow my ASP.NET Core tag helpers to be self-closing

I have written a tag helper that I can use as follows...
<mytaghelper attr1="jim"></mytaghelper>
I would like to be able to shorten this to just...
<mytaghelper attr1="jim">
...or at least...
<mytaghelper attr1="jim"/>
However, I can't get this to work. Here is some sample code for the Process method...
public override void Process(TagHelperContext context, TagHelperOutput output) {
output.TagName = "div";
output.PreContent.SetHtmlContent("<div>");
output.Content.SetHtmlContent("OUTPUT HTML GOES HERE");
output.PostContent.SetHtmlContent("</div>");
output.Attributes.Clear();
}
I have tried adding a TagStructure setting to the HtmlTargetElement attribute on the class...
[HtmlTargetElement("mytaghelper", TagStructure = TagStructure.WithoutEndTag)]
...but it doesn't seem to make any difference. <mytaghelper attr1="jim"/> generates <div /> and <mytaghelper attr1="jim"></mytaghelper> generates <div></mytaghelper>.
If I set the TagStructure to NormalOrSelfClosing then included a closing tag works, but <mytaghelper attr1="jim"/> gives an empty <div />
Anyone able to explain what I need to do?
TagStructure.WithoutEndTag is able to write the tag with only a start tag or self-closing, but the output would be <div > or <div/> . Self-closing anchor tags are not valid HTML, so you wouldn't want to create one, but you might want to create a tag helper that's self-closing. Tag helpers set the type of the TagMode property after reading a tag. Add the below code line Inside the process method:
output.TagMode = TagMode.StartTagAndEndTag;
Take a moment to read Author Tag Helpers in ASP.NET Core which covers this perfectly .
The correct syntax is:
[HtmlTargetElement("mytaghelper", TagStructure = TagStructure.WithoutEndTag)]
Which should be applied to the taghelper class, not the Process method. You may already be doing that, but it wasn't clear in your question. I believe you still must use the self-closing tag syntax (/>) for it work, though.

Is there a HTML helper that generates something like a label but with an ID attribute in MVC4?

I need to generate some html, that I can access later from Jquery to inject a value later on. On initial rendering, it should not show anything. I am using MVC4.
Maybe something like
Is there a HTML helper? or do I need to create my own? if so, how do I go about it?
Thanks
You just need to pass HtmlAttributes as parameters for the out-of-the-box MVC4 Helpers.
#Html.Label("", new { id = "yourID"})
But, maybe you just need a <span id="yourID"></span>
And you only need a helper for this, if you pretend to use it several times.
If you want to create an helper extension:
public static MvcHtmlString CustomLabel(this HtmlHelper helper, string labelId, string content = "")
{
var span= new TagBuilder("span");
span.Attributes.Add("id", labelId);
span.SetInnerText(content)
return MvcHtmlString.Create(span.ToString());
}
You could add another parameters to set CSS class or something like that.
Then, in your view you use it like this:
#Html.CustomLabel("yourID", "Initial Text")
EDIT: For strongly typed Html Helpers see this:
http://www.codeproject.com/Tips/389747/Custom-Strongly-typed-HtmlHelpers-in-ASP-NET-MVC
Any way, in your case, would just create one this way: #Html.CustomLabel(m=>m.YourID, "Initial Value") so that if you have the Initial Value in the model, you can do Model.InitValue instead of harcoding it like I did previously.

MVC Partial view with controller, ajax - how do I ge the partial controller to get data?

I'm learning MVC and am stumped by this. I'm trying to factor some common code that gets data and displays it in a WebGrid into a partial view that i can use on multiple pages.
My home controller Index method just does a return View(). The Home view looks like this:
#using (Ajax.BeginForm("SearchAction", "Search",
new AjaxOptions { UpdateTargetId = "data-grid", HttpMethod = "Post" }))
{
#Html.TextBoxFor(model => model.name)
<input type="submit" value="Search" />
}
#{
<div id="data-grid">
#Html.Partial("SearchResults", Model)
</div>
}
I'm trying to use Ajax to avoid losing my search form data when clicking a WebGrid pager link, which are rendered as normal links.
My SearchController looks like this:
public ActionResult SearchAction(string name)
{
return RedirectToAction("SearchResults", new { name = name });
}
public ActionResult SearchResults(string name)
{
//does database query and sticks results in the viewbag
//filter on optional name parameter
VieweBag.Members = MyQueryResults;
return PartialView();
}
My SearchResults shared view, data is passed in via ViewBag.Members:
#{
var grid = new WebGrid(null, rowsPerPage: ViewBag.Pagesize);
grid.Bind(ViewBag.Members);
#grid.GetHtml(// etc. etc.)
}
The results I'm getting is that the ViewBag.Pagesize and ViewBag.Members binding fails since there is no data in the viewbag. Obviously, my partial controller is not being called to do the initial query and put stuff in the ViewBag when the home page is first loaded. How do I make that happen?
The other weird thing is that if I just copy the database query code into my home controller (where it originally was) to force the original query, then if I put some text into the search field and do a search, the partial view renders by itself on a new page. Why is that happening, I thought it would only render as part of my home page.
I've cobbled this partial view together from various answers/places and have no doubt gotten something horribly wrong :\
The partial page won't pass through a controller, but simply render the view directly. If you want to pass view data to the partial view, there is an overloaded function that takes a viewdata dictionary. I'm sorry I can't be more detailed, but I'm on my mobile (waiting for my son to fall asleep in the other room) :)
Update:
If you want to trigger a GET action for your partial view, you can use Html.Action. Here are some useful links:
MSDN RenderAction
Difference between RenderPartial and RenderAction
Further, it would probably make sense for you to move your form tags into your partial view, but those are details for when you clean up the code.
Jonass is right, the ViewBag only propagates between the Controller and the View.
One thing you can do is make the model of the partial view be the same as the type of data you're putting into the ViewBag.
So if for example your MyQueryResults is of type:
IEnumerable<Result>
In your partial view you'd add
#Model IEnumerable<Result>
And then in the main view, you'd pass it through the Render method:
#Html.Partial("SearchResults", ViewBag.Members);
You'll need to tweak this a bit to make sure it's the right type, but this should do the trick.
Good luck!

Passing a GET parameter to ActionLink in ASP.NET

Sorry but I am new to C# and ASP.NET and I saw alot of posts about this problem but I quite didn't get it. I am trying to understand how to pass a GET parameter to an action thru HTML.ActionLink:
here is the the URL:
http://localhost:36896/Movies/SearchIndex?searchString=the
and my CSHTML page should look like this:
<input type="Text" id="searchString" name="searchString" />
#Html.ActionLink("Search Existing", "SearchIndex", new { searchString = "the"})
this hard coded parameter "the" is actually working, but how can I select the input element with id=searchString, with something like document.getElementById("searchString").value
Thanks,
If the value you want to send as GET parameter is not known on the server you cannot use the Html.ActionLink helper to add it. You need to use javascript to manipulate the existing link and append the parameter.
It looks like you have an input field that contains a search string and you want to send the value entered in this field to the server. A better way to handle this scenario is to use an HTML form with method="GET" instead of an ActionLink. This way you don't need to use any javascript - it's part of the HTML specification:
#using (Html.BeginForm("SearchIndex", "Movies", FormMethod.Get))
{
#Html.EditorFor(x => x.SearchString)
<button type="submit">Search</button>
}
Now when you click on the Search button the value entered in the SearchString field will automatically be sent to the SearchIndex action:
http://localhost:36896/Movies/SearchIndex?searchString=the
But if you absolutely insist on using an ActionLink you will have to write javascript to manipulate the href of the existing link when this link is clicked in order to append the value to the url. It's an approach I wouldn't recommend though because the HTML specification already provides you this functionality throughout HTML forms.
This makes the #Html.EditorFor refer to the Title field of the object, kinda in a random way but it works!
#using (Html.BeginForm ("SearchIndex", "Movies", FormMethod.Get))
{
#Html.EditorFor( x => x.ElementAt(0).Title)
<button type="submit">Search</button>
}
Still couldn't pass input parameter to the URL in the GET.
EDIT:
FINAL SOLUTION:
#Html.TextBox("SearchString")
<button type="submit">Filter</button>
and on the controller side, switch the input parameter. Basically it will automatically recognize the passed parameter.
public ActionResult SearchIndex(string searchString)
{
...
}

How to customize links for breadcrumbs widget for Yii?

How to customize links for breadcrumbs widget for Yii?
I can change the property tagName, but it for container. I want to change a tag for each links from a to li. How can I do it?
Well there's no setting/property value that you can specify for the default CBreadcrumbs widget class that will give you <li>. You can confirm this if you check out its run() method. In the source you can see this:
public function run(){
// code
foreach($this->links as $label=>$url)
{
if(is_string($label) || is_array($url))
$links[]=CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url);
else
$links[]='<span>'.($this->encodeLabel ? CHtml::encode($url) : $url).'</span>';
}
// more code
}
So what you'll have to do is extend this class and specify your own run method, where you can use <li> or CHtml::tag('li',//other options) instead of the default CHtml::link.
Edit:
Although i would suggest enclosing the <a> for each link with a <li> (instead of replacing it):
$links[]='<li>'.CHtml::link($this->encodeLabel ? CHtml::encode($label) : $label, $url).'</li>';
You can do that with 'activeLinkTemplate' and 'inactiveLinkTemplate' properties:
$this->widget('zii.widgets.CBreadcrumbs',
array('tagName'=>'ul',
'homeLink'=>'<li>'.CHtml::link('Home', array('/')).'</li>',
'activeLinkTemplate'=>'<li>{label}</li>',
'inactiveLinkTemplate'=>'<li class="active">{label}</li>',
'htmlOptions'=> array('class'=>'breadcrumb'),
'separator'=>' / ',
'links'=>$this->breadcrumbs,
));
Or U can write 'homeLink'=>false. But in this case U'll have to set Home url every time with $this->breadcrumbs.