A Cool Way to Debug JavaScript Applications using JetBrains IDEs

Hi folks,

It’s been a while, but in this article I will briefly discuss a very nice way to debug JavaScript applications when using JetBrains IDEs. For those who are unfamiliar, JetBrains is a manufacturer of very powerful and elegant IDEs for developing applications in a variety of languages. The first one I came across and loved is PhpStorm, the best IDE I’ve come across for PHP application development. I’ve also gone on to use others including PyCharm, IntelliJ IDEA and, most recently, WebStorm. Okay back to business.

So, to the issue at hand. JetBrains has an excellent Chrome extension called JetBrains IDE Support Chrome Extension which allows you debug JavaScript code in Chrome using WebStorm, PhpStorm, IntelliJ IDEA Ultimate, PyCharm Professional and RubyMine. It’s available on the Chrome Web Store for download. You can set breakpoints, step through code, view variables and do various other activities once this plugin is installed and activated.

I have used it recently and it works pretty well. This reduces the need for console logs. It’s also more convenient than having the write ‘debugger’ statements in code. So, if you write a lot of JavaScript applications and use JetBrains IDEs, then try out JetBrains IDE support today. Till next time.

How to wait for visibility in PhantomJS

I found an excellent piece of code on Stack Overflow on how to wait for elements to become visible before performing an action in PhantomJS. I thought I would share it here.

Here is the function required:

function waitFor ($config) {
    $config._start = $config._start || new Date();

    if ($config.timeout && new Date - $config._start > $config.timeout) {
        if ($config.error) $config.error();
        if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms');
        return;
    }

    if ($config.check()) {
        if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms');
        return $config.success();
    }

    setTimeout(waitFor, $config.interval || 0, $config);
}

Then use the code as follows:

waitFor({
    debug: true,  // optional
    interval: 0,  // optional
    timeout: 1000,  // optional
    check: function () {
        return page.evaluate(function() {
            return $('#thediv').is(':visible');
        });
    },
    success: function () {
        // we have what we want
    },
    error: function () {} // optional
});

Reference

http://stackoverflow.com/questions/16807212/how-to-wait-for-element-visibility-in-phantomjs

How to Make Checkbox Checked by Default in AngularJS

Here’s a quick tip on how to set a checkbox as checked by default when developing an app with AngularJS. In your controller, suppose you’re storing the form in a field someCheckboxField under a form variable someForm. All you need to do is set the field to true

e.g.

$scope.someForm = {
    someCheckboxField: true
};

Then in the template, make sure the checkbox has ng-model set appropriately, e.g.

 <input type='checkbox' name='someCheckboxField' ng-model='someForm.someCheckboxField' />

How to Copy Long Console Log in Google Chrome

When debugging JavaScript, you may come across situations where you have printed out some super-long variable which Chrome console doesn’t fully show. In order to retrieve the full variable, right-click the output, click Store as Global Variable. A variable name will appear at the bottom of the console together with the value you desire. Let’s assume the variable name is temp1. Execute the following command in the console:

copy(temp1);

That’s it! The value is now in your clipboard and can be pasted into an editor of your choice.

Creating a Simple app with CherryPy and React JS

Hi folks,

In this tutorial we will set up a simple web app using CherryPy and React js. This tutorial is based on the first tutorial on the CherryPy website with some minor updates necessary to make it work.

First, create a virtual environment, say cherrypyapp using the command:

mkvirtualenv cherrypyapp

The above command switches you to the environment on creation.
Next, install CherryPy using the following commands:

hg clone https://bitbucket.org/cherrypy/cherrypy
cd cherrypy
python setup.py install

Note: As of the time of writing the pip version didn’t seem to work well. On testing the installation there was an error about tutorial.conf not being found, hence my using hg.

Test your installation using command:

python -m cherrypy.tutorial.tut01_helloworld

You should see several lines of text show up with the last line containing the text:

ENGINE Bus STARTED

Now we’re ready to create a project. Create a folder for the project, say ~/Documents/cherrypyapp and change to the directory.

Just like in the tutorial on CherryPy website, we’re going to create a sample app that generates a random string of a user-supplied length (8 by default). The app will allow you edit or delete the string. SQLite db will be used to store the string generated.

Create a file cherrypyapp.py containing the following content:

import os, os.path
import random
import sqlite3
import string
import time

import cherrypy

DB_STRING = "my.db"

class StringGenerator(object):
   @cherrypy.expose
   def index(self):
       return file('index.html')


class StringGeneratorWebService(object):
    exposed = True

    @cherrypy.tools.accept(media='text/plain')
    def GET(self):
        with sqlite3.connect(DB_STRING) as c:
            cherrypy.session['ts'] = time.time()
            r = c.execute("SELECT value FROM user_string WHERE session_id=?",
                      [cherrypy.session.id])
            return r.fetchone()

    def POST(self, length=8):
        some_string = ''.join(random.sample(string.hexdigits, int(length)))
        with sqlite3.connect(DB_STRING) as c:
            cherrypy.session['ts'] = time.time()
            c.execute("INSERT INTO user_string VALUES (?, ?)",
                      [cherrypy.session.id, some_string])
        return some_string

    def PUT(self, another_string):
        with sqlite3.connect(DB_STRING) as c:
            cherrypy.session['ts'] = time.time()
            c.execute("UPDATE user_string SET value=? WHERE session_id=?",
                      [another_string, cherrypy.session.id])

    def DELETE(self):
        cherrypy.session.pop('ts', None)
        with sqlite3.connect(DB_STRING) as c:
            c.execute("DELETE FROM user_string WHERE session_id=?",
                      [cherrypy.session.id])

def setup_database():
    """
    Create the `user_string` table in the database
    on server startup
    """
    with sqlite3.connect(DB_STRING) as con:
        con.execute("CREATE TABLE user_string (session_id, value)")

def cleanup_database():
    """
    Destroy the `user_string` table from the database
    on server shutdown.
    """
    with sqlite3.connect(DB_STRING) as con:
        con.execute("DROP TABLE user_string")

if __name__ == '__main__':
    conf = {
        '/': {
            'tools.sessions.on': True,
            'tools.staticdir.root': os.path.abspath(os.getcwd())
        },
        '/generator': {
            'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
            'tools.response_headers.on': True,
            'tools.response_headers.headers': [('Content-Type', 'text/plain')],
        },
        '/static': {
            'tools.staticdir.on': True,
            'tools.staticdir.dir': './public'
        }
    }

    cherrypy.engine.subscribe('start', setup_database)
    cherrypy.engine.subscribe('stop', cleanup_database)

    webapp = StringGenerator()
    webapp.generator = StringGeneratorWebService()
    cherrypy.quickstart(webapp, '/', conf)

The StringGenerator class contains an index() function which handles the home page link. As seen, it just outputs the contents of index.html.

StringGeneratorWebService is a class that provides a RESTful API for creating, updating and deleting a string which we generate in the front end. The setup_database() function creates the user_string table and the cleanup_database() function drops it.

In the conf variable the line ‘request.dispatch’: cherrypy.dispatch.MethodDispatcher() indicates that we will use HTTP request methods that match the name of functions within the StringGeneratorWebService class.

Next, create a file index.html with the following contetent:

<!DOCTYPE html>
<html>
 <head>
 <link href="/static/css/style.css" rel="stylesheet">

 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-dom.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

 </head>
 <body>
 <div id="generator"></div>
 <script type="text/babel" src="static/js/gen.js"></script>
 </body>
</html>

Note the script type “text/babel”. That’s important. Don’t use just javascript, or else it may not work.

Next, create a folder public/css. Then create a file style.css inside it with the following content:

body {
  background-color: blue;
}

#the-string {
  display: none;
}

Then create a folder public/js and a file gen.js inside it with the following content:

 var StringGeneratorBox = React.createClass({
   handleGenerate: function() {
     var length = this.state.length;
     this.setState(function() {
       $.ajax({
         url: this.props.url,
         dataType: 'text',
         type: 'POST',
         data: {
           "length": length
         },
         success: function(data) {
           this.setState({
             length: length,
             string: data,
             mode: "edit"
           });
         }.bind(this),
         error: function(xhr, status, err) {
           console.error(this.props.url,
             status, err.toString()
           );
         }.bind(this)
       });
     });
   },
   handleEdit: function() {
     var new_string = this.state.string;
     this.setState(function() {
       $.ajax({
         url: this.props.url,
         type: 'PUT',
         data: {
           "another_string": new_string
         },
         success: function() {
           this.setState({
             length: new_string.length,
             string: new_string,
             mode: "edit"
           });
         }.bind(this),
         error: function(xhr, status, err) {
           console.error(this.props.url,
             status, err.toString()
           );
         }.bind(this)
       });
     });
   },
   handleDelete: function() {
     this.setState(function() {
       $.ajax({
         url: this.props.url,
         type: 'DELETE',
         success: function() {
           this.setState({
             length: "8",
             string: "",
             mode: "create"
           });
         }.bind(this),
         error: function(xhr, status, err) {
           console.error(this.props.url,
             status, err.toString()
           );
         }.bind(this)
       });
     });
   },
   handleLengthChange: function(length) {
     this.setState({
       length: length,
       string: "",
       mode: "create"
     });
   },
   handleStringChange: function(new_string) {
     this.setState({
       length: new_string.length,
       string: new_string,
       mode: "edit"
     });
   },
   getInitialState: function() {
     return {
       length: "8",
       string: "",
       mode: "create"
     };
   },
  render: function() {
     return (
       <div className="stringGenBox">
     <StringGeneratorForm onCreateString={this.handleGenerate}
     onReplaceString={this.handleEdit}
     onDeleteString={this.handleDelete}
     onLengthChange={this.handleLengthChange}
     onStringChange={this.handleStringChange}
     mode={this.state.mode}
     length={this.state.length}
     string={this.state.string}/>        
       </div>
     );
   }
 });

 var StringGeneratorForm = React.createClass({
   handleCreate: function(e) {
     e.preventDefault();
     this.props.onCreateString();
   },
   handleReplace: function(e) {
     e.preventDefault();
     this.props.onReplaceString();
   },
   handleDelete: function(e) {
     e.preventDefault();
     this.props.onDeleteString();
   },
   handleLengthChange: function(e) {
     e.preventDefault();
     var length = React.findDOMNode(this.refs.length).value.trim();
     this.props.onLengthChange(length);
   },
   handleStringChange: function(e) {
     e.preventDefault();
     var string = React.findDOMNode(this.refs.string).value.trim();
     this.props.onStringChange(string);
   },
   render: function() {
     if (this.props.mode == "create") {
       return (
         <div>
            <input type="text" value="{this.props.length}" />
            <button>Give it now!</button>
         </div>
       );
     } else if (this.props.mode == "edit") {
       return (
         <div>
            <input type="text" value="{this.props.string}" />
            <button>Replace</button>
            <button>Delete it</button>
         </div>
       );
     }

     return null;
   }
 });

 React.render(
   <StringGeneratorBox url="/generator" />,
   document.getElementById('generator')
 );

Note form the javascript file that the StringGeneratorBox displays the main container and inside it is the StringGeneratorForm which handles showing the form.

Now we have all the files in place, start the server using the command:

python cherrypyapp.py

You should then be able to visit the site in a browser at http://localhost:8080/

That’s all for now. Enjoy.

Sources

Tutorial | React. https://facebook.github.io/react/docs/tutorial.html

Tutorials — CherryPy 3.8.2 documentation. http://docs.cherrypy.org/en/latest/tutorials.html

Transfering Data between Multiple Browser Windows with Javascript

With javascript, it is fairly easy to transfer data between a popup window and the window which opened it. You can also call functions, or even set location of the opening window from a popup window. This is possible because a popup window holds a reference to the opening window in a javascript variable called ‘opener’.

So the variable:

window.opener

refers to opener window.

In this tutorial, we have an original webpage win_opener1.php and a popup webpage win_opener2.php. A link in the opening page (win_opener1.php) opens the popup (win_opener2.php). When the user types in some text in a form on win_opener2.php and submits it, the popup window closes, and the original window shows an alert of the text entered in the popup.

In the source code of the popup window javascript, there is also commented code, which when uncommented, makes the opening window redirect to a specified URL.

The source code for win_opener1.php is

<!DOCTYPE HTML>
<html lang="en">

<head>

 <meta charset="UTF-8">

 <title></title>

</head>

<body>

<a id="opener" href="#">Click to open child window</a> 

<form name="parentform" action="" >

 <input name="myinput" type="hidden" />

</form>

<script type="text/javascript" 

src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js">
</script>

<script type="text/javascript">

$(document).ready(function(){

 $("#opener").click(function(e){

 e.preventDefault();

 window.open("/resources/js/

data-trans-multiple-windows/win_opener2.php",
 "mywindow", "menubar=no,width=500,height=500");

 });

});

function process(){

 alert("You entered "+document.parentform.myinput.value);

}

</script>

</body>

</html>

The code for win_opener2.php is :

<!DOCTYPE HTML>

<html lang="en">

<head>

 <meta charset="UTF-8">

 <title></title>

</head>

<body>

<form name="childform" action="">

Enter name: <input id="myname" name="myname" type="text" />

<input type="submit" value="Submit" />

</form>

<script type="text/javascript" 

src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js">

</script>

<script type="text/javascript">

$(document).ready(function(){

 $("form").submit(function(e){

 e.preventDefault();

 // to set url on window opener

 // window.opener.location="http://www.yahoo.com";

 // passing data to window opener

 window.opener.document.parentform.myinput.value =
window.document.childform.myname.value;

 window.close();

 // to call a function on window opener

 window.opener.process();

 

 });

});

</script>

</body>

</html>