turbolinks / turbolinks-ios

Native iOS adapter for building hybrid apps with Turbolinks 5
MIT License
881 stars 92 forks source link

Javascript 'confirm' dialog doesn't send data back to the server #103

Closed pbmarcano closed 7 years ago

pbmarcano commented 7 years ago

Per issue #88, I added the WKUIDelegate to my project and added:

func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        print("webView:\(webView) runJavaScriptAlertPanelWithMessage:\(message) initiatedByFrame:\(frame) completionHandler:\(completionHandler)")

        // Alert Controller
        let confirm = UIAlertController(title: nil, message: message, preferredStyle: .alert)

        confirm.addAction(UIAlertAction(title: "Okay", style: .default) { (action) in
            completionHandler(true)
        })

        confirm.addAction(UIAlertAction(title: "Cancel", style: .cancel) { (action) in
            completionHandler(false)
        })

        self.present(confirm, animated: true, completion: nil)
    }

The alert comes up just fine, but either button doesn't do anything. As if completionHandler() doesn't actually do anything.

I tried adding this code to the TurbolinksDemo app with my backend and it also didn't work, but when adding it to a standard/Vanilla WKWebView it works just as the apple documentation suggests it should.

excid3 commented 7 years ago

I tried to implement this a few differents ways myself and couldn't get it to work either.

pbmarcano commented 7 years ago

I tried downgrading to an older Turbolinks-iOS library but Xcode yelled at me because it was unable to build anything before Swift 3... Thanks Apple πŸ™„...

I looked within the app of Basecamp 3 and it looks like Basecamp uses a data-confirm when you are emptying the trash... and that seems to work fine on their iOS app.

So either the trash view is a default WKWebView or I am missing something.

@zachwaugh hate to put you on the spot but you seem to be the helpful contributor here recently! πŸ˜„

pbmarcano commented 7 years ago

Like most problems I have, I was looking in the wrong spot.

Turns out, I wasn't building my links properly to be handled via XHR, and needed to add remote: true to the rails link_to method.

Your anchor tags need a data-remote="true" attribute.

That took way too long. Sorry folks.

http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#link-to

excid3 commented 7 years ago

Got this working thanks to @pbmarcano πŸ‘

For reference, there are two changes to the TurbolinksDemo app make:

  1. Extend ApplicationController with WKUIDelegate
extension ApplicationController: WKUIDelegate {
    func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
        print("webView:\(webView) runJavaScriptAlertPanelWithMessage:\(message) initiatedByFrame:\(frame) completionHandler:\(completionHandler)")

        // Alert Controller
        let confirm = UIAlertController(title: nil, message: message, preferredStyle: .alert)

        confirm.addAction(UIAlertAction(title: "Okay", style: .default) { (action) in
            completionHandler(true)
        })

        confirm.addAction(UIAlertAction(title: "Cancel", style: .cancel) { (action) in
            completionHandler(false)
        })

        self.present(confirm, animated: true, completion: nil)
    }
}
  1. Set the Turbolinks webview ui delegate to be the ApplicationController
    fileprivate lazy var session: Session = {
        let session = Session(webViewConfiguration: self.webViewConfiguration)
        session.delegate = self
        session.webView.uiDelegate = self // This is the line to add
        return session
    }()
  1. Your Rails app needs to have links with remote: true and data: { confirm: "Are you sure?" } to make them work. The remote: true isn't there in regular scaffolds, hence why it wasn't originally working even with the above Swift code.