2

I have a couple of major gaps in my understanding of vapor/leaf/html. I am working from the "todo" example that is created using the beta branch of vapor.

First, I made my own fluent model (no problems that I know of):

import FluentSQLite
import Vapor
final class affordatmodel: SQLiteModel {
    var id: Int?
    var propertyCost: String
    var targetEquity: String
    var interestRate: String
    var amortization: String
    var sponsor1: String
    var sponsor2: String
    var rent: String
    var rentInflation: String
    var propertyTaxes: String
    var propertyTaxesInflation: String
    var strataFees: String
    var strataFeesInflation: String
    init(propertyCost: String, targetEquity: String, interestRate: String, amortization: String, sponsor1: String, sponsor2: String, rent: String, rentInflation: String, propertyTaxes: String, propertyTaxesInflation: String, strataFees: String, strataFeesInflation: String) {
        self.propertyCost = propertyCost
        self.targetEquity = targetEquity
        self.interestRate = interestRate
        self.amortization = amortization
        self.sponsor1 = sponsor1
        self.sponsor2 = sponsor2
        self.rent = rent
        self.rentInflation = rentInflation
        self.propertyTaxes = propertyTaxes
        self.propertyTaxesInflation = propertyTaxesInflation
        self.strataFees = strataFees
        self.strataFeesInflation = strataFeesInflation
    }
}
/// Allows to be used as a dynamic migration.
extension affordatmodel: Migration { }
/// Allows to be encoded to and decoded from HTTP messages.
extension affordatmodel: Content { }
/// Allows to be used as a dynamic parameter in route definitions.
extension affordatmodel: Parameter { }

Then I make an instance and send it to a leaf template:

let defaultData = affordatmodel(propertyCost: "700000", targetEquity: "300000", interestRate: "1", amortization: "20", sponsor1: "500000", sponsor2: "200000", rent: "1200", rentInflation: "1", propertyTaxes: "8000", propertyTaxesInflation: "1", strataFees: "0", strataFeesInflation: "0")
return leaf.render("welcome", ["affordat": defaultData])

And my Leaf template successfully populates the html with the default data (body shown here):

<body class="container">
    <h1>Payment and Principal Calculations</h1>

    <form action="/affordat" method="POST">
        <div class="form-group">
            <label for="propertyCost">Property Cost</label>
            <input type="number" class="form-control" name="propertyCost" placeholder="#(affordat.propertyCost)">
                </div>
        <div class="form-group">
            <label for="targetEquity">Target Equity</label>
            <input type="number" class="form-control" name="targetEquity" placeholder="#(affordat.targetEquity)">
                </div>
        <div class="form-group">
            <label for="interestRate">Interest Rate</label>
            <input type="number" class="form-control" name="interestRate" placeholder="#(affordat.interestRate)">
                </div>
        <div class="form-group">
            <label for="amortization">Amortization (years)</label>
            <input type="number" class="form-control" name="amortization" placeholder="#(affordat.amortization)">
                </div>
        <div class="form-group">
            <label for="sponsor1">Sponsor 1 Funds</label>
            <input type="number" class="form-control" name="sponsor1" placeholder="#(affordat.sponsor1)">
                </div>
        <div class="form-group">
            <label for="sponsor2">Sponsor 2 Funds</label>
            <input type="number" class="form-control" name="sponsor2" placeholder="#(affordat.sponsor2)">
                </div>
        <div class="form-group">
            <label for="rent">Rent</label>
            <input type="number" class="form-control" name="rent" placeholder="#(affordat.rent)">
                </div>
        <div class="form-group">
            <label for="rentInflation">Rent Inflation (will be used exactly)</label>
            <input type="number" class="form-control" name="rentInflation" placeholder="#(affordat.rentInflation)">
                </div>
        <div class="form-group">
            <label for="propertyTaxes">Property Taxes (first year est.)</label>
            <input type="number" class="form-control" name="propertyTaxes" placeholder="#(affordat.propertyTaxes)">
                </div>
        <div class="form-group">
            <label for="propertyTaxesInflation">Property Taxes Inflation (est.)</label>
            <input type="number" class="form-control" name="propertyTaxesInflation" placeholder="#(affordat.propertyTaxesInflation)">
                </div>
        <div class="form-group">
            <label for="strataFees">Strata Fees (first year est.)</label>
            <input type="number" class="form-control" name="strataFees" placeholder="#(affordat.strataFees)">
                </div>
        <div class="form-group">
            <label for="strataFeesInflation">Strata Fees Inflation (est.)</label>
            <input type="number" class="form-control" name="strataFeesInflation" placeholder="#(affordat.strataFeesInflation)">
                </div>

        <input type="hidden" name="_csrf" value="{{csrfToken}}">
            <button type="submit" class="btn btn-primary">Refresh Calculations</button>
            </form>

</body>

Great, so I know how to get fluent data to HTML. My problem is I don't know how to get it back. When the "Post" occurs, the data does not seem to get passed to the controller. My route is:

router.post("affordat", use: affordatController.create)

And the relevant part of my controller looks like this:

import Vapor
final class AffordatController {
    func create(_ req: Request) throws -> Future<affordatmodel> {
        return try req.content.decode(affordatmodel.self).flatMap(to: affordatmodel.self) { affordatmodel1 in
            return affordatmodel1.save(on: req)
        }
    }
}

Which shows me one of my models, with an ID #, but no data. And I kind of understand why because I didn't really seem to send the post data to the controller. How I am supposed to send the POST data to the controller? Is the problem in my leaf template, my route, or my controller?

Narwhal
  • 744
  • 1
  • 8
  • 22
  • Hi. There are many ways to send POST data. First, be sure the method you are using. form-data / x-www-form-urlencoded / raw / json ? I suggest to download Postman(free & very useful app), you will able to be sure of the request and even do some unitary tests. So how do you send your data ? – Martin Apr 04 '18 at 08:09
  • Hi Martin. I send it from the Leaf template shown above, which calls the route "affordat" which is directed to the controller using this route: router.post("affordat", use: affordatController.create) but I have no evidence the data gets there because the controller returns {"id":1,"sponsor2":"","interestRate":"","strataFees":"","propertyTaxesInflation":"","targetEquity":"","rent":"","propertyTaxes":"","rentInflation":"","amortization":"","strataFeesInflation":"","sponsor1":"","propertyCost":""} (ie., it saved a blank model) – Narwhal Apr 04 '18 at 20:57

1 Answers1

1

It looks like it should work. You can inspect the data being sent to your server in the network inspector in your browser. Make sure you preserve logs and you'll be able to see the POST request and the data sent to the server.

If you breakpoint at each point in the request you can see what the data is.

As an aside, it looks like you're submitting an empty form, so it's just filling everything in as blank strings. Do you mean to use value instead of placeholder in the form inputs? Value will pre-populate the data for the user, placeholder will show the value to the user as a suggestion but won't send the data in the form submission.

0xTim
  • 5,146
  • 11
  • 23