1

I have date picker in my view like this:

struct BookTimeView: View {
    @ObservedObject var viewModel: BookTimeViewModel

    @State var startTime = Date.now
    
 
     var body: some View {
         DatePicker(“pick time”, selection: $startTime, displayedComponents: .hourAndMinute)
     }
}

initial startTime depends on data from backend.

So in view model I have API call that loads data from backend.

In success callback I want to change startTime.

Question: How can I change startTime from my ViewModel ?

P.S.: Is that possible to bind DatePicker with ViewModel directly ?

I tried to put @State var startTime = Date.now in view model. But it doesn't work, and I see warning in Xcode:

Accessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update.
Jim
  • 8,874
  • 16
  • 68
  • 125
  • Why don't you want to bind `DatePicker` directly to `viewModel`? – Asperi Nov 24 '21 at 11:16
  • @Asperi When I place State property in ViewModel, I see next warning: ccessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update. – Jim Nov 24 '21 at 11:23
  • Have it use the and `@Published` that you api updates – lorem ipsum Nov 24 '21 at 11:25
  • 1
    I'm about binding to published property, like in https://stackoverflow.com/a/60058909/12299030. – Asperi Nov 24 '21 at 11:25
  • @Asperi Wow. That it what I was looking for. Thanks man !! – Jim Nov 24 '21 at 11:38

1 Answers1

4

You can directly bind to the @Published property with just:

$viewModel.startTime

Which will be of type Binding<Date>, even though we declare it as just a @Published property on BookTimeViewModel.

Example code:

class BookTimeViewModel: ObservableObject {
    @Published var startTime: Date = .now
}
struct BookTimeView: View {
    @ObservedObject var viewModel: BookTimeViewModel

    var body: some View {
        DatePicker("pick time", selection: $viewModel.startTime, displayedComponents: .hourAndMinute)
    }
}

Similar to my answer here.

George
  • 25,988
  • 10
  • 79
  • 133
  • How to assign Date object to startTime: Binding ? – Jim Nov 24 '21 at 11:58
  • @Jim To assign, you can just do `viewModel.startTime = Date.now` for example. The code above is to create a `Binding` of it for your `DatePicker`. – George Nov 24 '21 at 12:04
  • When I try to assign Date.now to startTime: Binding I got error message that it's not possible to assign Date to Binding – Jim Nov 24 '21 at 12:09
  • @Jim You want `startTime` in `BookTimeViewModel` to be declared as `@Published var startTime = Date.now`. Then you can do the `viewModel.startTime = Date.now` as mentioned above, and also remove the `@State` variable for it. Remember to remove the `$` when just setting a new value. – George Nov 24 '21 at 12:15
  • The problem is that DatePicker works only with Binding. So I can't use just Publisher. It should be State or Binding – Jim Nov 24 '21 at 15:49
  • @Jim I think you may be slightly misunderstanding, so I've added example code. – George Nov 24 '21 at 16:32
  • Oh man. I tried to use $ before startTime, not before viewModel. Thank you !!! Your solution is simple and it works !! – Jim Nov 25 '21 at 07:25