Asp.Net Razor Pages OnClick not firing - asp.net-core

I have this Button in my Index.cshmtl
<button value="Search" name="Search" submit="Search" class="searchbutton" onclick="btnSearch_Click">Search</button>
this Button sends a post when clicked.
In my Index.cshtml.cs I have this boolean variable and function
private bool SearchButton;
protected void btnSearch_Click(object sender, EventArgs e)
{
SearchButton = true;
}
So my problem is that, if I click the Button the code will never enter the btnSearch_Click function

You can use a named handler method in Razor Pages to emulate a server-side event handler in Web Forms.
Here's a content page:
#page
#model RazorPagesDemo.Pages.HandlerDemoModel
#{
}
<p>#Model.Message</p>
<form asp-page-handler="Search" method="post">
<input type="text" asp-for="SearchTerm" />
<button class="btn btn-default">Search</button>
</form>
And here's the PageModel:
public class HandlerDemoModel : PageModel
{
[BindProperty]
public string SearchTerm { get; set; }
public string Message { get; set; }
public void OnPostSearch()
{
Message = $"You searched for {SearchTerm}";
}
}
OnPostSearch is the equivalent to your btnSearch_Click method. You use the asp-page-handler attribute to wire your form up to execute that method. You can read more about Razor Pages handler methods here: https://www.learnrazorpages.com/razor-pages/handler-methods

Related

Razor pages view renders original form value instead of modified when reshown

Moving from ASP.NET Core MVC to Razor pages, there must be an issue in my understanding of passing data to a Razor view.
Here's a simple view:
#page
#model TestModel
#{
System.Diagnostics.Debug.WriteLine(Model.Name);
}
<form class="form-horizontal" method="get">
Name: <input type="text" class="form-control" asp-for="Name">
<button type="submit" class="btn btn-default">Send...</button>
</form>
And here is the view model class with one event handler:
public class TestModel : PageModel
{
[BindProperty(SupportsGet = true)]
public string Name { get; set; } = "";
public TestModel() {}
public IActionResult OnGet()
{
Name += "N";
return Page();
}
}
Then running the project:
Debug.WriteLine shows "N" as expected
input fields has "N" default value as expected
overwrite "N" in the input field eg. to "A" then press Send button
Debug.WriteLine shows "AN" as expected so view has got the value modified by OnGet()
the input field in the page itself contains the value "A" instead of "AN", the generated HTML contains:
value="A"
View does not render the modified Model.Name value but the original from the form data.
How can it be corrected to make view to render the modified string?
You can try to add ModelState.Clear(); in OnGet handler.When binding data in client side,it will get value from ModelState prior to Model.
public class TestModel : PageModel
{
[BindProperty(SupportsGet = true)]
public string Name { get; set; } = "";
public TestModel() {}
public IActionResult OnGet()
{
Name += "N";
ModelState.Clear();
return Page();
}
}

Razor Pages Custom Tag Helper 2 Way Bind

I am wanting to create a custom tag helper in razor pages which binds to a custom model but the value is not being read back into the modal on post, below is my TagHelper code
[HtmlTargetElement("kenai-date", TagStructure = TagStructure.WithoutEndTag)]
public class Date : TagHelper
{
//public string Value { get; set; }
public ModelExpression AspFor { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "input";
output.TagMode = TagMode.SelfClosing;
output.Attributes.Add("value", this.AspFor.Model);
}
}
I am using the TagHelper with the below code
<kenai-date asp-for="DateValue" />
'DateValue' is a public property on the page, when first rendering the page the value of DateValue is correctly visible in the TagHelper Input element, if I force an OnPost, the value is removed.
I have applied the same to a standard input element with asp-for set and that works fine so suspect I am missing something in my TagHelper.
Asp.net core bind model data with name attribute.You use a custom tag helper,so it will get html like <input value="xxx">.So when form post,you cannot bind model data with name attribute,and when return Page in OnPost handler,model data is null.You need to add name attribute to <kenai-date asp-for="DateValue" />.Here is a demo:
TestCustomTagHelper.cshtml:
<form method="post">
<kenai-date asp-for="DateValue" name="DateValue" />
<input type="submit" />
</form>
TestCustomTagHelper.cshtml.cs:
public class TestCustomTagHelperModel : PageModel
{
[BindProperty]
public string DateValue { get; set; }
public void OnGet()
{
DateValue = "sss";
}
public IActionResult OnPost()
{
return Page();
}
}
result:

Why tempdata attribute retain after first read?

It spose that tempdata read once and disposed and that was ok before using it as attribute now when using it like attribute it retain to next request after read for first time
here is my sample code
Page A
public class AModel : PageModel
{
[TempData]
public string Message { get; set; }
public void OnGet()
{
Message = "test Page A";
}
}
<h1>A</h1>
<p>#Model.Message</p>
<a asp-page="b">Page B</a>
Page B
public class BModel : PageModel
{
[TempData]
public string Message { get; set; }
public void OnGet()
{
}
}
<h1>B</h1>
<p>#Model.Message</p>
<a asp-page="A">Page A</a>
when navigating from page A to page b it should not showing the message from page A but i got the message appear in page B the result look like that
B
test Page A
Page A
when navigating from page A to page b it should not showing the message from page A
If you do a test with following code, you would easily find that the code snippet #Model.Message in A.cshtml does not read TempData value.
<h1>A</h1>
using TempData["Message"]: <p>#TempData["Message"]</p>
<hr />
using Model.Message: <p>#Model.Message</p>
<hr />
using TempData.Peek("Message"): <p>#TempData.Peek("Message")</p>
<hr />
using Model.Message: <p>#Model.Message</p>
<a asp-page="b">Page B</a>
The output of above testing
And as mentoned about TempData in this doc:
This property stores data until it's read in another request.

asp-for tag helper not writing to field

The asp-for tag does not write to my field, if I set received_text with text it will show up in the web page.
The form does send the data but received_text is always blank.
CS:
public class IndexModel : PageModel
{
public string received_text;
public void OnGet()
{
Console.WriteLine("Text received = " + received_text);
}
}
CShtml:
#page "/"
#model WebApplication2.HomePage.IndexModel
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<p>Send text</p>
<form action="/" method="get">
<input asp-for=received_text />
</form>
<p>#Model.received_text</p>
You must have the BindProperty attribute applied, and it must be a property, not a field:
[BindProperty]
public string received_text { get; set; }

How do I convert a razor page with an injection to a code-behind?

I'm modifying a blazor example from [Blazor Tips and Tricks][1]
[1]: https://www.youtube.com/watch?v=3duXMxwnkXI starting at the 17 minute mark.
If you create a new Blazor App named BlazorCounter in Visual Studio, and modify the generated Counter.razor to look like this:
#page "/counter"
#inject Data.CounterState State
<h1>Counter</h1>
<p>Current count: #State.CurrentCount</p>
<button class="btn btn-primary" #onclick="IncrementCount">Click me</button>
#code {
void IncrementCount()
{
State.CurrentCount++;
}
}
Then add the following c# class to the Data folder
namespace BlazorCounter.Data
{
public class CounterState
{
public int CurrentCount { get; set; }
}
}
Finally add this line at the end of the ConfigureServices method of Startup class:
services.AddScoped<CounterState>();
Then you have a counter which preserves its state and doesn't start at zero every time you navigate to the Counter page.
My question is: How do I convert this to 'code-behind' and separate the C# code?
I've converted other razor pages to 'code-behind', but don't see how to handle the #inject line.
Create a Base class and inject the service with an [InjectAttribute]:
public class MyCounterComponent : ComponentBase
{
[Inject]
public virtual CounterState State { get; set; }
protected void IncrementCount()
{
State.CurrentCount++;
}
}
I also move your IncrementCount() method from the view file to this class file.
And now you can use it with a #inherits directive:
#page "/counter"
#inherits BlazorApp1.Pages.MyCounterComponent
<h1>Counter</h1>
<p>Current count: #State.CurrentCount</p>
<button class="btn btn-primary" #onclick="IncrementCount">Click me</button>
For more details, see Request a service in a component and Use DI in services