NEW: Learn to build the incredible iOS 15 Weather app today! >>

Update variable value after textField input

Forums > SwiftUI

Hello, I have a table for creating an invoice where user needs to add the concept, quantity, price and tax in each row. I need to update the "total" text so every time the user changes some value, the total row is updated. How can I achieve that behaviour? I was thinking about computed property but it can't be a @State property. Thank you very much.

   

Make your total a computed property whose value is calculated from your various State properties. When they update and trigger a rerender, the computed property will be recalculated and the new value displayed.

total only needs to be a State property if it will be manipulated directly.

(Ignore the specific details of the calculation and just look at the functionality.)

struct RecalcView: View {
    @State private var quantity = 0
    @State private var price = 0.0
    @State private var tax = 0.0

    var total: Double {
        (Double(quantity) * price) * tax
    }

    var currencyFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        return formatter
    }()

    var body: some View {
        VStack(spacing: 20) {
            TextField("Quantity", value: $quantity, formatter: NumberFormatter())
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Price", value: $price, formatter: currencyFormatter)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Tax", value: $tax, formatter: NumberFormatter())
                .textFieldStyle(RoundedBorderTextFieldStyle())
            Divider()
            Text(String(total))
        }
        .padding(.horizontal)
    }
}

1      

Hello, the 'total' variable doesn't update after price or quantity changed. Is there a way to recalculate the amount every time user changes anything?

   

Not sure if it is still an open question, but roosterboys response doesn't work as Mattiav8 notes. It seems like it should work, and I'm not sure why it doesn't. Anyway, the following does work:

struct RecalcView: View {
    @State private var quantity = ""
    @State private var price = ""
    @State private var tax = ""

    var total: Double {
        (Double(quantity) ?? 0.0) * (Double(price) ?? 0.0) * (Double(tax) ?? 0.0)
    }
    // currencyFormatter not used

    var body: some View {
        VStack(spacing: 20) {
            TextField("Quantity", text: $quantity)
            TextField("Price", text: $price)
            TextField("Tax", text: $tax)
            Divider()
            Text(String(total))
        }
        .textFieldStyle(RoundedBorderTextFieldStyle())
        .padding(.horizontal)
    }
}

   

The solution I posted works just fine for me. Works the same as the solution posted by @sbolin (except that the currency is formatted).

RecalcView gif

In thinking about it, though, it might make sense to change things a little like so:

struct RecalcView: View {
    @State private var quantity = 0
    @State private var price = 0.0
    @State private var tax = 0.0

    var total: Double {
        (Double(quantity) * price) * (1 + tax) //1
    }

    var currencyFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .currency
        return formatter
    }()

    //2
    var percentFormatter: NumberFormatter = {
        let formatter = NumberFormatter()
        formatter.numberStyle = .percent
        return formatter
    }()

    var body: some View {
        VStack(spacing: 20) {
            TextField("Quantity", value: $quantity, formatter: NumberFormatter())
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Price", value: $price, formatter: currencyFormatter)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            TextField("Tax", value: $tax, formatter: percentFormatter) //3
                .textFieldStyle(RoundedBorderTextFieldStyle())
            Divider()
            Text(String(total))
        }
        .padding(.horizontal)
    }
}
  1. If the tax is, say, 8%, then we should multiply the total price by 1.08. Because I've used a percent formatter (see below), our tax Double becomes 0.08 if we type 8 in the field. This also means that, unlike the previous solution, we don't need to type something in the tax field in order to get a final total, since 0% tax would still give us a legit number (i.e., 1 + 0.0) instead of 0.
  2. Format the tax amount as a percent.
  3. Use the percent formatter we set up above.

   

Sorry for the late response, thank you very much to all of you for the help, it works perfectly!!

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.