How to get the current Action name inside the View - c#

In my _Layout page, I have got a search form and each controller has an index view. When the user clicks the search button, it searches in the current index view.
I want to show the search field if the user is index view if they go to other views, I wanted to hide it.
In my _Layout
<form asp-action="Index" method="get" class="navbar-form form-inline navbar-right">
<input class="form-control mr-sm-2" id="search" name="search" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" id="BtnSearch" name="BtnSarch" type="submit">Search</button>
</form>
I am using JQuery at the moment but it is quite difficult to put every single view
$("#search").hide();
$("#BtnSearch").hide();
Basically, in my _Layout page, I wanted to show or hide Search form if the user is in the index view.
how can i get current view name in _Layout view, please?

Basically, in my _Layout page, I wanted to show or hide Search form if the user is in the index view.
Try with below codes :
#if ("Index".Equals(ViewContext.RouteData.Values["Action"].ToString()))
{
<form asp-action="Index" method="get" class="navbar-form form-inline navbar-right">
<input class="form-control mr-sm-2" id="search" name="search" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" id="BtnSearch" name="BtnSarch" type="submit">Search</button>
</form>
}

This sounds like it is the ideal candidate for mvc tag helpers.
You will need to create a class which inherits from TagHelpers and override the process method.
[HtmlTargetElement(“website-search”)]
Public class Search : TagHelper
{
Public WebsiteContext Info { get; set; }
Public override void Process(TagHelperContext context, TagHelperOutput output)
{
Output.TagName = “section”;
Output.Content.SetHtmlContent(“ HTML for your search form “);
Output.TagMode = TagMode.StartTagAndEndTag;
}
}
In order to get the controller and action you will need to add a property to the tag helper:
[HtmlAttributeNotBound]
[ViewContext]
Public ViewContext ViewContext { get; set; }
Now that you have the view context in place, you can look to do something like the following:
If(ViewContext.RouteData.Values[“action”]) != “Index”)
{
Output.SuppressOutput();
}
You can then reference this by putting website-helper in your view.
Please see the following link for an intro on tag helpers https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro?view=aspnetcore-2.2
There is the following stack overflow question detailing how to get the controller and action executed against : Knowing what route the user is on inside TagHelper in .NET Core
Hope this helps

You can add a hidden input to layouts file and assign to it an id.
Then you can get action and controller name from anywhere:
<input type="hidden" value="#this.ViewContext.RouteData.Values["action"].ToString()" />
<input type="hidden" value="#this.ViewContext.RouteData.Values["controller"].ToString()" />
So if you don't use them in JS, you can declare a variable and show your form when action is Index.
Hope to help.

If you want to show the search form only in specific views, I would not base this on the view name. In the future, you might also need it in other views. So, why not simply add a flag to show the search form to your ViewBag. It will mean, setting this flag in every "Index" action, but you will be more flexible with where to show it.
Controller:
public ActionResult Index()
{
this.ViewBag.ShowSearch = true;
// … your normal code
return this.View();
}
_Layout.cshtml
#if (this.ViewBag.ShowSearch == true) // explicitly check for true, so not having set the flag in the ViewBag will not pose a problem, i.e. null != true.
{
<form action="">#* … *#</form>
}

Related

ViewModel becomes null after creating a POST request in ASP.NET MVC

I'm creating an edit user page which will modify a user's existing role name within the web app. However, upon POST request, the Edit's view model becomes null after containing the values from the form (checked this using breakpoints).
I then get a prompt message in Visual Studio saying:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Microsoft.AspNetCore.Mvc.Razor.RazorPage\<TModel\>.Model.get returned null.
UserController.cs
[HttpPost]
public async Task<IActionResult> Edit(IFormCollection formCollection)
{
try
{
await _userControllerService.EditAzureUser(formCollection);
return RedirectToAction(nameof(Index));
}
catch
{
return View();
}
}
UserControllerService.cs
public async Task EditAzureUser(IFormCollection formCollection)
{
string id = formCollection["User.PrincipalId"];
string appRoleId = formCollection["User.AppRoleId"];
//Edit logic here
}
Edit.cshtml
#model CreateUserViewModel
#{
ViewData\["Title"\] = "Edit User";
}
<label asp-for="User.PrincipalDisplayName" class="col-form-label">Name: </label>
<input asp-for="User.PrincipalDisplayName" value="#Model.User.PrincipalDisplayName" readonly class="form-control"/>
<label class="col-form-label">Role: </label>
<select asp-for="User.AppRoleName" title="Select Role" required class="form-control" style="margin-bottom: 1rem"/>
#{
foreach(var role in AppRole.Roles)
{
if(Model.User.AppRoleName == role)
{
<option value="#role" selected>#role</option>
} else
{
<option value="#role">#role</option>
}
}
}
<input type="hidden" asp-for="User.AppRoleId"/>
<input type="button" value="Cancel" class="btn btn-secondary btn-sm" onclick="goBack()" />
<input type="submit" class="btn btn-info btn-sm" />
Your POST method doesn't return a model to the view, but the view expects a non-null CreateUserViewModel, which it uses in the markup. My guess is that's why you're getting the NRE.
However, if the POST was successful, why are you going back to the edit page anyway? Either send them to another page (often a user list if this is an admin facility, or a "thank you page if it's for the users themselves), or modify the Razor in this view to show a message saying the edit was successful. Either way, you don't need the model.

Calling ActionResult from PartialView never hits

Pretty new with MVC and going through a few tutorials. Have done the following:
Add a controller called CustomerController.
Add 2 methods
public ActionResult Render()
{
// Go to a third party WebAPI and get the results in a List
return PartialView("CustomerList", custList);
}
public ActionResult SomeTest()
{
Response.Redirect("Somepage");
}
I then add a page (LandingView.cshtml) and create a PartialView called CustomerList and add the below code to the LandingView page
#Html.Action("Render", "Customer")
When i view this page it renders the page with a list of customers. The HTML for the PartialView is
#using (Html.BeginForm("SomeTest", "Customer"))
{
<div class="container">
#foreach (var i in Model)
{
<a href="#i.Url">
<div class="product-grid__item__name">#i.Title</div><br />
<div class="product-grid__item__price">#i.Price.ToString("C")</div>
</a>
<input type="button" id="btnGo" value="Go" />
}
</div>
}
When i click the button it never hits the SomeTest method? In debug mode i have put a breakpoint on Render and SomeTest, Render hits on page load but when clicking Go it never hits the SomeTest method?
What am i missing here?
Set the 'type' attribute value of the input element to "submit" not "button". This will trigger the form submission on click.
<input type="submit" id="btnGo" value="Go" />
You may experience some build errors because the SomeTest() controller method is expecting a return value of type ActionResult.

Passing input value to a controller method, not the whole model in Asp.Net Core 3

I have a ToDo items dashboard page where I display the ToDo's, their status and some other app info.
I want to have one input where I can add a string value (the ToDo title) and on the button click
have that passed to the controllers Create get method, so it populates the Create views Title input field with that value.
I want to it without a form if that is possible as the dashboard page already has a model which is an IEnumerable, just pass that value as a querystring parameter to the Create pages get view (or is it doable in javascript?).
Im not an MVC expert and also not as familiar with the new tag helper methodologies. Any help in how to structure thiswould be helpful.
Here is the html
<!-- Add Task -->
<div class="input-group input-group-lg">
<input class="form-control" type="text" placeholder="Add task and press enter..">
<span class="input-group-addon">
<a asp-controller="ToDoItems" asp-action="Create" ><i class="fa fa-plus"></i></a>
</span>
</div>
<!-- END Add task -->
here is the new model
public Class MyModel{
public IEnumerable<your old model> Old Model {get; set;}
public string Title {get;set;}
}
You can create a form like so in html with razor syntax
#model MyModel
...
<form action="/Controller/PostTitle/" method="post">
#Html.TextBoxFor(m => m.Title,new {#class = "...", #placeholder="...",
#requried="required"})
<input id="export-btn" type="submit" value="Download" class="btn btn-info" />
</form>
The #TextBoxFor will create a textbox and the lambda lets you use your strongly typed model.
Here is the controller
[HttpPost]
public IActionResult PostTitle(string Title) {
...
}

How do i send data to asp.net controller so that it can return a view?

What I want to do is so simple, I'm still trying to learn ASP.NET with c# and MVC application but I'm just having a lot of difficulty getting a simple example to go through, then I can grow from it, here's how it goes: I have a simple html5 form that's method is GET, the type is text and I basically want to submit a text into my mvc controller, once my controller get's it, I want it to output that string 'worked' through HTML5, how do I do this?
summary: string 'worked' --> html form --> c# controller --> html (view?)
here's what I got for my 'view' (Search.cshtml)
<form action="Home/Search" method="get">
<input type="text" name="q" />
<input type="submit" value="Search" />
ok, so far so good, if I input 'worked' nothing is going to happen unless I add more code, here's c# (HomeController.cs):
public ActionResult Search(string q)
{
return this.View(q?); // so what exactly is View(q)? what is view returning? }
okay so this is where I am confused, does my string go through and become stored in 'q'? and if so, how do I get this thing to use HTML5 to output something like
<p> q </p> <!-- q = 'worked' -->
In your controller, you are calling the View(...) method incorrectly. The View(...) method expects the string parameter you're passing to be the path to the razor view you're trying to render.
A quick and simple way to pass the q variable from your controller to a view to be rendered is using ViewBag.
If you have a razor view named /Views/Search.cshtml you would do:
public class MyController : Controller
{
public ActionResult Search(string q)
{
ViewBag.Query = q;
return View("~/Views/Search.cshtml");
}
}
Then in /Views/Search.cshtml use it like this:
<p>#ViewBag.Query</p>
If you are using asp.net mvc, then please follow mvc pattern like this ..
View
#using (#Html.BeginForm("Search","Home",FormMethod.Post))
{
<b>Name : </b>
#Html.TextBox("searchTerm", null, new { #id = "txtSearch" })
<input type="submit" value="Search" />
}
Controller
[HttpPost]
public ActionResult Search(string searchTerm)
{
return View(searchTerm);
}
}
Search.cshtml
<form action="/Home/Search" method="get">
<input type="text" name="q" />
<input type="submit" value="Search" />
</form>
<p class='current-query'>#Model</p>
HomeController.cs
public ActionResult Search(string q)
{
return View((object)q); // return the model to the view (a string)
}

Passing data to a Controller method via POST

I have a 'Survey' page which is declared as follows:
#using (Html.BeginForm("Survey", "Home", new { questionList = Model.Questions }, FormMethod.Post))
{
<div class="survey">
<ol class="questions">
#foreach (Question q in Model.Questions)
{
<li class="question" id="#q.QuestionName">
#q.QuestionText<br />
#foreach (Answer a in q.Answers)
{
<input class="answer" id="#a.DisplayName" type="checkbox" /><label for="#a.DisplayName">#a.AnswerText</label>
if (a.Expandable)
{
<input type="text" id="#a.DisplayNameFreeEntry" maxlength="250" /> <span>(250 characters max)</span>
}
<br />
}
</li>
}
</ol>
</div>
<div class="buttons">
<input type="submit" value="Finish" />
</div>
}
When I'm stepping through my code, it hits the method I've set up to process their survey:
[HttpPost]
public ActionResult Survey( List<Question> questionList, FormCollection postData)
{
//Process Survey
}
However, when I step through I am finding that the variable questionList is null and the variable postData does not contain any data from the Form. Trying to access checkboxes via Request[a.Displayname also does not work.
Everything I've read indicates that this is the correct way to persist values from the Model to the submission method, and that I should be able to access the FormCollection this way.
What am I doing wrong?
You have to save questionList as a hidden field on the page. Non-primitive types do not get persisted simply by passing them in.
One way you can do that is
#Html.HiddenFor(m => m.Foo)
Or you could do it directly in HTML like this
<input type="hidden" name="Var" value="foo">
where m is your model.
The fact that the postData is empty is weird, since every input element with id inside a form tag should be passed with the POST request.
But the questionList won't be received that way, since its a list of complex class (not just a string or int), and the default ModelBinder (the thing that turns the HTTP Request Variables into parameters passed to the action method) don't support lists of complex classes.
If you want to be able to receive List you will have to implement your own binding mechanism with CustomModelBinder.
This article can help you implement it.
One problem is your checkbox and your textbox are not properly bound to your model.
You should be using #Html.CheckBoxFor and #Html.TextBoxFor

Categories

Resources