question

AD-4372 avatar image
0 Votes"
AD-4372 asked AD-4372 answered

ASP.NET 6 Razor Pages, JavaScript, Post Data to Code-behind

Sorry about the long post. My background: I am relatively new to the HTML/Javascript world and have basic knowledge of ASP.NET Razor Pages but no real experience using it.

Problem statement: Consume a (HTML) Web Component containing a form having input text boxes from ASP.NET 6 Razor pages/views so as to make available in the Razor Pages code behind, the values entered into the text boxes of the form.

I tried putting together a working example (PoC) as follows:

Visual Studio 2022 Solution: Created using Microsoft's guidelines from here

In my working PoC I have the following:

A Razor page that consumes a web component (called "my-component"): Added a new Razor Page which I used as my test page, called TestMyComp, which resulted in 2 files getting created: TestMyComp.cshtml and TestMyComp.cshtml.cs.

TestMyComp.cshtml:

 @page
 @Html.AntiForgeryToken()
 @model RazorWebApp.Pages.TestMyCompModel
    
 <h2>Test My Web Component!</h2>
    
 <form method="post" id="myform">
     <my-component id="myco"></my-component>
     <script src="../js/mycomponent.js"></script>
    
     <input hidden asp-for="BoundCredentialsModel!.UserName" id="myUsername"/>
     <input hidden asp-for="BoundCredentialsModel!.Password" id="myPass"/>
 </form>
    
 @section Scripts
 {
     <script type="text/javascript" language="javascript">
    
         const mycomp = document.getElementById('myco');
         mycomp.addEventListener('mycomp-submit', (e) => loginButtonClickedHandler(e));
    
    
         function loginButtonClickedHandler(e) {
             var username = e.detail.username;
             var pass = e.detail.password;
    
             document.getElementById('myUsername').value = username;
             document.getElementById('myPass').value = pass;
             document.getElementById('myform').submit();
    
         }
     </script>
 }


(Snipped) TestMyComp.cshtml.cs:

     public void OnGet()
     {
     }
    
     [BindProperty]
     public Credentials? BoundCredentialsModel { get; set; }
    
     public IActionResult OnPost()
     {
         if (!ModelState.IsValid)
         {
             return new JsonResult(".Error.");
         }
    
         return new JsonResult("Received in server: UserName = " + BoundCredentialsModel?.UserName + 
 ``", pass = " + BoundCredentialsModel?.Password);
     }


The Web Component contains a form with a few input text boxes and a submit button - in my PoC I have a username & a password input box and a submit button. After the username and password are entered I would like their values to be available in my code behind, i.e. in TestMyComp.cshtml.cs.

For this I made use of Razor's [BindProperty] on the code behind. Following is my flow:

  1. User enters username and password and presses the Submit button. This is happening in the web component.

  2. Web component fires an event after the Submit button is pressed

  3. In my Razor page i.e. TestMyComp.cshtml, where I have hosted the web component in a form, I am subscribed to the aforementioned event, so I receive it along with a payload that contains the username/password keyed in by the user.

  4. In TestMyComp.cshtml I also have 2 hidden input boxes, one each for username and password. In the event handler for the event, where the event's payload contains the username and password, I programmatically fill in the values of these two hidden boxes (this is the code behind's bound property) and also programmatically call submit on the form.

If it helps, here is a diagram with approximations to illustrate the flow: diagram243836-screenshot-2022-09-22-153609.png

This makes the username and password values available to me in the code behind (in the OnPost method). My question is, as far as the Razor (.cshtml and .cshtml.cs) code is concerned, have I done it right? Is there any better way of achieving this (i.e. is there a better solution)?


dotnet-aspnet-core-general
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

In my opinion the design is overly complicated. You could remove the JavaScript and submit the user's inputs rather than copying the values from on input to another within the same form element.

Does the code actually function as expected because the OnPost returns JSON. Usually JSON is returned to an AJAX request made by JavaScript.

I'm not sure if you know this but the component no longer exists when viewed in the browser. A component is a server side construct and when returned to the browser it is just HTML within the page.

0 Votes 0 ·

@AgaveJoe

You mentioned: "You could remove the JavaScript and submit the user's inputs".
How would I submit the inputs? Note that the web-component is written by a different team and I am a consumer of it. I am only aware of the "interface" it exposes i.e. the event that it fires to which I am subscribed.

"Does the code actually function as expected"?
Yes


"I'm not sure if you know this but the component no longer exists when viewed in the browser. A component is a server side construct and when returned to the browser it is just HTML within the page."
By "component" what are you referring to? <my-component id="myco"></my-component> OR TestMyComp? In any case I am aware of what you are saying.

Thanks a lot.

0 Votes 0 ·

How would I submit the inputs? Note that the web-component is written by a different team and I am a consumer of it. I am only aware of the "interface" it exposes i.e. the event that it fires to which I am subscribed.

The design is redundant because it copies input values to hidden fields which are in the same HTML form as the inputs. The browser submits every input with an HTML form.

By "component" what are you referring to? <my-component id="myco"></my-component> OR TestMyComp? In any case I am aware of what you are saying.

Both. my-component and TestMyComp are combined together on the server and returned to the browser as a single page.




0 Votes 0 ·
Bruce-SqlWork avatar image
0 Votes"
Bruce-SqlWork answered

your web components are javascript controls. that render the html and fire javascript events.

you need the designers of the components to answer these questions:

  • does it generate a <form>, if so it can not be nested in another form

  • does it support inclusion in a <form>. does it have any named inputs that would be included in the form post. if so these should be defined in the support docs.

  • does it have a hide / destroy support (client re-render)

if the component supports form posts, then you should map the names to the page model, and just do a form.submit() on the event.


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AD-4372 avatar image
0 Votes"
AD-4372 answered

Thank you @AgaveJoe and @Bruce-SqlWork.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.