8 Replies Latest reply on Sep 15, 2014 2:09 PM by Jon Tara

    Webview behavior

    Benigno Belisario

      Hello. 

      I need to run a javascript just after of load a page from a server. This page contains forms, I need to fill it and later do a submit, all this by a javascript.  I'd like to catch the event when the page load is complete in the webview and run the javascript in this moment. 

       

      I'm using Rho::Webview.navigate(url) to run the webview and load the page, I know that there is Rho::WebView.executeJavascript(javascript) but I don't know how execute this instruction after the page was completely loaded. 

       

      Looking in the log there are a line "QtMainWindow| Page load complete." that indicates me that the framework detects the end of the page load and here is where I'd like to run the javascript.

        • Re: Webview behavior

          Is suitable solution if inject javascript in page?

          <script type="text/javascript">

             window.onload = function(){alert('Loading complete')}

          </script>

            • Re: Webview behavior
              Jon Tara

              Are you using a Javascript framework? (jQuery Mobile? Something else?) We need to know that first.

               

              In any case, the best way to do this is to use a Javascript event callback. But how you write that depends on what Javascript framework, if any, you are using. You wouldn't use executeJavascript() for this.

               

              Rhodes comes with jQuery Mobile 1.3. But we don't know if you are using that or not, as you may have removed it or replaced it with a different framework.

                • Re: Webview behavior
                  Benigno Belisario

                  I'm using Rhodes framework. I know that I can use javascript and JQuery too.

                   

                  Using the simulator, after the page is loaded in the device, I can execute javascritp instructions from the console. But I don't know how call the method in the javascript automatically.

                   

                  What I want to do is run a javascript that is in the mobile device after that the webview finished the load a page from a server. I know that I can call a javascript from the html where is the page, but I can't do it.

                   

                  Is any way to catch a event when the webview has finished the loading of the page?

                    • Re: Re: Webview behavior
                      Jon Tara

                      There are a couple of ways. But, again, it depends on any Javascript framework you are using. It also depends on whether you are interested in being notified the the document has loaded or when a page has loaded. There's a difference.

                       

                      I will assume you are loading jQuery Mobile. If you are not, the code below will not work. It sounds like you are not fully aware of what jQuery Mobile is or quite what it does, so I'd suggest you visit the jQuery Mobile site, read up a bit, and then decide if it's even anything you want to use. It's a UI framework, and has some nice widgets like a listview, fancy-looking buttons, page transitions, etc. It's not a core part of Rhodes and you don't have to use it, but it's there by default. It lives in the browser (or webview).

                       

                      First off, WebView.navigate is not the best way to navigate if you are using jQuery Mobile. WebView.navigate will fully re-load the entire document, including any script and styles in <head>, will not use Ajax or do a page transition, will reload and reinitialize jQuery Mobile, etc. etc. I extend WebView to add WebView.changePage() WebView.navigate is like the user typing a new URL into the browser URL bar. It is a heavy, blunt instrument that should be avoided when using JQM unless absolutely necessary. It's not the right way to change pages.

                       

                      Note that navigation from WITHIN your HTML (links, use of $.mobile.changePage) WILL use Ajax and page transitions.

                       

                      The disconnect here is that Rhodes WebView is not at all cognizant of the Javascript framework (jQuery Mobile) that Rhodes puts in your app by default!

                       

                      It is best to catch this early on in the development of an app, because can be very costly to change later.

                       

                      class WebView

                        # This uses the Javascript UI framework to change to a new page using Ajax

                        # This is how we normally change pages

                        def self.change_page(href, options_in={})

                          options = options_in.merge({allowSamePageTransition:true, reloadPage:true})

                          self.execute_javascript "$.mobile.changePage('#{href}',#{options.to_json} );"

                        end

                      end

                       

                      I'd suggest registering an event with some code loaded from <head>.

                       

                      If you want to know when the DOCUMENT has loaded. This can be used if you are using jQuery Mobile or not, but the code below needs jQuery core.

                       

                      $(document).ready(function() {

                        // Do something here when the document is fully loaded.

                        // Note: this does NOT mean that images have been loaded, though.

                        $.post('/app/SomeModel/document_is_ready);

                        });

                       

                      Note though if you are using jQuery Mobile, this will fire only ONCE, when the document is loaded, not when each page is loaded.

                       

                      If you want to know when a PAGE has loaded. You will need to pick which page event you want to use though. JQM fires events at various stages during page load/show and so it is rather meaningless to say just "page is loaded". I'll use pagebeforeshow in the example. The page is loaded, but hasn't yet been shown to the user. Read about page events in the jQuery Mobile documentation. You need to be using jQuery Mobile:

                       

                      $(document).on('pagebeforeshow', '.ui-page', function() {

                      var $page = $(this);

                      $post('/app/SomeModel/page_before_show');

                      });

                       

                      You might also like to parse the URL to pass the notice along to the associated model, and/or you might include the URL in the notice (post).

                       

                      Without knowing exactly what you are trying to accomplish, it's hard to give concrete advice. I'm assuming your purpose is to set some flag that it is OK to send scripts to the document using executeJS().

                       

                      Finally, some thought should be given as to whether or not to use WebView to change documents or pages at all. You have to decide where the locus of control by the user is. Is it in Javascript? Or is it in Rhodes controllers? Or mixed-up in both?

                       

                      I prefer it to be Javascript. One reason for that it is that it's "closer" to the user. So, I take the approach that JS is in charge of navigation, usually if a decision as to where to go needs to be made, some JS code makes the decision (perhaps with information kindly provided by a Rhodes controller) and so I try to avoid the use of either WebView.navigate() (we use it only once in our application) or our extended WebView.changePage().

                       

                      It can be a bit confusing, because we have a bit of extra power with the embedded WebView that is not present if we had just a website. The WebView functions can be thought of as forcing the user's hand. e.g. we can think of it as making the user type a URL and navigate. That's a rather crude way of going about things, if you think about it, and so I try to avoid that and largely put the user in control, rather than the Rhodes controller.

                        • Re: Webview behavior
                          Benigno Belisario

                          The thing that I want to do is the next: We have a web app and we'd like to authenticate an user by user/pass once the mobile app started.

                           

                          In the first request http the web app send an autenticity token to the browser, this field is needed to send later a successfull post request with the user/pass for user authenticate.

                           

                          We though load the html from the server and fill the form fields (user and pass) and later submit, all this using javascript, doing this by the console works, but we don't know how do this automatically.

                           

                          Discussing here we saw that the server send the authenticity token in the html after the request get. Is possible get this value from the html, later arm a post request and render the html after the user is logged?

                            • Re: Webview behavior
                              Jon Tara

                              I'm afraid I can't follow - your description is too abstract.

                               

                              It's easier to help if you post some code and ask questions about it.

                               

                              Not sure what you mean by "web app". Is there some Rhodes app involve somewhere here?

                               

                              It's generally not a good idea to load some website (even your own) into the WebView. Make requests to Rhodes and let Rhodes give you the page. If Rhodes needs to get something from a server, have some code in a Rhodes controller that does that. Otherwise, you are going to run into cross-domain issues, because the "origin" of the browser content is the Rhodes server in the user's device and so any loading of external websites will be considered "cross-domain".

                               

                              Are you programming in Ruby, or only in Javascript? Are you using Rhodes controllers in Ruby, some adhoc Javascript code, or some Javascript MVC framework?

                                • Re: Webview behavior
                                  Benigno Belisario

                                  We have an application web developed on Ruby on Rails. We are developping and application on Rhodes using RhoStudio. We want to log in an user automatically from the mobile app in the Rails app.

                                  How can we do that?

                                    • Re: Webview behavior
                                      Jon Tara
                                      We want to log in an user automatically from the mobile app in the Rails app.

                                      Will you be using Ruby, or just Javascript?

                                       

                                      I would encourage you use Ruby to create your models, and to use Rhodes controllers, which must be written in Ruby.

                                       

                                      This is better than painting yourself into a JavaScript corner.

                                       

                                      Will you be using RhoConnect?

                                       

                                      Pick some controller to be responsible for the user login. If you have a User model, that's a good place. If not, I always toss miscellaneous stuff in the Settings model, though that's not necessarily best practice.

                                       

                                      Write a controller method that will log the user in. You'll use the Network API. You'll likely want to connect some login button or login form submission to your controller. e.g. in your template:

                                       

                                      <form action='<%= url_for :action => login %>'>

                                       

                                      That gets the form submitted to the login method of the controller that handles the login page template. The login method should use the Network API to log the user in to your backend.

                                       

                                      You should be able to find some sample code to do something similar. Perhaps somebody else can suggest where to look, as I haven't worked with the Kitchen Sink or other samples much.