Hot questions for Using Vapor in html

Question:

I am developing a web app with Swift 4 and Vapor 2.0. I have a method for a POST request which creates a new user:

builder.post("user", "createUser") { (request) -> ResponseRepresentable in

But I don't know how to add action for button in the .leaf file to call the createUser method. It easy to add a JavaScript action in a .html file, like that <script src="js/index.js"></script>. But with Vapor, I didn't see any mention about that in the Vapor 2.0 docs

Update:

With help from @Caleb Kleveter, now it worked. I updated html page(it's just for test, so that it's not a nice page) with hope: it'll help for newcomer whom face with the same problem when use vapor.

Here is my HTML contents:

    <!DOCTYPE html>
<html >
    <head>
        <meta charset="UTF-8">
            <title>Responsive Login Form</title>


            <link rel='stylesheet prefetch' href='http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css'>

                <link rel="stylesheet" href="styles/app.css">


                </head>

                <body>
                <link href='https://fonts.googleapis.com/css?family=Ubuntu:500' rel='stylesheet' type='text/css'>
                <h3>
                <form action="/user/createUser" method="POST" class="login-form">
                <label for="username">Username:</label>
                <input type="text" placeholder="Username" name="username"/>
                <label for="password">Password:</label>
                <input type="password" placeholder="Password" name="password"/>
                <input type="submit" value="Login" class="login-button"/>
                <form>
                </h3>
                <a class="sign-up">Sign Up!</a>
                <br>
                <h6 class="no-access">Can't access your account?</h6>
                </div>
                </div>
                <!-- <div class="error-page">
                    <div class="try-again">Error: Try again?</div>
                </div> -->
                <script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
                    <script src='http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js'></script>

                    <script  src="js/index.js"></script>

            </body>
</html>

Answer:

Scripts can be added to a .leaf file the same way as you would in HTML, just add a script tag:

<script src="js/index.js"></script>

From viewing your code, what you want is a form to post the data to the server. You should replace your .login-form div with a form element:

<form action="/create-user" method="POST" class="login-form">
    <label for="username">Username:</label>
    <input type="text" placeholder="Username" name="username"/>
    <label for="password">Password:</label>
    <input type="password" placeholder="Password" name="password"/>
    <input type="submit" value="Login" class="login-button"/>
<form>
<a class="sign-up">Sign Up!</a>
<h6 class="no-access">Can't access your account?</h6>

Here is the documentation for HTML forms.

Then you should be able to access the form data in you route method with request.body:

func createUser(req: Request) throws -> ResponseRepresentable {
    guard let password = req.body["password"]?.string,
          let username = req.body["username"]?.string else {
             throw Abort.badRequest
    }

    // The rest of your code goes here
}

I am not sure if this will work, I haven't tested it, but I think you get the idea.

Question:

I am working on a very simple Vapor app. I am currently working on one of the views:

#extend("base")

#export("body") {
    <form>
        <div class="row">
                <div class="six columns">
                    <label for="exampleEmailInput">Acronym</label>
                    <input class="u-full-width" type="email" id="short">
                    </div>
                <div class="six columns">
                    <label for="exampleRecipientInput">Long form</label>
                    <input class="u-full-width" type="email" id="long">
                </div>
        </div>
    </form>
    <div class="row">
        <div class="five columns"></div>
            <div class="two columns">
                <a class="button button-primary" id="submit" href="/acronym/all">Save Acronym</a>
            </div>
        <div class="five columns"></div>
    </div>
    <script>
        function setHref() {
            var short = $("#short").val();
        }
    </script>
}

This code works until I add the short variable to the setHref function. Then I get a parsing error:

Uncaught Error: ParseError.tagTemplateNotFound("short\").val"). Use middleware to catch this error and provide a better response. Otherwise, a 500 error page will be returned in the production environment.

Why is this happening?


Answer:

Leaf is finding #short and parsing it as a tag. My guess is you're looking for some type of escaping mechanism. Here's some options:

#()short => #short
#raw() { #short } => #short

Question:

I'm using vapor framework and created a table with longText type in mysql & store text with html tags in it,

+----+----------------------+
| id |       content        |
+----+----------------------+
|  1 | <b>title</b>sometext |
+----+----------------------+

now when i show them in leaf, it's shows with html tags like:

<b>title</b>sometext

My Leaf file: but i want to show like:

title sometext

how can i do this? thanks


Answer:

Try something like

<pre class="item-body-text-pre">#raw(post.content)</pre>

You can use #raw(<yourVariableHere>) to insert unescaped text.

Question:

I am making a post request to a server with an HTML form. When I press the submit button for the form I get a 404 page does not exist error. However, if I go to the URL through directly typing in the address bar, I get the error I should be getting from the server (400 invalid request).

Here is my HTML (note I am using leaf):

#extend("base")

#export("head") {
    <link rel="stylesheet" href="/styles/normalize.css">
    <link rel="stylesheet" href="/styles/skeleton.css">
}

#export("body") {
    <div class="container">
        <form action="/admin/new-post" method="POST">
            <div class="row" style="padding: 25px 0 0 0;">
                <div class="six columns form-group">
                    <label for="email">Usernam</label>
                    <input class="u-full-width" type="text" placeholder="Username" id="email" name="email">
                </div>
                <div class="six columns form-group">
                    <label for="password">Password</label>
                    <input class="u-full-width" type="password" placeholder="Password" id="password" anem="password">
                </div>
            </div>
            <input type="hidden" name="_csrf" value="{{csrfToken}}">
            <button type="submit" class="button-primary">Login</button>
        </form>
    </div>
}

And my server code (Swift):

import Vapor
import HTTP

final class AdminController {

    func addRoutes(to drop: Droplet) {
        let admin = drop.grouped("admin")
        drop.get("login", handler: login)
        admin.get("new-post", handler: newPost)
    }

    func login(_ request: Request)throws -> ResponseRepresentable {
        return try drop.view.make("admin-login", [])
    }

    func newPost(_ request: Request)throws -> ResponseRepresentable {
        guard let cred = request.auth.header?.basic else {
            throw Abort.badRequest
        }
        do {
            try request.auth.login(cred)
            return try drop.view.make("new-post", [])
        } catch {
            return Response(redirect: "/login?login=failed")
        }
    }
}

Why am I getting a 404 error?

The web framework I am using is Vapor.


Answer:

So, have a look at your droplet, you add a new route with a GET-Request new-post but your form try POST to new-post, for sure that will fail.

Try to change

admin.get("new-post", handler: newPost)

to

admin.post("new-post", handler: newPost)