Javascript Debugging in WebStorm/PhpStorm

The Decline of Offline Chat

image

I want to preface this post with the point that I love everything technology has brought us, as well as the advancements in the webosphere. With every great advancement, comes some side effects. A crucial side effect that I want to address today is the decline in social interaction without the use of text messaging on phones or instant messaging. That, and the need to browse your phone when wanting to avoid social interaction.

So, you must be asking yourself, why am I choosing a topic for my second post that goes against everything I love about the digital space, mobile.

Well … it all starts out with my morning drive, and every morning drive before today’s. Every day I leave for work, I pass school bus stops, packed with students ready to face the day. Now, when I was younger and waiting at the stop, I couldn’t wait to see my friends. We would talk about the previous days events, the neighborhood happenings and just random ramblings. Fast forward to today, kids seem to do nothing of the sort. Every one of them are glued to their mobile devices or iPods, clueless of the world around them. The only interaction these kids have with their peers anymore are through digital middlemen.

I would love to say that this sort of behavior is a trend with the younger generation, but I would be a fabulist. My generation is also guilty of playing a part in the decline of offline chat. Not so much as the example above, but in the way we act around our friends during lunch outings and happy hours. Raise your hands if you’ve played on your phone during a lunch outing with co-workers or friends. Don’t feel bad, mine is raised too.

It’s not that I don’t like my friends. They’re great. Often times I don’t even realize I do this. It doesn’t hit me that I’m completely out of it until I look up and see half the table hypnotized by that digital glow protruding from their droids or iPhones.

So, they say the first step to an addiction is acknowledgement of a problem. Mark step one off the list. It finally hit me at 8:25 this morning. I have a problem and I can beat it. I plan to take steps to increase my offline chat. I’m taking it on myself to turn my mobile device off or leave it behind when I venture off for lunch with friends or coworkers. Same goes with happy hours and dinner outings. I plan to communicate more in person or verbally over the phone rather than lol’ing or responding in some other form of text acronyms.

I will be victorious! Will you?

That being said, love using your mobile device. Browse for recipes, look up movie times, wiki the worlds tallest building … but lets keep that to a non-social interaction time. We have plenty of it.

Let’s take back offline chat and keep from being a socially inept society.

- BS

AngularJS: An MV* on Steroids

image

The advancement of the web is moving at the speed of light. It’s easy to get lost in the sea of frameworks out there, shooting in the dark trying to figure out which one to choose for your next application. With so many that come to fruition, how are we suppose to know which will keep its traction through its adolescent life. There is a great site that helps you view the differences between these MV* frameworks. It’s called TodoMVC. I recommend researching what is out there. Out of all of them, Angular was the right fit for me, and for my coding style.

There are a lot of things I look for in a framework. Some key factors to me are:

  • Ease of Use
  • A well-documented API
  • An active, strong community
  • It’s backed by a known enteprise
  • It’s Scalable
  • It’s Extensible
  • It’s Modular

Fortunately, Angular hits on all of these points. In my opinion, Angular is as native as you can get to writing HTML/Javascript with a third-party MV* framework. It has a strong, active community, and it’s backed by Google…yes, Google. You can find more information and download the framework here.

I am currently working on an Angular Series, which will range from covering the basic concepts of Angular to writing a real-world application. Below is an outline of what will be covered in this series:

  1. Concepts
    1. Scope
    2. Model
    3. Controller
    4. View
    5. Directives
    6. Filters
    7. Services
    8. Modules
    9. Dependency Injection
  2. Putting some of the concepts to practice
  3. Building a sample application using JSON content
  4. Writing a real-world application with a RESTful Service & MongoDB

In no time, you will be up and running building applications that people will use on a daily basis. Please feel free to ask any questions or request any subject matter in the “Pick my Brain” section.

- BS

Using HTML5 Geolocation with the Google Maps API

I recently had to implement a custom Google Map for a friends website. After writing down all the business requirements for what this “Locator” map implementation would take, I started sifting through the Google Maps API. I worked with the Map API on a previous site, but this implementation was going to be a little more robust. It needed custom markers and an address locator. It also needed to utilize the HTML5 Geolocation API.

Before I start, I have to commend Google on upkeeping a great developer API site with plenty of well detailed documentation covering their wide assortment of APIs. Below is a list of what was needed to build out the custom map solution:

  1. Geolocation from users device
  2. Address/Zip Code Finder
  3. Custom Icon for the location of their brewery
  4. Markers for where they sell their products
  5. Information on the places they sell their products

You can view the demo of this code here.

Google Maps API

The first thing you need is the Google Maps API. I prefer to load the script from Googles hosted servers. You can acquire the link on their Maps API site. Below is a code snippet of loading the script right before the closing body tag. I also included my custom map script.

<!doctype html>
<html>
<head>
<title>Google Map Tutorial</title>
</head>
<body>

//HTML goes here

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script type="text/javascript" src="/custom_maps.js"></script>

</body>
</html>

HTML

Now that we have our Google Maps API loaded in, lets add the little HTML to get this map up-and-running. The following code includes the form for the Address/zip code search as well as the actual map canvas that gets built from the Maps API.

<!doctype html>
<html>
<head>
    <title>Google Map Tutorial</title>
</head>
<body>

<form>
    <input type="text" placeholder="Enter an address or zip code..."  />
    <button type="submit" class="btn btn-primary"> Search</button>
</form>

//insert map below
<div id="mapCanvas"></div>

<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script type="text/javascript" src="/custom_maps.js"></script>

</body>
</html>

The CSS

The next piece is the CSS for the map. You should really place your CSS in an external stylesheet, linked in your head section. For simplicity of this tutorial, I will display the CSS below

#mapCanvas
{
  width:500px;
  height:500px;
  border:6px double;
}

The Javascript

Now we get to the fun part. The rest of the code will be located in the custom_maps.js file you inserted after the Google Maps API reference. I’m going to start with the HTML5 Geolocation first. You can find out more about the Geolocation API here.

HTML5 Geolocation:

The first thing we want to do is detect if the users device allows for the HTML5 Geolocation spec. We can do that with a simple if statement.

<script type="text/javascript">
    if(navigator.geolocation){
        //do geolocation code here
    } else {
        //no geolocation support
        //lets provide a fallback in case we have no support
    }
</script>

If the users device supports the HTML5 Geolocation spec, then we want to get the users position. The Geolocation API supports two methods to get this. One is the getCurrentPosition method, which is a one-time position request. The other is the watchPosition method, which is a repeated position request method. We will be using the watchPosition method. Both allow for success and error callback methods.

Below is an example of getting a users current position, supporting both a success and error callback. If a user declines or if there is an error receiving the users location, we will supply default geo-coordinates.

        
<script type="text/javascript">
    if(navigator.geolocation){
        //declare an array to store the coords(lat,lng)
        var latLng = [];
        navigator.geolocation.watchPosition(function(pos){
            //in our success callback
            //push the coords into our latLng object
            latLng.push({
                'lat': pos.coords.latitude,
                'lng': pos.coords.longitude
            });
        }, function(error){
            //did not allow users location or a generic error
            //push or default geo-coordinates
            latLng.push({
                'lat': 32.472,
                'lng': -97.805
            });
        });
    } else {
        //no geolocation support
        //lets provide a fallback in case we have no support
        latLng.push({
            'lat': 32.472,
            'lng': -97.805
        });
    }
</script>

Putting it all Together

Now that we know how to get the users geo-coordinates, lets combine it with the Google Maps API. I’m going to build a custom map object literal, which will namespace this object for our custom map module. The next couple of sections will break apart our CUSTOM_MAP object literal.

Declare the Object Literal:
        
<script type="text/javascript">
    var CUSTOM_MAP = {
        //variables and methods go here
    };
</script>
Set Variables:
        
<script type="text/javascript">
    var CUSTOM_MAP = {
        geocoder:'',
        map: '',
        //methods below here
    };
</script>
Init Method:
        
<script type="text/javascript">
    var CUSTOM_MAP = {
        geocoder:'',
        map: '',
        init: function(){
            //get user location
            CUSTOM_MAP.getUserLocation(function(defaultLatLng){
                //get starting coords
                var mainLatlng = new google.maps.LatLng(defaultLatLng[0].lat, defaultLatLng[0].lng),
                    //set starting options for map
                    mapOptions = {
                        zoom: 10,
                        center: mainLatlng,
                        mapTypeId: google.maps.MapTypeId.ROADMAP
                    },
                    revolver,
                    //info window for icons clicked
                    revInfo = new google.maps.InfoWindow({
                        content: "<p><b>Revolver Brewing</b></p><p>5600 Matlock Rd<br/>Granbury, TX<br/>76049</p>"
                    }),
                    //set custom coords of locations on map
                    //this could be done in an external file
                    coords = [//granbury
                    "32.44198759273831:-97.78741836547852:Eighteen Ninety Grille & Lounge:115 East Pearl Street<br/>Granbury, TX, 76048 ", "32.44126323457845:-97.78690338134766:Hoffbrau Steaks:315 E. Hwy. 377<br/>Granbury, TX, 76048", "32.44191515718427:-97.78849124908447:Fuzzy's Taco:115 W Pearl St<br/>Granbury, TX, 76048", "32.416196857732615:-97.78827667236328:Stumpy's Lakeside Grille:2323 South Morgan Street<br/>Granbury, TX, 76048", "32.46284660956346:-97.71583557128906:Bootlegger Liquor:4517 E Highway 377<br/>Granbury, TX 76049",//dallas 
"32.791892438123696:-96.81976318359375:Meddlesome Moth:1621 Oak Lawn Ave.<br/>Dallas, TX 75207"];
                
                //init geocoder MAP API
                CUSTOM_MAP.geocoder = new google.maps.Geocoder();
                
                //user default marker
                new google.maps.Marker({
                    map: map,
                    draggable: false,
                    position: mainLatlng
                });
                revolver = new google.maps.Marker({
                    map: map,
                    draggable: false,
                    position: new google.maps.LatLng(32.472, -97.805),
                    //set custom icon here
                    icon: '/Content/img/common/revIcon.png'
                });

                google.maps.event.addListener(revolver, 'click', function () {
                    revInfo.open(map, revolver);
                });

                for (var c in coords) {
                    var ll = coords[c].split(':');
                    CUSTOM_MAP.addMarkers(ll[0], ll[1], ll[2], ll[3], map);
                }
                
                //create map
                map = new google.maps.Map(document.getElementById('mapCanvas'), mapOptions);
            });
        }
    };
</script>
Geolocation Method(getUserLocation):
        
<script type="text/javascript">
    var CUSTOM_MAP = {
        //variables and init...,
        getUserLocation: function(callback){
            var latLng = [];
            if (navigator.geolocation) {
                navigator.geolocation.watchPosition(function (pos) {
                    //success method
                    latLng.push({
                        'lat': pos.coords.latitude,
                        'lng': pos.coords.longitude
                    });

                    //check if callback is a function
                    if (typeof callback === "function") {
                        callback(latLng);
                    }
                }, function (error) {
                    //did not allow or location
                    latLng.push({
                        'lat': 32.472,
                        'lng': -97.805
                    });

                    //check if callback is function
                    if (typeof callback === "function") {
                        callback(latLng);
                    }
                });
            } else {
                //if geolocation is not supported
                latLng.push({
                    'lat': 32.472,
                    'lng': -97.805
                });
                //check if callback is a function
                if (typeof callback === "function") {
                    callback(latLng);
                }
            }
        }
    };
</script>
Add Custom Markers:
        
<script type="text/javascript">
    var CUSTOM_MAP = {
        //variables and init, getUserLocation...,
        addMarkers: function(lat, lng, name, address, MAP){
            var info = new google.maps.InfoWindow({
                        content: "<p><b>" + name + "</b><br/>" + address + "</p>"
                    }),
                    marker = new google.maps.Marker({
                        map: MAP,
                        draggable: false,
                        position: new google.maps.LatLng(lat, lng),
                        title: name,
                        animation: google.maps.Animation.DROP,
                        icon: '/Content/img/common/beerIcon.png'
                    });

            google.maps.event.addListener(marker, 'click', function () {
                info.open(MAP, marker);
            });
        }
    };
</script>
Code Address Method(form submit):
        
<script type="text/javascript">
    var CUSTOM_MAP = {
        //variables and init, getUserLocation, addMarkers...,
        codeAddress: function(){
            var address = document.getElementById('address').value;

            CUSTOM_MAP.geocoder.geocode({ 'address': address }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    map.setCenter(results[0].geometry.location);
                    var marker = new google.maps.Marker({
                        map: map,
                        position: results[0].geometry.location
                    });
                } else {
                    alert('Geocode was not successful for the following reason.' + status);
                }

            });
        }
    };
</script>

That’s a Wrap

The full custom_map.js file is below.

        
<script type="text/javascript">
    var CUSTOM_MAP = {
        geocoder:'',
        map: '',
        init: function(){
            //get user location
            CUSTOM_MAP.getUserLocation(function(defaultLatLng){
                //get starting coords
                var mainLatlng = new google.maps.LatLng(defaultLatLng[0].lat, defaultLatLng[0].lng),
                    //set starting options for map
                    mapOptions = {
                        zoom: 10,
                        center: mainLatlng,
                        mapTypeId: google.maps.MapTypeId.ROADMAP
                    },
                    revolver,
                    //info window for icons clicked
                    revInfo = new google.maps.InfoWindow({
                        content: "<p><b>Revolver Brewing</b></p><p>5600 Matlock Rd<br/>Granbury, TX<br/>76049</p>"
                    }),
                    //set custom coords of locations on map
                    //this could be done in an external file
                    coords = [//granbury
                    "32.44198759273831:-97.78741836547852:Eighteen Ninety Grille & Lounge:115 East Pearl Street<br/>Granbury, TX, 76048 ", "32.44126323457845:-97.78690338134766:Hoffbrau Steaks:315 E. Hwy. 377<br/>Granbury, TX, 76048", "32.44191515718427:-97.78849124908447:Fuzzy's Taco:115 W Pearl St<br/>Granbury, TX, 76048", "32.416196857732615:-97.78827667236328:Stumpy's Lakeside Grille:2323 South Morgan Street<br/>Granbury, TX, 76048", "32.46284660956346:-97.71583557128906:Bootlegger Liquor:4517 E Highway 377<br/>Granbury, TX 76049",//dallas
"32.791892438123696:-96.81976318359375:Meddlesome Moth:1621 Oak Lawn Ave.<br/>Dallas, TX 75207"];
                
                //init geocoder MAP API
                CUSTOM_MAP.geocoder = new google.maps.Geocoder();
                
                //user default marker
                new google.maps.Marker({
                    map: map,
                    draggable: false,
                    position: mainLatlng
                });
                revolver = new google.maps.Marker({
                    map: map,
                    draggable: false,
                    position: new google.maps.LatLng(32.472, -97.805),
                    //set custom icon here
                    icon: '/Content/img/common/revIcon.png'
                });

                google.maps.event.addListener(revolver, 'click', function () {
                    revInfo.open(map, revolver);
                });

                for (var c in coords) {
                    var ll = coords[c].split(':');
                    CUSTOM_MAP.addMarkers(ll[0], ll[1], ll[2], ll[3], map);
                }
                
                //create map
                map = new google.maps.Map(document.getElementById('mapCanvas'), mapOptions);
            });
        },
        getUserLocation: function(callback){
            var latLng = [];
            if (navigator.geolocation) {
                navigator.geolocation.watchPosition(function (pos) {
                    //success method
                    latLng.push({
                        'lat': pos.coords.latitude,
                        'lng': pos.coords.longitude
                    });

                    //check if callback is a function
                    if (typeof callback === "function") {
                        callback(latLng);
                    }
                }, function (error) {
                    //did not allow or location
                    latLng.push({
                        'lat': 32.472,
                        'lng': -97.805
                    });

                    //check if callback is function
                    if (typeof callback === "function") {
                        callback(latLng);
                    }
                });
            } else {
                //if geolocation is not supported
                latLng.push({
                    'lat': 32.472,
                    'lng': -97.805
                });
                //check if callback is a function
                if (typeof callback === "function") {
                    callback(latLng);
                }
            }
        },
        addMarkers: function(lat, lng, name, address, MAP){
            var info = new google.maps.InfoWindow({
                        content: "<p><b>" + name + "</b><br/>" + address + "</p>"
                    }),
                    marker = new google.maps.Marker({
                        map: MAP,
                        draggable: false,
                        position: new google.maps.LatLng(lat, lng),
                        title: name,
                        animation: google.maps.Animation.DROP,
                        icon: '/Content/img/common/beerIcon.png'
                    });

            google.maps.event.addListener(marker, 'click', function () {
                info.open(MAP, marker);
            });
        },
        codeAddress: function(){
            var address = document.getElementById('address').value;

            CUSTOM_MAP.geocoder.geocode({ 'address': address }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    map.setCenter(results[0].geometry.location);
                    var marker = new google.maps.Marker({
                        map: map,
                        position: results[0].geometry.location
                    });
                } else {
                    alert('Geocode was not successful for the following reason.' + status);
                }

            });
        }
    };
</script>

You can view the demo of this code here.

Thanks for reading, and look forward to more articles. My next series will cover the basics of AngularJS and why it’s so awesome!

- BS