JavaScript Through Facebook Hacks/Hackers Buenos Aires. Aug., 2012
Follow Along
http://j.mp/hhba-js
Schedule
1. JS Crash Course
2. DOM/jQuery
3. Facebook API
4. Your turn
Running JS in the browser
<script>
// code here
</script>
<script src="yourscript.js"></script>
The console
Intro.
Programming is 3 things
Assignment, Conditional, Iteration
Assignment
Conditional
if (name === "Al") {
console.log("hello, " + name);
}
Iteration
var names = ["Al", "Joe", "Sally"];
for (var i = 0; i < names.length; i++ ) {
console.log(name + " is here!");
}
Let's go!
var address = 20;
var street = "Cooper Sq.";
var city = "New York";
var state = "NY";
var zip = 10003;
city + state;
//=> "New York, NY"
address + zip;
//=> 10023
address + street + zip;
//=> "20Cooper Sq.10003"
address + ", " + zip;
//=> "20, 10003"
address + " " + street;
//=> ?
address + " " + street;
//=> "20 Cooper Sq."
var initial = 10;
10 += 10;
//=> 20;
var str = "";
str += initial;
//=> ?;
var str = "";
str += initial;
//=> "10";
var a = 3;
var b = 3;
a === b
//=> true
var a = 3;
var b = 3;
if (a === b) {
console.log('they match');
}
var a = 1;
var b = 2;
if (a !== b) {
console.log("They don't match!");
}
var a = 3;
var b = 3;
if (a === b) {
console.log('they match');
} else {
console.log("they don't match");
}
var printAddress = function(address, street, city, state, zip) {
str = "";
str += address + " " + street;
str += "<br>";
str += city + ", " + state + " " + zip;
return str;
}
printAddress(address, street, city, state, zip);
//=> "20 Cooper Sq.<br>New York, NY 10003"
var address = 10;
printAddress(address, street, city, state, zip);
//=> "10 Cooper Sq.<br>New York, NY 10003"
var person = {};
person.first_name = "Al";
person.last_name = "Shaw";
var person = {};
person['first_name'] = "Al";
person['last_name'] = "Shaw";
var people = [];
people.push(person);
people[0];
//=>
{
first_name : "Al",
last_name : "Shaw"
}
var students = ["Amy", "Joe", "Sally", "Harry"];
var i;
for (i = 0; i < students.length; i += 1) {
console.log(students[i] + " is in class today");
}
//=>
Amy is in class today
Joe is in class today
Sally is in class today
Harry is in class today
var even_numbers = [2, 4, 6, 8, 10];
var odd_numbers = [];
// how can we programmatically
// fill up this array with odd numbers
var i = 0;
for (i = 0; i < even_numbers.length; i+= 1) {
odd_numbers.push(even_numbers[i] + 1);
}
console.log(odd_numbers);
//=> [3, 5, 7, 9, 11]
// Who's in class today?
var attendance = {
"Amy" : true,
"Joe" : true,
"Sally" : false,
"Harry" : true
};
var isInClass = function(student) {
if (attendance[student]) {
console.log("Here");
} else {
console.log("Absent");
}
};
// Try it
isInClass("Sally");
//=> Absent
isInClass("Joe");
//=> Here
JS vs. The DOM
HTML: Structure
CSS: Presentation
JS: Behavior
// the DOM
// scripting the elements on a web page
var target = document.getElementById("target");
the DOM is the page from JavaScript's perspective
jQuery makes the DOM easy
jQuerify your browser
so you get jQuery in your console
http://www.learningjquery.com/2006/12/jquerify-bookmarklet
var target = $("#target");
vs.
document.getElementById("target");
Use CSS Syntax
tag: $("input");
id: $("#target");
class: $(".target");
attributes: $("input[type=submit]");
Add Behavior!
<div id="target"></div>
<div id="result"></div>
$("#target").click(function() {
$("#result").html("You clicked!");
});
//=> <div id="result">You clicked!</div>
OR
<div id="target"></div>
<div id="result"></div>
var showClickText = function() {
$("#result").html("You Clicked");
}
$("#target").click(showClickText);
jQuery isn't a JS Replacement
Use jQuery to query the DOM
Manipulation, Traversal, AJAX
There are slides in this deck.
// That just happened live!
There are <span class="slidect"></span> slides in this deck.
$(".slidect").html($("div").length)
<style>
.box {
width:200px;
height:200px;
}
.redbox {
background:#ff0000;
}
.blackbox {
background:#000;
}
</style>
<div class="box redbox"></div>
$(".box.redbox").addClass("blackbox");
$(".box.redbox").removeClass("redbox");
<div class="goaway"></div>
$(".goaway").remove();
Add CSS on the fly!
// turn redbox into purplebox
$(".box.redbox").css("background", "purple");
// Bind to elements
$(".target").click()
// an expansion of
$(".target").bind("click");
"Binding" is trapping events the browser emits whenever the user does anything
$(".target").click( /* do something */ );
// Pass a "callback" function
$(".target").click(function() {});
// Pass a "callback" function
$(".target").click(function() {
console.log("You clicked the target");
});
Callbacks, by convention, are functions that get called after other functions run.
// Example
var doSomething(cb) {
doTask();
if (cb) { cb() }; //callback is invoked
}
// Calling the function
doSomething(function() {
//do something else;
})
// You don't have to invoke the callback function,
// the parent function invokes it.
Operating on many elements with jQuery
// turn all links red
$("a").each(function() {
$(this).css("color", "red");
})
If you understand `this`, you understand JavaScript.
But, to understand `this`, you need to understand prototypes.
This gets kinda advanced.
// set up the room
var Animal = function(kind, sound) {
this.kind = kind;
this.sound = sound;
}
Animal.prototype.speak = function() {
console.log(this.sound);
}
// instantiate it
var cat = new Animal("cat", "meow")
// make it speak
cat.speak()
//=> meow
// instantiate it
var bear = new Animal("bear", "grrrr")
// make it speak
bear.speak()
//=> grrr
// add a new method on the fly
Animal.prototype.sayMyName = function() {
console.log(this.kind);
}
cat.sayMyName();
//=> "cat";
Animal is what we call a `class`.
It can create as many animals as you want.
Use `this` to stash attributes in the class.
Why you should care, if you're just using jQuery.
`this` is slippery with callbacks.
// Let's have the speak method
// bind to a click handler. So whenever we click a link
// it'll meow in the console
// WARNING, this will not work.
Animal.prototype.speak = function() {
$("a").click(function() {
console.log(this.sound);
});
}
Scope!
// JavaScript has functional scope.
// `this` will no longer be in scope within
// a child function.
// How do we get around that?
Animal.prototype.speak = function() {
var that = this;
$("a").click(function() {
console.log(that.sound);
});
}
cat.speak(); //=> binds to links
// $(this) creates a jQuery object
// for the element that moves into scope
// on each iteration.
$("a").each(function() {
$(this).css("color", "red");
})
$(".box.redbox").click(function() {
$(this).addClass("purplebox");
});
Digression on a digression. Scope is really important
// we use var to maintain scope.
// variables without the `var` keyword are global
var myFunction = function() {
var val = 10;
}
myFunction();
console.log(val);
//=> ReferenceError: val is not defined
// we use var to maintain scope.
// variables without the `var` keyword are global
var myFunction = function() {
// no var keyword!
// We created a global variable.
// Avoid doing this!
val = 10;
}
myFunction();
console.log(val);
//=> 10
// However,
// Inner functions always get access to
// outer function variables.
// This is called "closure"
// Because the outer function "closes over"
// the inner function
var outer = function() {
var val = 10;
var inner = function() {
console.log(val);
}
inner();
}
outer();
//=> 10;
Why do we crave `closure`?
// we'll "close over" the kind variable,
// when creating a new calculator
// so it will always do that operation, even
// after that variable is gone forever!
var createCalculator = function(kind) {
var operation = kind;
return function(val1, val2) {
if (operation === "add") {
return val1 + val2;
}
if (operation === "subtract") {
return val1 - val2;
}
}
}
var adder = createCalculator("add")
adder(1, 2)
//=> 3
Putting it together, we can figure out how jQuery's $ function works
var $ = function(selector) {
// get selector
var els = document.querySelectorAll(selector);
var methods = {
click : function(cb) {
for (var i = 0; i < els.length; i++) {
els[i].addEventListener("click", cb, false);
}
return this;
},
hide : function() {
for (var i = 0; i < els.length; i++) {
els[i].style.display = "none";
}
return this;
},
show : function() {
for (var i = 0; i < els.length; i++) {
els[i].style.display = "block";
}
return this;
}
}
return methods;
}
AJAX
Asynchronous JAvascript with XML. (Now usually JSON)
Bring remote data into your web page
The Facebook API
http://graph.facebook.com/ashaw
{
"id": "2902652",
"name": "Al Shaw",
"first_name": "Al",
"last_name": "Shaw",
"link": "https://www.facebook.com/ashaw",
"username": "ashaw",
"gender": "male",
"locale": "en_US"
}
// JSON is just JavaScript Objects
$.getJSON(url, callback)
// Notice we're not creating a jQuery object,
// we're using a jQuery "class method."
// Remember prototypes
var myElement = $("#target");
myElement.hide(); // these are "instance methods"
myElement.show(); // We have "instantiated" a new jQuery object,
// much like our Animal class, we're operating
// on one instance of that class.
// `getJSON` is a class method, meaning it's part of jQuery, but
// not a jQuery object. So we call it with $.getJSON.
var profile;
$.getJSON("http://graph.facebook.com/ashaw?callback=?", function(resp) {
profile = resp;
});
console.log(profile.first_name);
//=> Al
Let's dynamically add some Facebook data to a web page
// The Markup
<h1></h1>
<a href="#">Click here to see my profile</a>
// Let's stick real data in that HTML
$(document).ready(function() {
var url = "http://graph.facebook.com/ashaw"
$.getJSON(url + "?callback=?", function(resp) {
$("h1").html(resp.first_name);
$("a").attr("href", resp.link)
});
});
<h1>Al</h1>
<a href="https://www.facebook.com/ashaw">Click here to see my profile</a>
Let's build an app that gives you a full name from a username
<input type="text" id="username" />
<input type="submit" id="submit" />
<p id="fullname"></p>
$(document).ready(function() {
$("#submit").click(function() {
var username = $("#username").val();
$.getJSON("http://graph.facebook.com/" +
username + "?callback=?", function(resp) {
$("#fullname").html(resp.first_name + " " + resp.last_name);
});
});
});
What if the username doesn't exist?
Error checking!
$(document).ready(function() {
$("#submit").click(function() {
var username = $("#username").val();
$.getJSON("http://graph.facebook.com/" +
username + "?callback=?", function(resp) {
if (resp.error) {
$("#fullname").html("That username doesn't exist");
} else {
$("#fullname").html(resp.first_name + " " + resp.last_name);
}
});
});
});
More complicated apps
FB makes this easier by giving us a JS SDK.
Let's use it to get stuff that requires our user to be logged in!
Setting up the room
<!-- facebook needs this on the page -->
<div id="fb-root"></div>
// Load the SDK (English)
<script src="//connect.facebook.net/en_US/all.js"></script>
// Spanish/Latin America
<script src="//connect.facebook.net/es_LA/all.js"></script>
// put this in a script tag
FB.init({
appId : '429491807092112', // test app we're using for HHBA
status : true,
cookie : true,
xfbml : true
});
This FB app is set to work on localhost:8000
// in your code folder, on Mac or Linux
$ python -m SimpleHTTPServer
Goal: Let's build an app that tells us what our friends' favorite news sources are
Steps:
1. Get user's permission
2. Grab news feed
3. Find link domains
4. Present results
Follow along:
https://gist.github.com/3497835
Improvements?
1. More links
2. Site name instead of Domain
3. Filter out social media
OK. Your turn!
Thank you.
Al Shaw @A_L ALMSHAW@GMAIL.COM