Skip to content

Instantly share code, notes, and snippets.

@amysimmons
Last active December 26, 2017 06:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amysimmons/a064218347d6345b90bf to your computer and use it in GitHub Desktop.
Save amysimmons/a064218347d6345b90bf to your computer and use it in GitHub Desktop.
WDI Week 7 Notes

#WDI Week 7 Notes

##Monday

###MTA Demos

###Timers & Underscore

rails new matrix -T

gem 'underscore-rails' in Gemfile

bundle

//= require underscore in application.js

rails generate controller Pages index

start server

view page sources to check that underscore.js is included

Matrix js and comments:

var numbers = [];

// set to null so that i can call clear timeout and stop the timer running

$(document).ready(function() {

    var addBox = function(n){
        var $box = $('<div/>').addClass('box');
        $box.text(n);
        $box.prependTo('#boxes');
    }
    // the difference between .text and .html is that html will allow you to include
    // html tags like <strong></strong>, text wont. in this case we know that the text will
    // always just be a number, so no need to make it hml

    var showNumbers = function(){
        $('#boxes').empty();

        // _(numbers).each(function(n){
        //     addBox(n);
        // });

        _(numbers).each(addBox); // (this line does the same as the above three)

        // when somebody calls show numbers pass the numbers into underscore
        // call the .each method on it
    };

    var addNumber = function(){ 
        var n = $('#number').val();
        console.log(n);
        // at this point, the n is a string
        n = parseInt(n);

        numbers.push(n);

        addBox(n);

        $('#number').val('').focus();
        // sets the value to nothing and focuses on the input

    };

    $('#add_number').on('click', addNumber);
    // $('#add_number').click(addNumber); this is the same code as above


    var squareNumbers = function(){
        console.log("squareing numbers");

        numbers = _(numbers).map(function(n){
            return n * n;
        });

        // _.map(numbers), function(num){return num * num;});
        // _(numbers).map(function(num){return num * num;});
        // the above two lines do the same thing 

        showNumbers();
    };

    $('#square').on('click', squareNumbers);


    var customFunction = function(){
        numbers = _(numbers).map(calc);
        showNumbers();
    };

    var calc = function(i){
        var equation  = $('#number').val();
        return eval(equation);
    };

    $('#function').on('click', customFunction);

    var timer = null;

    $('#start').on('click', function(){
        clearInterval(timer);
        // this will ensure that any existing timer is stopped;

        timer = setInterval(addRandom, 500);

        // this line is starting the timer, saying every interval i want 
        // you to run the addRandom function
        // and it will do this every 500 miliseconds
    });

    $('#stop').on('click', function(){
        clearInterval(timer);
    });

    var addRandom = function(){
        var n = _.random(10000);
        // generates a random number between 0 and 10,000
        console.log(n);
        numbers.push(n);
        addBox(n);
    };

});

Matrix html:

<h1>Welcome to the Matrix</h1>

<div>
    <%= text_field_tag 'number', nil, :autofocus => true %>
    <%= button_tag 'Add number', :id => 'add_number' %>
    <%= button_tag 'Square', :id => 'square' %>
    <%= button_tag 'Custom function', :id => 'function' %>
    <%= button_tag 'Start', :id => 'start' %>
    <%= button_tag 'Stop', :id => 'stop' %>
</div>

<div id="boxes"></div>

###Ajax Intro

curl http://code.jquery.com/jquery-1.11.2.js > public/js/jquery.js

AJAX - asynchronous javascript and xml

We did this in the console:

var request = new XMLHttpRequest()

request

XMLHttpRequest {statusText: "", status: 0, responseURL: "", response: "", responseType: ""…}

request.readyState

0

request.open('GET', '/bros')

undefined

request.readyState

1

request.send()

request.responseText

"Zeppo"

To get another Marx brother:

var request = new XMLHttpRequest()

undefined

request.open('GET', '/bros')

undefined

request.send()

undefined

VM450:2 XHR finished loading: GET "http://localhost:4567/bros".

request.responseText

"Harpo"

  • you can re-use the same request, you don't need to make a new one each time

  • making a new request is like opening a new tab

  • using the same request is like re-entering the url in the same tab

Another example:

In main.rb:

get '/lotto' do
    Random.rand(1..40).to_s
end

In the console:

var lottoRequest = new XMLHttpRequest()

undefined

lottoRequest.open('GET', '/lotto')

undefined

lottoRequest.readyState

1

lottoRequest.send()

undefined

VM632:2 XHR finished loading: GET "http://localhost:4567/lotto".

lottoRequest.responseText

"34"

**Another console example: **

var request  = new XMLHttpRequest()

undefined

request.onreadystatechange = function(){

console.log(this.responseText);

console.log(this.readyState);

}

function (){

console.log(this.responseText);

console.log(this.readyState);

}

request.readyState

0

request.open('GET', '/slow')

VM1162:3 

VM1162:4 1

undefined

request.send()

undefined

VM1162:3 

VM1162:4 2

VM1162:3 haha

VM1162:4 3

VM1316:2 XHR finished loading: GET "http://localhost:4567/slow".

VM1162:3 haha

VM1162:4 4

In the ajax.js file:

var request = new XMLHttpRequest();

request.onreadystatechange = function(){
    console.log("ready state has changed");
    console.log(this.readyState);
    console.log(this.responseText);

    if (this.readyState === 4) {
        $('h3').text(this.responseText);
        console.log("Done");
    }
};

request.open('GET', '/slow');
request.send(); // asynchronous

console.log("ajax request is probably still running");

###Flickr

https://github.com/amysimmons/wdi8_homework/tree/master/amy/mta_jquery

##Tuesday

###Warmup

https://gist.github.com/wofockham/53232592840ff0b712cd

###Flickr Demos

https://github.com/amysimmons/wdi8_homework/tree/master/amy/flickr_app

###Flickr Review

https://github.com/wofockham/wdi-8/blob/018b42f2e1de677bc5a906f13a07bd4cd741b955/08-ajax/flickr_app/app/assets/javascripts/flickr.js

###More Ajax

###JQuery: Return Flight

###Ajax Movies

$.ajax('http://www.omdbapi.com/?t=jaws&y=&plot=short&r=json')

Object {readyState: 1, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}

jquery-87424c3c19e96d4fb033c10ebe21ec40.js?body=1:9660 XHR finished loading: GET "http://www.omdbapi.com/?t=jaws&y=&plot=short&r=json".

$.ajax('http://www.abc.net.au/news')

Object {readyState: 1, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}

localhost/:1 XMLHttpRequest cannot load http://www.abc.net.au/news. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
$.ajax('http://www.omdbapi.com/?t=jaws&y=&plot=short&r=json').done(function(result){
console.log(result);
});

Object {readyState: 1, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}abort: function ( statusText ) {always: function () {complete: function () {done: function () {error: function () {fail: function () {getAllResponseHeaders: function () {getResponseHeader: function ( key ) {overrideMimeType: function ( type ) {pipe: function ( /* fnDone, fnFail, fnProgress */ ) {progress: function () {promise: function ( obj ) {readyState: 4responseText: "{"Title":"Jaws","Year":"1975","Rated":"PG","Released":"20 Jun 1975","Runtime":"124 min","Genre":"Drama, Thriller","Director":"Steven Spielberg","Writer":"Peter Benchley (screenplay), Carl Gottlieb (screenplay), Peter Benchley (based on the novel by)","Actors":"Roy Scheider, Robert Shaw, Richard Dreyfuss, Lorraine Gary","Plot":"When a gigantic great white shark begins to menace the small island community of Amity, a police chief, a marine scientist and grizzled fisherman set out to stop it.","Language":"English","Country":"USA","Awards":"Won 3 Oscars. Another 10 wins & 14 nominations.","Poster":"http://ia.media-imdb.com/images/M/MV5BNDcxODkyMjY4MF5BMl5BanBnXkFtZTgwOTk5NTc5MDE@._V1_SX300.jpg","Metascore":"79","imdbRating":"8.1","imdbVotes":"332,608","imdbID":"tt0073195","Type":"movie","Response":"True"}"setRequestHeader: function ( name, value ) {state: function () {status: 200statusCode: function ( map ) {statusText: "OK"success: function () {then: function ( /* fnDone, fnFail, fnProgress */ ) {__proto__: Object
jquery-87424c3c19e96d4fb033c10ebe21ec40.js?body=1:9660 XHR finished loading: GET "http://www.omdbapi.com/?t=jaws&y=&plot=short&r=json".jquery-87424c3c19e96d4fb033c10ebe21ec40.js?body=1:9660 jQuery.ajaxTransport.sendjquery-87424c3c19e96d4fb033c10ebe21ec40.js?body=1:9211 jQuery.extend.ajaxVM418:2 (anonymous function)VM229:777 InjectedScript._evaluateOnVM229:710 InjectedScript._evaluateAndWrapVM229:626 InjectedScript.evaluate
VM418:3 {"Title":"Jaws","Year":"1975","Rated":"PG","Released":"20 Jun 1975","Runtime":"124 min","Genre":"Drama, Thriller","Director":"Steven Spielberg","Writer":"Peter Benchley (screenplay), Carl Gottlieb (screenplay), Peter Benchley (based on the novel by)","Actors":"Roy Scheider, Robert Shaw, Richard Dreyfuss, Lorraine Gary","Plot":"When a gigantic great white shark begins to menace the small island community of Amity, a police chief, a marine scientist and grizzled fisherman set out to stop it.","Language":"English","Country":"USA","Awards":"Won 3 Oscars. Another 10 wins & 14 nominations.","Poster":"http://ia.media-imdb.com/images/M/MV5BNDcxODkyMjY4MF5BMl5BanBnXkFtZTgwOTk5NTc5MDE@._V1_SX300.jpg","Metascore":"79","imdbRating":"8.1","imdbVotes":"332,608","imdbID":"tt0073195","Type":"movie","Response":"True"}

##Wednesday

###Warm up

https://gist.github.com/anonymous-wolf/9bf29bd5980a35b3f9ec

https://gist.github.com/anonymous-wolf/0288b4aea24fd07ca833

###Movie demos

https://github.com/amysimmons/wdi8_homework/tree/master/amy/movies_jquery

###Ajax review

###TODO App

Have a task

A description of the task

A checkbox that will determine whether it was completed or not

They can check or uncheck the box

Save button


rails new todo_app -T

rails generate migration create_tasks task:text description:text completed:boolean

rake db:migrate

touch app/models/task.rb

annotate

###Homework

####Working with JavaScript in Rails - http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html

Ajax introduction:

  • JavaScript can make requests to the server, and parse the response.
  • It also has the ability to update information on the page.
  • Combining these two powers, a JavaScript writer can make a web page that can update just parts of itself, without needing to get the full page data from the server.
  • This is a powerful technique that we call Ajax.
$.ajax({
  url: "/test"
}).done(function(html) {
  return $("#results").append(html);
});

The above code that makes an Ajax request using the jQuery library, appending the result to the div with an id of results.

Unobtrusive JavaScript:

Built-in helpers:

Methods written in Ruby to assist you in generating HTML.

eg form_for

<%= form_for(@article, remote: true) do |f| %>
  ...
<% end %>

The above generates the following html:

<form accept-charset="UTF-8" action="/articles" class="new_article" data-remote="true" id="new_article" method="post">
  ...
</form>

The data-remote="true" means the form will be submitted by Ajax rather than by the browser's normal submit mechanism.

To bind to the ajax:success event upon a successful submission:

$(document).ready(function() {
  return $("#new_article").on("ajax:success", function(e, data, status, xhr) {
    return $("#new_article").append(xhr.responseText);
  }).on("ajax:error", function(e, xhr, status, error) {
    return $("#new_article").append("<p>ERROR</p>");
  });
});

form_tag differs slightly

<%= form_tag('/articles', remote: true) do %>
  ...
<% end %>

results in the following html:

<form accept-charset="UTF-8" action="/articles" data-remote="true" method="post">
  ...
</form>

link_to generates links and also has a remote option:

<%= link_to "an article", @article, remote: true %>

generates the following html:

<a href="/articles/1" data-remote="true">an article</a>

Say we have a list of articles that can be deleted with one click:

<%= link_to "Delete article", @article, remote: true, method: :delete %>

button_to

<%= button_to "An article", @article, remote: true %>

generates the following html:

<form action="/articles/1" class="button_to" data-remote="true" method="post">
  <div><input type="submit" value="An article"></div>
</form>

Server-side concerns:

Ajax requests should usually return JSON, rather than HTML.

In this form example:

<%= form_for(@user, remote: true) do |f| %>
  <%= f.label :name %><br>
  <%= f.text_field :name %>
  <%= f.submit %>
<% end %>

Because the form's remote option is set to true, the request will be posted to the UsersController as an Ajax request, looking for JavaScript.

The create action of your controller would then look like this:

# app/controllers/users_controller.rb
# ......
def create
  @user = User.new(params[:user])
 
  respond_to do |format|
    if @user.save
      format.html { redirect_to @user, notice: 'User was successfully created.' }
      format.js   {}
      format.json { render json: @user, status: :created, location: @user }
    else
      format.html { render action: "new" }
      format.json { render json: @user.errors, status: :unprocessable_entity }
    end
  end
end

Turbolinks:

Turbolinks will make an Ajax request for the page, parse the response, and replace the entire of the page with the of the response.

It will then use PushState to change the URL to the correct one, preserving refresh semantics and giving you pretty URLs.

Additional reading:

http://www.alfajango.com/blog/rails-3-remote-links-and-forms/

http://railscasts.com/episodes/205-unobtrusive-javascript

http://railscasts.com/episodes/390-turbolinks

Anonymous functions and Closures

  • An anonymous function allows a developer to create a function that has no name.
  • Anonymous functions can be used to store a bit of functionality in a variable and pass that piece of functionality around.

For example, an anonymous function in Ruby and JS:

[1, 2, 3].map do |number_to_double|
  number_to_double * 2
end

_.map([1, 2, 3], function(numberToDouble) {
  return numberToDouble * 2
})
  • When a closure is created it can reference any of the variables available in its local environment.

JS lexical scoping example:

function lexicalScopeExample(multiplier) {
  return _.map([1, 2, 3], function(number) {
    var newNumberToDouble = number * multiplier
    return newNumberToDouble * 2
  });
}

In our JavaScript example we have two lexical scopes:

  1. The lexicalScopeExample function has the parameter multiplier
  2. The block we pass to the map method can access the multiplier, number and newNumberToDouble variables
  • The block’s lexical scope includes the variables which belong to the lexical scope it is created in.

  • The inverse is not true.

  • Variables defined in the block’s lexical scope are not then available to the function’s lexical scope.

Closures:

  • Closures allows us to define units of functionality while maintaining references to all the variables that exist in the lexical scope they are defined.

  • These units of functionality can then be executed in a different lexical scope.

function scopeTwo(callback) {
  callback();
}

function scopeOne() {
  var closureAddend = 3;

  scopeTwo(function() {
    closureAddend = closureAddend + 5;
  });

  console.log("The variable in our main lexical scope after the method is
    executed " + closureAddend);
}

javascript > scopeOne()

The variable in our main lexical scope after the method is executed equals 8

In our JavaScript example we have three lexical scopes:

  1. The scopeOne function includes the closureAddend variable

  2. The function (closure) we pass when we call the scopeTwo function includes the closureAddend variables

  • In the browser console we call our scopeOne function
  • Within this function we create the closureAddend variable and assign it the value of 3
  • Within the lexical scope of our scopeOne function we define a function and pass it to the scopeTwo function
  • Inside the new lexical scope of the scopeTwo function we execute our closure that we called callback
  • Inside of our closure we add 5 to the closureAddend variable we defined within the lexical scope of the scopeOne function
  • We then return to our scopeOne lexical scope and log our closureAddend variable, which has now been incremented by 5

Our closure gets executed in a completely different lexical scope than it was created in, but still has access to the variables in the original scope.

We can't access closureAddend in scopeTwo's lexical scope:

function scopeTwo(callback) {
  callback();
  console.log("We just modified this variable in the block above " + closureAddend);
}

function scopeOne() {
  var closureAddend = 3;

  scopeTwo(function() {
    closureAddend = closureAddend + 5;
  });

  console.log("The variable in our main lexical scope after the method
    is executed " + closureAddend);
}

javascript > scopeOne()

ReferenceError: closureAddend is not defined

Source:

https://gist.github.com/wofockham/9fb80a265a60c865b308

https://robots.thoughtbot.com/back-to-basics-anonymous-functions-and-closures

####Everything you need to know about Scope

What is Scope?:

Scope refers to the current context of your code.

Ask yourself, are we inside Scope A or Scope B?

Global:

Before you write a line of JavaScript, you're in what we call the Global Scope.

jQuery('.myClass'); is accessing jQuery in global scope.

We can refer to this access as the namespace.

The namespace is sometimes an interchangable word for scope, but usually the refers to the highest level scope.

In this case, jQuery is in the global scope, and is also our namespace.

The jQuery namespace is defined in the global scope, which acts as a namespace for the jQuery library as everything inside it becomes a descendent of that namespace.

Local:

Any scope defined past the global scope.

// Scope A: Global scope out here
var myFunction = function () {
  // Scope B: Local scope in here
};

Any locally scoped items are not visible in the global scope - unless exposed!

New function = New Scope:

// Scope A
var myFunction = function () {
  // Scope B
  var myOtherFunction = function () {
    // Scope C
  };
};

Lexical scope:

Whenever you see a function within another function, the inner function has access to the scope in the outer function, this is called Lexical Scope or Closure.

// Scope A
var myFunction = function () {
  // Scope B
  var name = 'Todd'; // defined in Scope B
  var myOtherFunction = function () {
    // Scope C: `name` is accessible here!
  };
};

Any variables/objects/functions defined in it's parent scope, are available in the scope chain

var name = 'Todd';
var scope1 = function () {
  // name is available here
  var scope2 = function () {
    // name is available here too
    var scope3 = function () {
      // name is also available here!
    };
  };
};

But lexical scope does not work backwards.

// name = undefined
var scope1 = function () {
  // name = undefined
  var scope2 = function () {
    // name = undefined
    var scope3 = function () {
      var name = 'Todd'; // locally scoped
    };
  };
};

Scope chain:

When resolving a variable, JavaScript starts at the innermost scope and searches outwards until it finds the variable/object/function it was looking for.

Closures:

Inside our scope, we can return things so that they're available in the parent scope:

var sayHello = function (name) {
  var text = 'Hello, ' + name;
  return function () {
    console.log(text);
  };
};

In the above example, our scope inside sayHello is inaccessible to the public scope.

Calling the function alone will do nothing as it returns a function:

sayHello('Todd'); // nothing happens, no errors, just silence...

The function returns a function, which means it needs assignment, and then calling:

var helloTodd = sayHello('Todd');
helloTodd(); // will call the closure and log 'Hello, Todd'

Scope and this:

By default this refers to the outer most global object, the window.

We can easily show how invoking functions in different ways binds the this value differently:

var myFunction = function () {
  console.log(this); // this = global, [object Window]
};
myFunction();

var myObject = {};
myObject.myMethod = function () {
  console.log(this); // this = Object { myObject }
};

var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
  console.log(this); // this = <nav> element
};
nav.addEventListener('click', toggleNav, false);

But the this value can cause problems when inside the same function, the scope can be changed and the this value can default back to the window.

For example:

var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
  console.log(this); // <nav> element
  setTimeout(function () {
    console.log(this); // [object Window]
  }, 1000);
};
nav.addEventListener('click', toggleNav, false);

In the above example we've created new scope which is not invoked from our event handler, so it defaults to the window Object as expected.

You can use that access the proper this value:

var nav = document.querySelector('.nav'); // <nav class="nav">
var toggleNav = function () {
  var that = this;
  console.log(that); // <nav> element
  setTimeout(function () {
    console.log(that); // <nav> element
  }, 1000);
};
nav.addEventListener('click', toggleNav, false);

The above allows you to use the proper this value and resolve problems with newly created scope.

.call() and .apply():

The .call() and .apply() methods allow you to pass in a scope to a function, which binds the correct this value.

Here, we set this to be the value of the li:

var links = document.querySelectorAll('nav li');
for (var i = 0; i < links.length; i++) {
  (function () {
    console.log(this);
  }).call(links[i]);
}

The difference between .call() and .apply():

We can use either .call() or .apply() to change the scope, but any further arguments are where the two differ...

  • .call(scope, arg1, arg2, arg3) takes individual arguments, comma separated

  • .apply(scope, [arg1, arg2]) takes an Array of arguments

Using .call() or .apply() actually invokes your function

.bind():

Using .bind() does not invoke a function, it merely binds the values before the function is invoked.

nav.addEventListener('click', toggleNav.bind(scope, arg1, arg2), false);

The function isn't invoked, and the scope can be changed if needed, but arguments are sat waiting to be passed in.

Source:

https://gist.github.com/wofockham/9fb80a265a60c865b308

http://toddmotto.com/everything-you-wanted-to-know-about-javascript-scope/

##Thursday

###Warmup

https://gist.github.com/anonymous-wolf/36571a4de68d042c7131

https://gist.github.com/anonymous-wolf/383eba988f641a6abc90

class DNA

    def initialize(strand1)
        @strand1 = strand1
    end

    def hamming_distance(strand2)

        @strand2 = strand2

        strand1_length = @strand1.chars.length 
        strand2_length = @strand2.chars.length

        min_length = [strand1_length, strand2_length].min
        count = 0
        index = - 1

        while index < min_length - 1 do
            index = index += 1
            a = @strand1[index]
            b = @strand2[index]
            if a != b 
                count += 1
            end
        end

        p count

    end

end

The zip method:

http://apidock.com/ruby/Array/zip

Allows for easy comparison betweeen two arrays!

###Callbacks

Understanding the difference between the following callbacks:

$(document).ready(fn)

  • this says i want you to run when the document is ready, you know that at some point the document will be ready and your code will always run, but you don't know when, some time in the future i want this to happen

setTimeout(fn, 1000)

  • after 1000 ms i want this function to ran

.fadeOut(fn)

  • after the fadeout, i want this fn to run, the default is 400ms, so after 400ms i want this fn to run

.on('click', fn)

  • you can't guarantee that a user ever actually clicks this function, so it may never run

.ajax('someurl').done(fn)

  • this ajax fn should finish eventually, but you dont know how long its going to take, also something can go wrong wit this url

  • whats special about the ajax one is that it can access data that isn't currently in your page or in your dom

  • it can reach out to any url, and either get some data from it or put some data to it

  • eg a chat system, the magic thing about ajax is that it can go and get data from the server, pull it into your javascript environment, and then you can do something with it

  • most of the time it will be pulling in something that you couldn't have previously predicted

  • the information it can get or send to the server is anything, it's up to you

  • ajax needs the server to cooperate as well, it's not just javascript

Other than that the above callbacks are all similar, it's always some function that gets called at some point in the future.

###Handlebars

http://handlebarsjs.com/

###UJS

Unobtrusive javascript:

if there is data remote true field set on the form

:remote => true

instead of it running my ajax code

it makes a silent request in the background

###Codeschool JavaScript path - https://www.codeschool.com/paths/javascript

##Friday

###Git talk

the app is created by one person in the team

/config/database.yml - add this in the .gitignore file

in config folder, make a new database.yml.example file

host: localhost

username: inceptor

rake db:create

push the existing repo to the command line

by doing a git remote

and then a git push

git rm config/database.yml (if the yml file gets pushed, and doesnt get removed)

the other people in the group clone the project

always git pull before you git push

so that you have the latest changes on your computer

git log wil show you what changes have been made

branch scenario:

git checkout -b users

generate a migration

generate a controller

git add

git commit -m

git status, on branch users

git merge master into users

then can push my users branch into master

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment