rustrust-rockethtml-templates

How to pass a Rust function to onclick inside html button tag?


I want to pass a Rust function for the onClick in my button tag. I know how to pass a variable but not a function. Below is my Rust file where I call the routes:

use rocket_dyn_templates::{context, Template};
use serde::Serialize;

#[derive(Serialize)]
struct Context {
    prompt: String,
}

#[macro_use]
extern crate rocket;

fn submit(prompt: String) {
    println!("value is {prompt}");
}

#[get("/")]
fn index() -> Template {
    let prompt: String = "".to_string();
    Template::render("index", context! { field: prompt })
}

#[launch]
fn rocket() -> _ {
    rocket::build()
        .mount("/", routes![index])
        .attach(Template::fairing())
}

My html file:

<head>
  <style type="text/css">
    <title>Generator Image</title>body {
      background: #1a6875;
      font-family: Arial, Helvetica, sans-serif;
    }

    .container-prompt {
      height: 10em;
      display: flex;
      align-items: center;
      justify-content: center;
    }

    .submit-prompt {
      margin: 0;
    }
  </style>
</head>

<body>
  <div class="container-submit">
    <div class="submit-prompt">
      <input method="text" name="prompt" id="prompt"/>
      <button onClick="">Submit</button>
    </div>
  </div>
</body>

At the end, I would like to use the variable prompt used in the input tag on the Rust function as a parameter when the button is clicked.


Solution

  • One possibility is creating a new route for the submit button.
    The implementation would be something like this:

    struct Prompt(String);
    
    #[rocket::async_trait]
    impl<'r> FromRequest<'r> for Prompt {
        type Error = rocket::http::uri::error::Error<'r>;
        async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
            let query = request.uri().query().unwrap();
            println!("{:?}", query);
    
            let query_segments: Vec<_> = query.segments().collect();
    
            let mut prompt: Option<String> = None;
            for segment in query_segments {
                if segment.0 == "prompt" {
                    prompt = Some(segment.1.to_string());
                    break;
                }
            }
    
            Outcome::Success(Prompt(prompt.unwrap_or_default()))
        }
    }
    
    #[get("/submit")]
    fn submit(prompt: Prompt) -> String {
        println!("value is {}", prompt.0);
        format!("Hello {}", prompt.0)
    }
    
    

    Then, instead of using the onclick function, you could do:

        <div class="submit-prompt">
            <input method="text" name="prompt" id="prompt" onchange="prompt()"/>
            <a href="/" id="anchor">
                <button>Submit</button>
            </a>
        </div>
    

    The prompt function would be (You can include it in the head, just below the closing style tag):

        <script>
            function prompt() {
                let prompt = document.getElementById('prompt');
                let anchor = document.getElementById('anchor');
                anchor.href = "/submit?prompt=" + prompt.value;
            }
        </script>
    

    Basically, what this does is create a new handler for any GET request to the route "/submit." If there is a request to the submit route, then it will retrieve the prompt query from the request (for example, if the uri "/submit?prompt=hello" is requested, then the prompt will be "hello") and displays them both to the console and to the client. The javascript retrieves the prompt text and anchor tag, and sets the anchor tag's link to be "/submit?prompt=input_value" so that the submit button will go to the right place.


    Hopefully, this cleared things up...happy coding!!!!