Cordova (aka PhoneGap) 3.x Tutorial

cordova

In this tutorial, you’ll create a fully functional employee directory application with Cordova.

What you will learn:

  • How to use different local data storage strategies.
  • How to use several Cordova APIs such as Geolocation, Contacts, and Camera.
  • How to handle specific mobile problems such as touch events, scrolling, styling, page transitions, etc.
  • How to build an application using a single-page architecture and HTML templates.
  • How to build (compile and package) an application locally using the Cordova CLI (Command Line Interface).

Requirements:

To complete this workshop, all you need is a code editor, a modern browser, and a connection to the Internet.

A working knowledge of HTML and JavaScript is assumed, but you don’t need to be a JavaScript guru.

A mobile device or a Mobile SDK is not a requirement for this tutorial. However, if you want to run and test the application on a mobile device or on an emulator for a mobile platform supported by Cordova, you need the Mobile SDK for that platform (iOS SDK, Android SDK, etc.) installed on your system. If you don’t want to install a Mobile SDK, you’ll be able to test your application in a browser on your computer.

Part 1: Creating a Cordova Project


  1. Make sure an up-to-date version of Node.js is installed on your system.
  2. Open Terminal (Mac) or a Command window (Windows), and type the following command to install the Cordova CLI:
    npm install -g cordova

    or on a Mac:

    sudo npm install -g cordova
  3. Navigate to a directory where you store projects on your system. For example:
    cd ~/Projects
  4. Create a project called “workshop”:
    cordova create workshop com.yourname.workshop Workshop
  5. Navigate to the project directory:
    cd workshop
  6. Add the platforms you want to support. For example, to add support for iOS and Android, type:
  7. cordova platforms add ios
    cordova platforms add android
  8. Make sure you are in the “workshop” directory, and add basic plugins to your projects:
    cordova plugin add org.apache.cordova.device
    cordova plugin add org.apache.cordova.console
  9. Examine the directory structure under workshop.


Part 2: Building a Cordova Project


iOS

You need the iOS SDK installed on your computer to build an iOS version of your application using the steps below.

cordova build ios

The project is built in the workshop/platforms/ios folder. Double-click Workshop.xcodeproj to open the project in XCode, and run it in the emulator or on your device.

You can also run the application in the iOS emulator directly from the command line. First install ios-sim:

sudo npm install -g ios-sim

Then run the application in the iOS emulator:

cordova emulate ios

Android

You need the Android SDK installed on your computer to build an Android version of your application using the steps below.

To build the project in the workshop/platforms/android folder and run it on an Android device connected to your computer using a USB cable, type:

cordova run android

To build the project in the workshop/platforms/android folder and run it in the Android emulator, type:

cordova emulate android

 

Part 3: Setting Up the Workshop Files


  1. Download the assets for the workshop here or clone this repository
  2. .

  3. Unzip the file anywhere on your file system.
  4. Delete the contents of your project’s workshop/www folder with the exception of the config.xml file.
  5. Copy the contents of cordova-tutorial-master/www into your project’s workshop/www folder.
  6. Build and test your application: If you have a Mobile SDK installed on your system, repeat the steps in Part 2 above. If you don’t, simply open index.html in a browser on your computer.
  7. Type a few characters in the search box to search employees by name. Clicking an employee link doesn’t produce any result at this time.
Step-by-step solutions are available in the cordova-tutorial-master/solutions folder


Part 4: Choosing a Local Storage Option


Step 1: Explore different persistence mechanisms

Open the following files in workshop/js/adapters, and explore the different persistence adapters:

  1. MemoryAdapter (in memory-adapter.js)
  2. JSONPAdapter (in jsonp-adapter.js)
  3. LocalStorageAdapter (in localstorage-adapter.js)
  4. WebSqlAdapter (in websql-adapter.js)

Step 2: Test the application with different persistence mechanisms

The application is initially configured to work with the in-memory datastore. To change the local persistence mechanism for the application:

  1. In index.html: instead of memory-adapter.js, import the .js file for the data adapter of your choice: jsonp-adapter.js, localstorage-adapter.js, or websql-adapter.js.
  2. In js/app.js, replace the instantiation of MemoryAdapter with the instantiation of the data adapter you imported in the previous step: JSONPAdapter, LocalStorageAdapter, or WebSqlAdapter.
  3. Test the application.


Part 5: Using Native Notification


A default JavaScript alert gives away the fact that your application is not native. In this section, we set up the basic infrastructure to display native alerts when the application is running on a device, and fall back to default JavaScript alerts when it is running in the browser.

  1. Add the native dialogs plugin to your project:
    cordova plugin add org.apache.cordova.dialogs
  2. In index.html, add the following script tag (as the first script tag at the bottom of the body):
    <script src="cordova.js"></script>
    

    This instructs the Cordova CLI to inject a platform specific version of cordova.js at build time. In other words, cordova.js doesn’t need to be (and shouldn’t be) present in your project/www folder.
  3. When running on a device with the navigator.notification object available (the dialogs plugin is installed), override the window.alert() function and replace its default implementation with a call to navigator.notification.alert(). Add this code to the “Event Registration” block:
    document.addEventListener('deviceready', function () {
        if (navigator.notification) { // Override default HTML alert with native dialog
            window.alert = function (message) {
                navigator.notification.alert(
                    message,    // message
                    null,       // callback
                    "Workshop", // title
                    'OK'        // buttonName
                );
            };
        }
    }, false);
    
  4. Test the application: click the Help button.

    When you run the application in the browser, you should see a standard browser alert.
    When you run the application on your device, you should see a native alert.


Part 6: Avoid the 300ms Click Delay


  1. Test the application on your iOS device or in the iOS emulator: Tap the Help button, and notice the delay before the dialog appears.
  2. This delay occurs because the operating system is waiting roughly 300ms to see if the user is going to tap the target again (and therefore perform a double-tap).
  3. In index.html, add the following script tag:
    <script src="lib/fastclick.js"></script>
    

    FastClick is an open source library built by the Financial Times. More information here.

  4. In app.js, register FastClick inside the deviceready event handler.

    FastClick.attach(document.body);
  5. Test the application: Click the Help button. The message should now appear without delay.


Part 7: Setting Up a Single-Page Application


A “Single-Page Application” is a web application that lives within a single HTML page. The “views” of the application are injected into and removed from the DOM as needed as the user navigates through the app. A single-page application architecture is particularly well suited for mobile apps:

  • The absence of page refreshes provides a more fluid and closer to native experience.
  • The UI is entirely created at the client-side with no dependency on a server to create the UI, making it an ideal architecture for applications that work offline.

In this section, we set up the basic infrastructure to turn Employee Directory into a single-page application.

  1. In index.html: remove the HTML markup inside the body tag (with the exception of the script tags).
  2. Inside the immediate function in app.js, define a function named renderHomeView() (right after the findByName function). Implement the function to programmatically add the Home View markup to the body element.
    function renderHomeView() {
        var html =
            "<h1>Directory</h1>" +
            "<input class='search-key' type='search' placeholder='Enter name'/>" +
            "<ul class='employee-list'></ul>";
        $('body').html(html);
        $('.search-key').on('keyup', findByName);
    }
    
  3. Modify the data adapter initialization logic: when the adapter has been successfully initialized, call the renderHomeView() function to programmatically display the Home View.
    var adapter = new MemoryAdapter();
    adapter.initialize().done(function () {
        renderHomeView();
    });
    
  4. Since you moved the registration of the keyup event inside the renderHomeView() function, make sure you remove the original event registration in the Event Registration section.
  5. Since the Help button is no longer there, remove the click event handler for the help button (in the Event Registration section).
  6. Test the application.


Part 8: Using Handlebars Templates


Writing HTML fragments in JavaScript and programmatically inserting them into the DOM is tedious. It makes your application harder to write and harder to maintain. HTML templates address this issue by decoupling the UI definition (HTML markup) from your code. There are a number of great HTML template solutions, including Mustache.js, Handlebars.js, and Underscore.js to name a few.

In this section, we create two templates to streamline the code of the Employee Directory application. We use Handlebars.js but the same result can be achieved using the other HTML template solutions.

Modify index.html as follows:

  1. Add a script tag to include the handlebars.js library:
    <script src="lib/handlebars.js"></script>
    
  2. Create an HTML template to render the Home View. Add this script tag as the first child of the body tag:
    <script id="home-tpl" type="text/x-handlebars-template">
        <div class="topcoat-navigation-bar">
            <div class="topcoat-navigation-bar__item center full">
                <h1 class="topcoat-navigation-bar__title">Employee Directory</h1>
            </div>
        </div>
        <div class="search-bar">
            <input type="search" placeholder="search" class="topcoat-search-input search-key">
        </div>
        <div class="topcoat-list__container">
            <ul class="topcoat-list list employee-list"></ul>
        </div>
    </script>
    
  3. Create an HTML template to render the employee list items. Add this script tag immediately after the previous one:
    <script id="employee-li-tpl" type="text/x-handlebars-template">
        {{#.}}
        <li class="topcoat-list__item">
            <a href="#employees/{{id}}">
                <img src="assets/pics/{{pic}}">
                <p>{{firstName}} {{lastName}}</p>
                <p>{{title}}</p>
                <span class="chevron"></span><span class="count">{{reports}}</span>
            </a>
        </li>
        {{/.}}
    </script>
    
  4. Add topcoat-mobile-light.css and styles.css to the head of index.html
    <link href="assets/topcoat/css/topcoat-mobile-light.css" rel="stylesheet">
    <link href="assets/css/styles.css" rel="stylesheet">
    

Modify the immediate function in app.js as follows:

  1. Immediately before the adapter variable declaration, declare two variables that hold the compiled version of the templates defined above:
    var homeTpl = Handlebars.compile($("#home-tpl").html());
    var employeeLiTpl = Handlebars.compile($("#employee-li-tpl").html());
    
  2. Modify renderHomeView() to use the homeTpl template instead of the inline HTML:
    function renderHomeView() {
        $('body').html(homeTpl());
        $('.search-key').on('keyup', findByName);
    }
    
  3. Modify findByName() to use the employeeLiTpl template instead of the inline HTML:
    function findByName() {
        adapter.findByName($('.search-key').val()).done(function (employees) {
            $('.employee-list').html(employeeLiTpl(employees));
        });
    }
    
  4. Test the application.


Part 9: Creating a View Class


It’s time to provide the application with some structure. If we keep adding all the core functions of the application to the immediate function that bootstraps the app, it will very quickly grow out of control. In this section we create a HomeView object that encapsulates the logic to create and render the Home view.

Step 1: Create the HomeView Class

  1. Create a file named HomeView.js in the js directory, and define a HomeView constructor implemented as follows:
    var HomeView = function (adapter, template, listItemTemplate) {
    
    }
    
  2. The constructor function takes three arguments: the data adapter, the Home View template, and the employee list item template.
  3. Define an initialize() function inside the HomeView constructor. Define a div wrapper for the view. The div wrapper is used to attach the view-related events. Invoke the initialize() function inside the HomeView constructor function.
    var HomeView = function (adapter, template, listItemTemplate) {
    
        this.initialize = function () {
            // Define a div wrapper for the view. The div wrapper is used to attach events.
            this.el = $('<div/>');
            this.el.on('keyup', '.search-key', this.findByName);
        };
    
        this.initialize();
    
    }
    
  4. Move the renderHomeView() function from app.js to the HomeView class. To keep the view reusable, attach the HTML to the div wrapper (this.el) instead of the document body. Because the function is now encapsulated in HomeView, you can also rename it from renderHomeView() to just render().
    this.render = function() {
        this.el.html(template());
        return this;
    };
    
  5. Move the findByName() function from app.js to HomeView.
    this.findByName = function() {
        adapter.findByName($('.search-key').val()).done(function(employees) {
            $('.employee-list').html(listItemTemplate(employees));
        });
    };
    

Step 2: Using the Home View

  1. In index.html, add a script tag to include HomeView.js (just before the script tag for app.js):
    <script src="js/HomeView.js"></script>
    
  2. In app.js, remove the renderHomeView() function from the immediate function.
  3. Remove the findByName() function from the immediate function.
  4. Modify the adapter initialization logic to display the Home View when the adapter has been successfully initialized. Pass the adapter, the Home View template, and the employee list item template as arguments to the Home View constructor.
    adapter.initialize().done(function () {
        $('body').html(new HomeView(adapter, homeTpl, employeeLiTpl).render().el);
    });
    
  5. Test the application


Part 10: Implementing Native Scrolling


Test the application. Specifically, test the list behavior when the list is bigger than the browser window (or the screen). Notice that the entire view (including the header) is scrolling. To anchor the header at the top of the screen, and scroll the employee list only:

  1. In the Home Page template, add a css class named scroller to the div surrounding the employee list ul.
    <div class="topcoat-list__container scroller">
        <ul class="topcoat-list list employee-list"></ul>
    </div>
    
  2. In assets/css/styles.css define the scroller class as follows:
    .scroller {
        overflow: auto;
        -webkit-overflow-scrolling: touch;
        position: absolute;
        top: 141px;
        bottom: 0px;
        left: 0px;
        right: 0px;
    }
    
  3. Test the application.

On iOS, you can still scroll down the web view (including the header). To disable this behavior, open config.xml in the workshop/www folder and add the following preference as the last line within the widget tag:

<preference name="DisallowOverscroll" value="true" />


If the platforms you target support touch-based scrolling of fixed regions, this approach is all you need. If not, you’ll need to implement a programmatic approach, typically with the help of a library such as iScroll.


Part 11: View Routing


In this section, we add an employee details view. Since the application now has more than one view, we also add a simple view routing mechanism that uses the hash tag to determine whether to display the home view or the details view for a specific employee.

Step 1: Create the employee template

Open index.html and add a template to render a detailed employee view:

<script id="employee-tpl" type="text/x-handlebars-template">
    <div class="topcoat-navigation-bar">
        <div class="topcoat-navigation-bar__item left quarter">
            <a class="topcoat-icon-button--quiet back-button" href="#">
                <span class="topcoat-icon topcoat-icon--back"></span>
            </a>
        </div>
        <div class="topcoat-navigation-bar__item center half">
            <h1 class="topcoat-navigation-bar__title">Employee</h1>
        </div>
    </div>
    <div class='details'>
        <img src="assets/pics/{{pic}}" class="employee-image">
        <h1>{{firstName}} {{lastName}}</h1>
        <h2>{{title}}</h2>
        <h2>{{city}}</h2>
        <div class="topcoat-list__container scroller">
            <ul class="topcoat-list list actions">
                {{#if managerId}}
                <li class="topcoat-list__item"><a href="#employees/{{managerId}}"><p>View Manager</p><p>{{managerName}}</p><div class="action-icon icon-manager"/></a></li>
                {{/if}}
                <li class="topcoat-list__item"><a href="tel:{{officePhone}}"><p>Call Office</p><p>{{officePhone}}</p><div class="action-icon icon-call"/></a></li>
                <li class="topcoat-list__item"><a href="tel:{{cellPhone}}"><p>Call Cell</p><p>{{cellPhone}}</p><div class="action-icon icon-call"/></a></li>
                <li class="topcoat-list__item"><a href="sms:{{cellPhone}}"><p>SMS</p><p>{{cellPhone}}</p><div class="action-icon icon-sms"/></a></li>
                <li class="topcoat-list__item"><a href="mailto:{{email}}"><p>Email</p><p>{{email}}</p><div class="action-icon icon-mail"/></a></li>
            </ul>
        </div>
    </div>
</script>

Step 2: Create the EmployeeView class

  1. Create a file named EmployeeView.js in the js directory, and define an EmployeeView constructor implemented as follows:
    var EmployeeView = function(adapter, template, employee) {
    
    }
    
  2. Define an initialize() function inside the HomeView constructor. Define a div wrapper for the view. The div wrapper is used to attach the view related events. Invoke the initialize() function inside the EmployeeView constructor function.
    var EmployeeView = function(adapter, template, employee) {
    
        this.initialize = function() {
            this.el = $('<div/>');
        };
    
        this.initialize();
    
    }
    
  3. Define a render() function implemented as follows:
    this.render = function() {
        this.el.html(template(employee));
        return this;
    };
    
  4. In index.html, add a script tag to include EmployeeView.js (just before the script tag for app.js):
    <script src="js/EmployeeView.js"></script>
    

Step 3: Implement View Routing

  1. Open app.js. In the Local Variables section, declare a variable named employeeTpl that holds the compiled template for the employee details view:
    var employeeTpl = Handlebars.compile($("#employee-tpl").html());
    
  2. In the Local Variables section, declare a variable named detailsURL that holds a regular expression to match employee details URLs.
    var detailsURL = /^#employees\/(\d{1,})/;
    
  3. In the Event Registration section, add an event listener to listen to URL hash tag changes:
    $(window).on('hashchange', route);
    
  4. In the Local Functions section, define a route() function to route requests to the appropriate view:
    • If there is no hash tag in the URL, display the HomeView
    • If there is a hash tag matching the pattern for an employee details URL, display an EmployeeView for the specified employee.
    function route() {
        var hash = window.location.hash;
        if (!hash) {
            $('body').html(new HomeView(adapter, homeTpl, employeeLiTpl).render().el);
            return;
        }
        var match = hash.match(detailsURL);
        if (match) {
            adapter.findById(Number(match[1])).done(function(employee) {
                $('body').html(new EmployeeView(adapter, employeeTpl, employee).render().el);
            });
        }
    }
    
  5. Modify the adapter initialization logic to call the route() function when the adapter has been successfully initialized:
    adapter.initialize().done(function () {
        route();
    });
    
  6. Test the application.


Part 12: Using the Location API


In this section, we add the ability to tag an employee with his/her location information. In this sample application, we display the raw information (longitude/latitude) in an alert. In a real-life application, we would typically save the location in the database as part of the employee information and show it on a map.

The code below works when running the application as a Cordova app on your device. It should also work in Chrome on the desktop when the page is served with the http:// protocol, and in Firefox, regardless of the protocol (http:// or file://).
  1. Add the geolocaton plugin to your project
    cordova plugin add org.apache.cordova.geolocation
  2. In index.html, add the following list item to the employee-tpl template:
    <li class="topcoat-list__item"><a href="#" class="add-location-btn"><p>Add Location</p></a></li>
    
  3. In the initialize() function of EmployeeView, register an event listener for the click event of the Add Location list item.
    this.el.on('click', '.add-location-btn', this.addLocation);
    

    Make sure you add this line as the last line of the initialize() function (after this.el is assigned).

  4. In EmployeeView, define the addLocation event handler as follows:
    this.addLocation = function(event) {
        event.preventDefault();
        navigator.geolocation.getCurrentPosition(
            function(position) {
                alert(position.coords.latitude + ',' + position.coords.longitude);
            },
            function() {
                alert('Error getting location');
            });
        return false;
    };
    
  5. Test the Application


Part 13: Using the Contacts API


In this section, we use the Cordova Contacts API to provide the user with the ability to add an employee to the device’s contact list.

The code below only works when running the application on your device as a Cordova app. In other words, you can’t test it in a browser on your computer.
  1. Add the contacts plugin to your project
    cordova plugin add org.apache.cordova.contacts
  2. In index.html, add the following list item to the employee template:
    <li class="topcoat-list__item"><a href="#" class="add-contact-btn"><p>Add to Contacts</p></a></li>
    
  3. In the initialize() function of EmployeeView, register an event listener for the click event of the Add to Contacts list item:
    this.el.on('click', '.add-contact-btn', this.addToContacts);
    
  4. In EmployeeView, define the addToContacts event handler as follows:
    this.addToContacts = function(event) {
        event.preventDefault();
        console.log('addToContacts');
        if (!navigator.contacts) {
            alert("Contacts API not supported", "Error");
            return;
        }
        var contact = navigator.contacts.create();
        contact.name = {givenName: employee.firstName, familyName: employee.lastName};
        var phoneNumbers = [];
        phoneNumbers[0] = new ContactField('work', employee.officePhone, false);
        phoneNumbers[1] = new ContactField('mobile', employee.cellPhone, true);
        contact.phoneNumbers = phoneNumbers;
        contact.save();
        return false;
    };
    
  5. Test the Application


Part 14: Using the Camera API


In this section, we use the Cordova Camera API to provide the user with the ability to take a picture of an employee, and use that picture as the employee’s picture in the application. We do not persist that picture in this sample application.

The code below only works when running the application on your device as a Cordova app. In other words, you can’t test it in a browser on the desktop.
  1. Add the camera plugin to your project
    cordova plugin add org.apache.cordova.camera
  2. In index.html, add the following list item to the employee template:
    <li class="topcoat-list__item"><a href="#" class="change-pic-btn"><p>Change Picture</p></a></li>
    
  3. In the initialize() function of EmployeeView, register an event listener for the click event of the Change Picture list item:
    this.el.on('click', '.change-pic-btn', this.changePicture);
    
  4. In EmployeeView, define the changePicture event handler as follows:
    this.changePicture = function(event) {
        event.preventDefault();
        if (!navigator.camera) {
            alert("Camera API not supported", "Error");
            return;
        }
        var options =   {   quality: 50,
                            destinationType: Camera.DestinationType.DATA_URL,
                            sourceType: 1,      // 0:Photo Library, 1=Camera, 2=Saved Album
                            encodingType: 0     // 0=JPG 1=PNG
                        };
    
        navigator.camera.getPicture(
            function(imageData) {
                $('.employee-image', this.el).attr('src', "data:image/jpeg;base64," + imageData);
            },
            function() {
                alert('Error taking picture', 'Error');
            },
            options);
    
        return false;
    };
    
  5. Test the Application


Part 15: Sliding Pages with CSS Transitions


Modify index.html as follows:

  1. Add pageslider.css inside the head tag in index.html:
    <link href="assets/css/pageslider.css" rel="stylesheet">
    
  2. Add a script tag to include the pageslider.js library:
    <script src="lib/pageslider.js"></script>
    
PageSlider is a micro library I host on GitHub here.

Modify app.js as follows:

  1. In the Local Variables section, declare an instance of the PageSlider object as follows:
    var slider = new PageSlider($('body'));
    
  2. In the route() function, replace the calls to $(‘body’).html() with calls to slider.slidePage() passing the same argument to the function.
    slider.slidePage(new HomeView(adapter, homeTpl, employeeLiTpl).render().el);
    

    and

    slider.slidePage(new EmployeeView(adapter, employeeTpl, employee).render().el);
    


Part 16: Explore Other Implementations


112 Responses to Cordova (aka PhoneGap) 3.x Tutorial

  1. suraj kumar gorai January 8, 2014 at 11:59 pm #

    Thanks Christophe,

    I search these type tutorial from long time.

  2. Tiendq January 9, 2014 at 5:27 am #

    Thanks, it’s the best Cordova basic tutorial until now, I believe so :)

    I also have a couple of questions:

    1. FastClick only solves delay issue, there’s nothing here mentioned about touch events, we need them to implement active state of list items and buttons. Can you add a section for it?

    2. How can use PageSlider to make difference sliding effects e.g. slide in, out, up, down, forward/back?

    Thanks,

  3. Qian January 9, 2014 at 9:11 am #

    Great efforts! Thanks for such a detailed tutorial Christophe!

    I have a question here concerning Cordova(PhoneGap) command line tool. It seems “cordova” and “phonegap” are not yet convergent for the moment. For example, there is no “phonegap platforms add ios”, adding a plugin requires “phonegap local plugin add …”.

    So when should we use cordova and when should we use phonegap? For the time being, are they maintained in the same level?

    Thank you!

  4. Christophe Coenraets January 9, 2014 at 11:14 am #

    @Tiendq.
    1. You can manage the state of list items in CSS. Look at styles.css for an example:
    .list li:active {
    background-color: #d6d6d6;
    }
    2. PageSlider is really a very simple micro library provided as a sample. It does support left and right directions, but not up and down. It can easily be extended though.

  5. Christophe Coenraets January 9, 2014 at 11:23 am #

    @Qian: The PhoneGap CLI is built on top of the Cordova CLI. The PhoneGap CLI is meant to be a bit higher level (for example, platforms are added implicitly). It is also meant to support additional services that are not part of Cordova. At his time, the only example of that is PhoneGap Build, which is why the PhoneGap CLI has those “local” and “remote” options that the Cordova CLI doesn’t have:
    phonegap local build ios (builds locally: you need the iOS SDK)
    phonegap remote build ios (builds in the cloud using PhoneGap build: you don’t need the iOS SDK installed locally)

    • José Jesús Pérez Rivas March 12, 2014 at 8:02 am #

      Hi Christophe. I see that you put in the title “Cordova (aka PhoneGap)”. Could you clarify me if some change is expected with this framework? Thanks. Regards.

  6. Ocean Lin January 9, 2014 at 11:54 am #

    Thank you very much, I am very thankful about this.

  7. Hernan January 9, 2014 at 2:04 pm #

    Excellent Tutorial, Thanks!. I had an issue when deploy it to my device for testing purpose (Android Sony Xperia S), in “HomeView” the list does not scroll up and down, but in “EmployeeView” it does.

    • Andrea January 22, 2014 at 2:48 am #

      I’m having the same problem.

      How did you solve it Hernan?

      • michas March 4, 2014 at 10:21 am #

        Easy solution is to change height of chevron icon in:
        styles.css line 173 to 42px.

    • Michael Oryl February 1, 2014 at 9:55 am #

      I believe I know the answer to that. I saw it, too. It was a CSS problem. There were actually two scrolling areas, which you could plainly see if you looked at the web app in a web browser. That’s how I figured it out.

      In topcoat-light-mobile.css at line 1508 you see this:

      .list,
      .topcoat-list {
      padding: 0;
      margin: 0;
      font: inherit;
      color: inherit;
      background: transparent;
      border: none;
      cursor: default;
      -webkit-user-select: none;
      -moz-user-select: none;
      -ms-user-select: none;
      user-select: none;
      overflow: auto; /* Change to ‘visible’ to get around the issue */
      -webkit-overflow-scrolling: touch;
      }

      If you change that overflow: auto to overflow: visible, the problem will be fixed.

      I don’t know what other issues that might cause, though, so it would likely be best to override it in the template in index.html:

      Hope that helps.

      • Michael Oryl February 1, 2014 at 9:56 am #

        It would look like this:

        <ul class=”topcoat-list list employee-list” style=”overflow: visible”></ul>

  8. Ross Martin January 10, 2014 at 10:08 am #

    Hey I noticed you accidentally created a global variable in localstorage-adapter.js on line 31 -

    var deferred = $.Deferred(),
    employees = JSON.parse(window.localStorage.getItem(“employees”)),
    employee = null; // <– ruh roh no comma
    l = employees.length; // <– global

    Thank you for the tutorial.

    • Christophe Coenraets January 16, 2014 at 9:58 am #

      Good Catch! Thanks Ross. Fixed and pushed to GitHub.

  9. Geovane January 13, 2014 at 10:26 am #

    What a great tutorial!

    It suits very well for me, I have fired my neurons trying to find a great way to do the page routing, thank you very very much!

  10. ahetman January 13, 2014 at 4:33 pm #

    can’t add android, here’s the script:

    c:\Cordova\workshop>cordova platforms add android
    Installing cordova library for android…
    Downloading cordova library for android…
    Download complete
    Installing cordova library for android…
    Creating android project…

    C:\Users\Andrei\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:126

    throw e;
    ^
    Error: An error occured during creation of android sub-project.

    C:\Users\Andrei\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:126
    throw e;
    ^
    Error: ERROR : executing command ‘ant’, make sure you have ant installed and add
    ed to your path.
    at C:\Users\Andrei\.cordova\lib\android\cordova\3.3.0\bin\lib\check_reqs.js:
    47:27
    at ChildProcess.exithandler (child_process.js:641:7)
    at ChildProcess.EventEmitter.emit (events.js:98:17)
    at maybeClose (child_process.js:735:16)
    at Socket. (child_process.js:948:11)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Pipe.close (net.js:466:12)

    at C:\Users\Andrei\AppData\Roaming\npm\node_modules\cordova\src\platform.js:
    244:30
    at ChildProcess.exithandler (child_process.js:641:7)
    at ChildProcess.EventEmitter.emit (events.js:98:17)
    at maybeClose (child_process.js:735:16)
    at Socket. (child_process.js:948:11)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Pipe.close (net.js:466:12)

    any ideas?

    • ahetman January 13, 2014 at 4:39 pm #

      additionally, for ios i get:

      c:\Cordova\workshop>cordova platforms add ios
      Creating ios project…

      C:\Users\Andrei\AppData\Roaming\npm\node_modules\cordova\node_modules\q\q.js:126

      throw e;
      ^
      Error: An error occured during creation of ios sub-project.
      ‘”C:\Users\Andrei\.cordova\lib\ios\cordova\3.3.0\bin\create”‘ is not recognized
      as an internal or external command,
      operable program or batch file.

      at C:\Users\Andrei\AppData\Roaming\npm\node_modules\cordova\src\platform.js:
      244:30
      at ChildProcess.exithandler (child_process.js:641:7)
      at ChildProcess.EventEmitter.emit (events.js:98:17)
      at maybeClose (child_process.js:735:16)
      at Process.ChildProcess._handle.onexit (child_process.js:802:5)

      thank you in advance Christophe! I am really looking forward to progressing past part 1 :)

      • ahetman January 14, 2014 at 4:58 pm #

        I installed ANT, that didn’t resolve the issue. This is on Windows 8.1, if that makes any difference.

    • ahetman January 14, 2014 at 6:00 pm #

      Ok, I finally cleared this hurdle! The problem was that I didn’t have apache ant, and I didn’t have the correct path specified for the android sdk! The android project was created successfully and now I can go on with your tutorial :)

  11. Seven January 15, 2014 at 10:54 am #

    I have a question that is so bothering me. how can I pass parameters like a user logging in to my database. can I use ms-sql database or sql light? If so how can I get the data from my sql server to the phone

    • Christophe Coenraets January 16, 2014 at 9:03 am #

      @Seven: You don’t connect your app to your remote database server. Instead, you expose a set of services (written in Java, PHP, Node, .NET, Rails, …) and your client app gets its data by invoking these services. If you want to store data locally, you use the SQLite database available on your device.

  12. Filipe January 16, 2014 at 11:39 am #

    Great tutorial, came across it while doing a related search!

    I am having problems creating a phonegap 3.x app with Backbone.js + Require.js that uses the camera plugin. I keep on getting an error when trying start the camera, seems that the plugin is not loaded.

    Have you have any similar issues?

  13. Matthew Reetz January 16, 2014 at 3:02 pm #

    Testing on an iPhone 5s I am having an issue with the Employee ListView. If I click on the search box, then press delete, I get the full list of employees. I attempt to scroll to the bottom of the list but cannot. With a series of random touches I am able to get it to scroll to the bottom. Any ideas how to fix this?

  14. ahetman January 16, 2014 at 6:50 pm #

    Minor mistake in Part 11, Step 2, number 2. HomeView is referenced instead of EmployeeView.

    • Christophe Coenraets January 16, 2014 at 10:48 pm #

      Good catch! Fixed. Thanks!

  15. Mat Martin January 17, 2014 at 6:22 am #

    Hi Christoph – I am working through your tutorial and really like it. Have gotten stuck on stage 9. The employee search was working up to stage 8 (using handlebars templates).

    When I move the view to HomeView, the initial view renders properly, but then when I type in the search box, nothing happens (i.e., no employees appear).

    The error on javascript console is:

    Uncaught TypeError: Object .search-key has no method ‘apply’

    Which I think means this line in the initialise:

    this.el.on(‘keyup’, ‘.search-key’, this.findByName);

    isn’t working. I.e., its not finding an element in the DOM with the search-key class. But that plainly exists in index.html in the html template script block:

    Employee Directory

    If I change the child selector in the jQuery on call (e.g., to “.searc-key”), the error changes (to “.searc-key”) – so I’m reasonably sure that’s it.

    Can’t figure the rest of it out though.

    Any help appreciated!

    • Mat Martin January 17, 2014 at 7:15 am #

      Platform details: running the tutorial on chrome, debugging using developer tools. Also testing on a Galaxy S4 when the chrome tests pass.

    • Mat Martin January 17, 2014 at 7:21 am #

      Also getting the warning:
      event.returnValue is deprecated. Please use the standard event.preventDefault() instead.
      And Jquery version is: 1.9.1

      • San April 10, 2014 at 4:51 pm #

        Mat, that is an internal issue with jQuery – you can see it in the console of just about every site

    • Christophe Coenraets January 17, 2014 at 8:05 am #

      Matt,
      Does Part 9′s solution work for you? It’s in www09.
      Christophe

      • Mat Martin January 17, 2014 at 8:45 am #

        Hi Christoph – I’m pretty sure I have verbatim the same code as you do in www09 (just looked at it on github). Everything was working fine up to part 8, and then the findByName stopped working in part 9.

      • Mat Martin January 17, 2014 at 8:52 am #

        On closer inspection, there was one small change which made the difference! I had the line:

        this.initialize();

        included immediately after the initialize() function definition. You had it after the render and findByName function definitions. That did it!

        Not sure why – but that’s probably because I’m new to javascript!

        BTW, I am really enjoying going through your tutorial. Its really well done.

        Perhaps in part 9, you could add a note to ensure that the ” this.initialize() ” is done after the findByName and render function definitions?

        cheers

        Mat

        • zeuz February 26, 2014 at 10:06 am #

          thank you very much, just had the same problem :)

        • Ben March 2, 2014 at 8:33 am #

          Same here, thanks for the fix mat!

        • Nitin Surana March 17, 2014 at 10:37 pm #

          Had the same problem, it worked! Although can’t understand the reason. It’ll be great if someone can explain ?

      • Adriana March 9, 2014 at 11:03 pm #

        Hello Christophe!
        Thanks a lot for your tutorial! it’s great
        I’m stuck on part 9… there is nothing showing in my app after the changes I did in part 9…the this.initialize() is in the correct place, any idea?

        Thanks in advance!

  16. Mat Martin January 17, 2014 at 6:24 am #

    Noticed the script block didn’t show in my post. The line in the block which defines the html for the search box is:

    Which plainly has the class search-key. Not sure why its not being found..

  17. Mat Martin January 17, 2014 at 6:26 am #

    Apologies, angle brackets don’t work. Is there a way of posting literal code?

    Try single quotation marks:

  18. Mat Martin January 17, 2014 at 6:27 am #

    Without angle brackets:

    input type=”search” placeholder=”search” class=”topcoat-search-input search-key”

  19. Mat Martin January 17, 2014 at 9:20 am #

    Typo?

    I think part 11, step 2: “Define an initialize() function inside the HomeView constructor.”

    Should be rather: “Define an initialize() function inside the EmployeeView constructor.”

    I.e., HomeView ==> EmployeeView not in the code, but in the text (this is probably a separate typo to the one the other commenter mentions).

  20. Mat Martin January 17, 2014 at 10:12 am #

    Just finished the tutorial. Thanks for putting this together – it was really fun to do and extremely useful.

    cheers

    Mat

    • Christophe Coenraets January 17, 2014 at 10:35 am #

      Thanks Mat. Glad to hear it was helpful.

  21. Matthew Reetz January 20, 2014 at 9:02 am #

    The list view does not scroll to the bottom on a four inch iPhone with iOS 7. I’ve tested on device and simulator. Has anyone else had this issue?

  22. Satya January 24, 2014 at 2:05 pm #

    Finally, Adobe is making amends for its sins by hiring people like you who want to educate. Now only if they reduce photoshop to about 299 pakistani rupees will i shift from pixlr.

  23. kavin January 25, 2014 at 6:52 am #

    I am using ios 7 the navigator.notification.alert does not work fine, is thr any real issue with it,I followed the steps in the pahonegap.com api docs.

  24. Paul January 27, 2014 at 2:07 pm #

    This is the clearest, most concise Phonegap tut I’ve ever read. You make it so easy! Thanks A MILLION!!

  25. Harry Moreno January 27, 2014 at 2:49 pm #

    I’m trying to emulate android from the command line. But things are really slow. I recall reading somewhere that there are ways to get hardware acceleration enabled. How can I speed up my emulation of an android app built with this tutorial?

  26. Harry Moreno January 27, 2014 at 3:30 pm #

    Making a mention of this .gitignore file https://github.com/morenoh149/cordova-employee-app/blob/master/.gitignore might be useful for those that want to use version control

  27. Héctor January 27, 2014 at 6:21 pm #

    Christophe thank you very much.

  28. Harry Moreno January 27, 2014 at 10:06 pm #

    part 11 step 2 sec 2: `Define an initialize() function inside the HomeView constructor.` should be `Define an initialize() function inside the EmployeeView constructor.`

  29. Michael Oryl January 29, 2014 at 12:53 pm #

    I see a problem in Part 9.

    This code in app.js doesn’t work for me:

    $(‘body’).html(new HomeView(adapter, homeTpl, employeeLiTpl).render().el);

    It throws an exception saying there is no “el” property available. “Uncaught TypeError: Cannot read property ‘el’ of undefined”

    Changing the code to three lines worked:

    var homeView = new HomeView(adapter, homeTpl, employeeLiTpl);
    homeView.render();
    $(‘body’).html(homeView.el);

    • Michael Oryl January 30, 2014 at 12:19 pm #

      It appears that I was missing the final “return this” in the HomeView.render() method. That caused the error.

  30. Derek January 29, 2014 at 1:22 pm #

    I’m was able to get the memory-adapter, websql-adapter and localstorage-adapter to work (shows list data). But when I used the jsonp-adapter the list is blank. What is going on… What can I do to investigate this? There is no error being reported… I’m using IOS and have tried in the emulator and in the device itself but the jsonp adapter seems to result in no errors but no data :(

    • Tinashe January 29, 2014 at 2:40 pm #

      It appears the url for the json-adapter is returning an error. If you check the file there is
      http://coenraets.org/directory/api/employees and it’s not returning the list.

      {“error”:{“text”:SQLSTATE[HY000] [2003] Can’t connect to MySQL server on ’127.0.0.1′ (111)}}

    • Derek January 29, 2014 at 4:00 pm #

      Actually when I run it in the chrome browser I see an error in the Console when using the jsonp-adapter…. The data adapter is getting initialized as I do see that the console reports that “Data adapter initialized”. But when I type a letter in the input — for example if I type “b” — then in the console I get an error. It is attempting to use the following URL to get the data (showing the text from the console):

      Resource interpreted as Script but transferred with MIME type text/html: “http://coenraets.org/directory/api/employees?name=b&callback=jQuery191018584011192433536_1391028714970&_=1391028714971″.

      Then I get a RED line showing an error as follows:

      Uncaught SyntaxError: Unexpected token :

      ….So why am I getting an Uncaught SyntaxError?? What is the enexpected token??? What can do now???

      • Derek January 29, 2014 at 4:06 pm #

        So when I type in the URL I showed above I get the same thing that someone else here has reported which is:

        {“error”:{“text”:SQLSTATE[HY000] [2003] Can’t connect to MySQL server on ’127.0.0.1′ (111)}}

        Not sure why it is mentioning 127.0.0.1.

        Not sure if this is an irrelevant detail … maybe this URL only works in a JSONP context whatever that means exactly. Does that mean perhaps that the URL:

        http://coenraets.org/directory/api/employees?name=b&callback=jQuery191018584011192433536_1391028714970&_=1391028714971

        … cannot by typed into a browser? Is this a correct URL?

        • Tinashe January 29, 2014 at 6:12 pm #

          127.0.0.1 that’s local host. So the MySQL server associated with that URL is probably only listening to localhost which I guess you can’t really do anything about since you don’t own the server.

          • kevin February 4, 2014 at 9:52 am #

            Great tutorial!
            Got the same problem. No json data returned.

  31. EvanZ February 1, 2014 at 12:02 pm #

    Thanks for doing this tutorial. Everything worked fine for me until I got to Step #8 and now I don’t see anything in the IOS emulator. Not sure what I’m doing wrong.

    • Jorge February 20, 2014 at 5:32 pm #

      I am having the same issue. After step 8, when I write on the search field, nothing happens. The console says it doesn’t find cordova.js, but the file is where is supposed to be.

  32. ramin February 4, 2014 at 10:49 pm #

    Hi Christophe, first of all many thanks for the great tutorial. I went through all steps without a problem except the Part 12 (Location API). It works perfectly in the browser but nothing happens on my Android Nexus 4, Android 4.4.2.

    I know the plugin is setup correctly because if I look at the workshop app in the settings, it says the app uses the location services.

    I was wondering if you had any ideas why it’s not working.

    Cheers,
    Ramin

    • ramin February 5, 2014 at 6:13 pm #

      Well, problem was Google’s stupid policy that you have to let them track you, enabling the Location is not enough! Thanks a bunch though.

  33. Itziar February 5, 2014 at 4:46 am #

    Thanks for the tutorial! It’s very useful.

  34. connor February 7, 2014 at 4:28 am #

    Is it possible to build ios apps running ubuntu?

    I tried `cordova platforms add ios` but got the error:

    [Error: Xcode is (probably) not installed, specifically the command `xcodebuild` is unavailable or erroring out. Output of `xcodebuild -version` is: /bin/sh: 1: xcodebuild: not found
    ]

    Do I have to install xcode on my ubuntu system?

    • William Witt February 9, 2014 at 11:10 pm #

      You can only build iOS apps on a Mac, fortunately https://build.phonegap.com allows you to build in the cloud. You still need all of the Apple issued certs in order to build and deploy.

  35. Mario February 10, 2014 at 3:28 am #

    Hi there… great tutorial but i have a little problem. I’ve installed the camera & contact package from cordova but i always get an error in the ios emulator: “Contacts API not supported”. The location service works fine, but contacts and camera are not available.

    Do you have any ideas?

    • Rick February 10, 2014 at 5:08 pm #

      Same problem here. I’m been looking at the code all weekend and restarted from the beginning too many times to count and yet have the same issue as Mario. I want to introduce PhoneGap to my students in school but I need to understand it better first.

  36. Bagara February 10, 2014 at 11:02 am #

    Hello and thanks for this excellent tutorial!

    I’m stuck in the step 11. When I click in “add location”, the app goes to the main page without notifying anything. But in the javascript console I get the error:
    “Uncaught TypeError: Object .add-location-btn has no method ‘apply’” (in chrome)
    “TypeError: i.handler.apply is not a function” (in firefox)

    I have copied and pasted all the code from above… where is the problem?

  37. javaguy February 11, 2014 at 12:13 pm #

    Hi Chris,

    Excellent tutorial and a great intro to phonegap.

    I’m a native developer (I do both iOS and Android) who once did W3, and I’ve come to take a look at how far PhoneGap has gotten since I left years ago for native.

    Quick question – how do you store state in the TopCoat navigation bar? The Navigation Bar doesn’t work correctly according to Apple Guidelines etc. and not even what I expect in the Android Activity stack.

    For example, if do the following: tap on John Williams -> James King and then tap back once, it should take me back to John Williams but instead end up on the home screen.

    Is there an easy way to do this in Single Page Apps architecture that is now prominent in PhoneGap? I realize that this is not a state / behaviour that is natural to HTTP based html sites…so I’m curious as to how + the best way to solve this problem in PhoneGap.

    Thanks

    • twork March 12, 2014 at 7:53 pm #

      Just finished up with the tutorial, and have the same question about back functionality. Were you able to come up with a good solution? Thanks.

      • javaguy March 14, 2014 at 6:12 am #

        Sadly no…been busy unfortunately. Would be really good / important to add to this tutorial I think…the random Apple reviewer assigned to your app on submission could / would reject on this issue. I’ve been rejected for lesser offences

  38. Shari February 11, 2014 at 7:06 pm #

    I follow your instruction and i am getting bellow error message, Please let me know how to fix this error

    C:\AndroidDevelopment\development\pf>cordova platforms add android
    Creating android project…
    Error: An error occured during creation of android sub-project.

    C:\Users\Sname\.cordova\lib\android\cordova\3.3.0\bin\node_modules\q\q.js:126

    throw e;
    ^
    Error: ERROR : executing command ‘ant’, make sure you have ant installed and add
    ed to your path.
    at C:\Users\Sname\.cordova\lib\android\cordova\3.3.0\bin\lib\check_reqs.j
    s:47:27
    at ChildProcess.exithandler (child_process.js:641:7)
    at ChildProcess.EventEmitter.emit (events.js:98:17)
    at maybeClose (child_process.js:743:16)
    at Socket. (child_process.js:956:11)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Pipe.close (net.js:466:12)

    at C:\Users\smohatad\AppData\Roaming\npm\node_modules\cordova\src\platform.j
    s:282:30
    at ChildProcess.exithandler (child_process.js:641:7)
    at ChildProcess.EventEmitter.emit (events.js:98:17)
    at maybeClose (child_process.js:743:16)
    at Socket. (child_process.js:956:11)
    at Socket.EventEmitter.emit (events.js:95:17)
    at Pipe.close (net.js:466:12)

    • Shari February 11, 2014 at 8:48 pm #

      I Figured it out

      This is what i did.
      1. download Ant and unzip at c:\ant
      2. find JDK in your system, If not install it . You should see a file like “JDK.6.0_27″ my my case, You might have a different version
      3, download android SDK

      Open CMD prompt and do following

      1. c:\> set ANT_HOME = c:\ant
      2. c:\> set PATH=%PATH%;%ANT_HOME%\bin
      3. c:\> set JAVA_HOME = c:\jdk1.6.0_27
      4. C:\f>set PATH=%PATH%;;C:\AndroidDevelopment\adt-
      bundle-windows-x86_64-20131030\sdk\platform-tools;C:\AndroidDevelopment\adt-bund
      le-windows-x86_64-20131030\sdk\tools

      Once all these steps completed.
      Now run below command

      “cordova platforms add android”

      You should see a success message and Android is installed in your dir

  39. Vinny M. February 12, 2014 at 8:29 pm #

    Hey been looking at some of your tutorial for a while I think they’re thorough, I was wondering if you’d know how to add the facebook plugin? I’ve tried by adding the following line in the config.xml file :

    Then when I compile I get an error on line 698 of build.xml located in adt for android project I havent tried for ios. ? Have you ever had an issue integrating the facebook plugin ?

    Cheers,

  40. ospider February 14, 2014 at 1:42 am #

    Wow, after a day of googling, I only find this tutorial is great. Others are either too old (written in 2012 or earlier) or too vogue. Thank you.

  41. Rod Knowlton February 19, 2014 at 4:15 pm #

    Christophe,

    Great tutorial, thanks for creating it.

    One question—is there a reason you use classes for identification of singular items, for example `.search-key`?

    It seems that ‘id’ would make more sense semantically, so I’m wondering if there’s a Cordova related reason.

    Thanks,

    Rod

  42. David February 20, 2014 at 2:47 am #

    Hi Christophe,
    Thanks for this great tutorial.

  43. Jorge February 20, 2014 at 11:08 am #

    I Part 5: Step 3 We see:

    When running on a device with the navigator.notification object available (the dialogs plugin is installed), override the window.alert() function and replace its default implementation with a call to navigator.notification.alert(). Add this code to the “Event Registration” block:

    document.addEventListener(‘deviceready’, function () {
    if (navigator.notification) { // Override default HTML alert with native dialog
    window.alert = function (message) {
    navigator.notification.alert(
    message, // message
    null, // callback
    “Workshop”, // title
    ‘OK’ // buttonName
    );
    };
    }
    }, false);

    Where is this code located?? In which file I am supposed to modify that??

    • duedl0r March 24, 2014 at 12:56 pm #

      app.js

  44. Tristan February 25, 2014 at 4:45 pm #

    Hi,

    This guide has been great, thank you. Where would I change the database location for connecting a mongodb with nodejs to an external mongodb (not on localhost)?

    I cannot for the life of me work out where to put the database/username/password information but the app works great as localhost.

    Many thanks in advance.
    Tristan

  45. Brad February 25, 2014 at 4:58 pm #

    Yeah! This tutorial totally rocks for cordova hello world x10… Super thank you!

  46. Dawesi March 2, 2014 at 8:18 am #

    Use Sencha and you’ll save yourself a tonne of work. Nice article tho.

  47. Peter March 2, 2014 at 7:47 pm #

    Hi!
    Thanks for a great series.
    I’ve got a few questions: which of your versions has the best response (closest to NATIVE)
    what has better performance angular js VS backbone js ?

    Thanks

  48. Sani Elfishawy March 3, 2014 at 12:42 pm #

    Great tutorial thanks!

    Do you know whether you use the cordova CLI to build with a particular (post 3.0) version of Cordova?

    cordova create …
    cordova platform add …

    seems to add the most recent version of cordova framework. Currently 3.4.0. What if you wanted to build with 3.1.0 for example?

  49. LA March 5, 2014 at 10:29 am #

    Just wanted to THANK YOU for this tutorial. Extremely helpful.

  50. Alberto Lopez March 6, 2014 at 12:08 am #

    Hello Christophe,

    I have one question, I hope you could help me giving me some advice, what would you do if you were required to authenticate access to this app?

    regards
    Alberto Lopez

  51. Sam March 16, 2014 at 7:41 pm #

    Thank you so much for this. Straight to the point and very informative, you may have saved me from going insane! Thanks again.

  52. Malek March 20, 2014 at 5:46 pm #

    Hi, I don’t have an app.js file, I ma using cordova 3. Any thoughts ?

  53. Jay T. March 20, 2014 at 10:35 pm #

    Excellent tutorial – excellent. I get api not supported on the camera and contacts – at the very end but everything else works amazingly. deployed to kit kat phone – not sure but I’ll keep trying to figure it out.

  54. Jay T. March 21, 2014 at 12:16 pm #

    I think I figured it out – by default – this line in the config.xml says cordova… not phonegap..
    updated to…

    xmlns:gap=”http://phonegap.com/ns/1.0″>

    plus added to config file….

  55. linda March 21, 2014 at 1:12 pm #

    Hi!

    First of all, it’s a very good tutorial.
    Even for people who doesn’t speak english, is easy to understand.
    However, i’m trying to switch to ‘JSONPAdapter’ and i’m having problems, it doesn’t work :(

    When I test in a navigator, it blocked by a script…

    And in the phone, it doesn’t show anything…

    Any idea?

  56. Mark March 25, 2014 at 12:25 am #

    Awesome tutorial!

  57. Alejandro March 25, 2014 at 7:43 am #

    First at all, congratulations. I have a very rare issue. I can’t execute any plugin inside the route() function after a hash chage. There is no error, it just skips the window var. For example, I have inAppBrowser installed. If I run windows.open on the first steep of the route() function, it works. If I change hash and execute again the window.open it doesn’t do anything. It also happends with the console.log, etc…

    any help?

  58. Carlos Garcia March 26, 2014 at 11:24 am #

    I’m having the same problem as other people here: when I try to use the JSONPAdapter, the list won’t show up. I tried setting up a local json file (although I might be doing it wrong, since I’m new to json) but it’s still not showing up any data. Any help here?

  59. ttemp March 29, 2014 at 8:34 pm #

    great tutorial :) I spend like 2 days searching for something good enough to start with this is great :)

    one thing though i really think you should add all the phonegap build quirks (config.xml needs to change to give permissions to camera and contacts and geolocation) moreover there are some updates ( contacts api need to be rewriten by https://github.com/apache/cordova-plugin-contacts/blob/431eeea9f5d7ea738b3b8277162a4ab4313dc32f/doc/index.md and so does geolocation at least for galaxy s2)

    thanks this is really great

  60. Rada April 3, 2014 at 3:25 pm #

    I got a problem with JSONPAdapter. Anyone have a solution?

  61. Chris April 8, 2014 at 5:27 am #

    Thanks Christophe for this great tutorial. You just unlocked a lot of doors for me

  62. vitamix blender April 8, 2014 at 10:05 pm #

    This electric mixer works very well and measures
    about 3 x 3 x 14 inches. No should decant it bit by bit right into a blender jug then into another container.

    With the simplicity of use, also comes a design which is
    meant for comfortable usage.

  63. Steve James April 9, 2014 at 5:16 am #

    Hi Christophe,

    Greaqt titorial,

    I have a problem however, whilst adding android platform I get the following error:
    Error ENOENT, no such file or directory C:|users\Dell\.cordova\lib\android\cordova\3.4.0\VERSION

    It is true that this directory doesn’t exist, but then I didn’t create the rest of the structure, I just followed the instructions so I don’t know why or how this should exist.

    All help appreciated.

    Thanks,
    Steve

    • Steve James April 10, 2014 at 9:08 am #

      Have sorted it.
      I reloaded cordova several times but it was only when I deleted the install and reloaded it that the problem cease. In the meantime, I loaded JDK and ANT. Not sure if these had any effect but would have expected different errors if they were the problem. I already had ADT Eclipse loaded BTW.

  64. David Chen April 11, 2014 at 8:32 pm #

    Great tutorial!

    I followed the tutorial and sometimes stuck in one place and didn’t know why. Google online and find debug in chrome is very useful:

    chrome://inspect

  65. Safaa Alnablsi April 16, 2014 at 2:38 am #

    I’ve finished the tutorial , thank you very much for this great effort :)
    everything worked perfectly with me, but I have a few questions:
    I want to make a setting page with two text boxes and save button
    problem is I can’t slide to home after clicking the save because route function is written in app.js
    and the rout method depends on hash, so home & setting would be the same.
    can you help me on that ? I can’t find any useful tutorial except yours .. and I ad build my app on yours

  66. www.bestdentistqueens.biz April 16, 2014 at 10:45 pm #

    I pay a visit every day a few sites and sites to read content, but this website
    offers feature based content.

Trackbacks/Pingbacks

  1. New Cordova/PhoneGap 3.x Tutorial | Christophe Coenraets - January 8, 2014

    [...] Cordova/PhoneGap 3.x Tutorial [...]

  2. PhoneGap 3.x Tutorial - January 17, 2014

    […] The tutorial can you find here. […]

  3. PhoneGap for Hybrid App Development | Robin C Samuel - January 30, 2014

    […] I’m would suggest Mr.Coenraets tutorial for phonegap beginner, as there is a well explained tutorial in his blog. http://coenraets.org/blog/cordova-phonegap-3-tutorial/ […]

Leave a Reply