Objective |
---|
To identify the basic compenents of a Angular application and integrate them together in a manner that creates a canonical example for one to further develop or rexamine afterward. |
========
- A First
ng-app
- Setup JS-Bin
- Add Library
angular 1.2.1
- Setup an
ng-app
- Seeing
ng-model
, and two_way_data_binding
- Seeing
- Setup an
ng-controller
- The
ng-controller
directive- A controller function
- Using $scope in a controller
- Using the
ng-repeat
directive- A new
$scope
- Iterating through an
Array
- Iterating through
(key, values)
in anArray
- A new
- Using some actions
ng-sumbit
ng-click
- The
- Modularizing
- An app module
- A controller module
- A Basic Rails App (Using Rails 4 or 3, won't assume a particular gem)
- Setting up a Sample App
- Setup
config/routes
- generate a
SamplesController
with methods.
- Setup
- Download Angular into
vendor/assets/javascripts
- Setup a modular
SampleApp
- Setup a modular
SampleAppCtrl
- Using
$http
- Using
- Setup with
ngRoute
- Setup with
ngResource
- Setting up a Sample App
========
Let's begin a project in a directory of your choosing:
rails new sample_app
....
cd sample_app
To get angular you can do one of the following
curl -G http://code.angularjs.org/1.2.13/angular-1.2.13.zip > vendor/assets/javascripts && open vendor/assets/javascripts/angular
and just rm vendor/assets/javascripts/angular
, which might be a little over the top and UNIX-y, or you can download it from here, open it, and then
mv "~/Downloads/angular-1.2.13" vendor/assets/javascripts/
We need to load our angular.min.js
, so we add the following to the assets/javascripts/application.js
/application.js
...
//= require jquery
//= require jquery_ujs
//= require turbolinks
// ***** ADD ANGULAR HERE *****
//= require angular-1.2.13/angular.min
// *****
//= require_tree .
Let's start off with a controller called SamplesController
for our SampleApp
rails g controller samples index
/samples/index.html.erb
<div ng-app>
<input type="text" ng-model="name" placeholder="name">
<p> HELLO, {{name}}! </p>
</div>
Now we modify our routes
SampleApp::Application.routes.draw do
root to: "samples#index"
resources :samples
end
If angular has loaded correctly then this example should be working at localhost:3000
Change <div ng-app>
in the index to ng-app="SampleApp"
/samples/index.html.erb
<div ng-app="SampleApp">
...
</div>
Create a sample_app.js
in app/assets/javascripts
and define a SampleApp
module in it.
/assets/javascripts/sample_app.js
var SampleApp = angular.module("SampleApp",[]);
Create a samples_controller.js
in app/assets/javascripts
and define a SampleAppCtrls
module in it.
/assets/javascripts/samples_controller.js
var SampleAppCtrls = angular.module("SampleAppCtrls",[]);
SampleAppCtrls.controller("SamplesCtrl", ["$scope", function($scope){
}]);
Now we can add SampleAppCtrls
as a module in sample_app.js
, i.e.
/assets/javascripts/sample_app.js
var SampleApp = angular.module("SampleApp",[
"SampleAppCtrls"
]);
Let's define some fakeSamples
in the SamplesCtrl
/assets/javascripts/samples_controller.js
...
SampleAppCtrls.controller("SamplesCtrl", ["$scope", function($scope){
// fakeSamples
$scope.fakeSamples = [
{name: "bunny", description: "fluffy"}
,{name: "Green Stuff", description: "meh"}
,{name: "elephant", description: "big"}
];
}]);
Now we need to display these fakeSamples
in a view for our SamplesCtrl
/samples/index.html.erb
<div ng-app="SampleApp">
...
<!-- NOTE HERE THE ng-controller-->
<div ng-controller="SamplesCtrl">
<!-- NOTE HERE THE ng-repeat over the items defined
in our SamplesCtrl -->
<div ng-repeat="sample in fakeSamples">
A {{sample.name}} looked {{sample.description}}
</div>
</div>
...
</div>
We can handle routing by loading the ngRoute
module. We begin this by adding the angular-route
script into our appliction.js
/application.js
//= require jquery
//= require jquery_ujs
//= require turbolinks
// ***** ADD ANGULAR HERE *****
//= require angular-1.2.13/angular.min
// ***** ADD ANGULAR ROUTER HERE *****
//= require angular-1.2.13/angular-route.min
//*****
//= require_tree .
Now we can update our sample_app.js
to include a router module.
/assets/javascripts/sample_app.js
var SampleApp = angular.module("SampleApp",[]);
// Create our Sample module with `ngRoute` dependency
var SamplesRouter = angular.module("SamplesRouter", ["ngRoute"]);
Next we need to configure our route to respond to certain paths
/assets/javascripts/sample_app.js
SamplesRouter.config(["$routeProvider",
function($routeProvider, $httpProvider){
$routeProvider.when("/samples", {
// Note here the path is just "/samples/pretty_template"
templateUrl: "/samples/pretty_template",
controller: "SamplesCtrl"
})
}]);
Note we add this /samples/pretty_template
path to our routes
config/routes.rb
SampleApp::Application.routes.draw do
root to: "samples#index"
# pretty template
get "/samples/pretty_template" to: "samples#pretty_template"
resources :samples
end
Note we add the /samples/pretty_template
view and method
samples_controller.rb
class SamplesController < ApplicationController
def index
end
def pretty_template
render layout: false
end
end
/samples/pretty_template.html.erb
<div style="color:blue; padding: 10px;"ng-repeat="sample in fakeSamples">
{{sample.name}} is {{sample.description}}
</div>
Now all that is left is to render the view in the index.html, and we change it to look as follows.
<div ng-app="SampleApp">
<input type="text" ng-model="name" placeholder="name">
<p> HELLO, {{name}}! </p>
<a href="#/samples"> pretty format</a>
<div ng-view>
</div>
</div>
Let's try making a request for more samples to our server. In order to make a request we should update our SampleController#index
to respond with an array of JSON samples.
samples_controller.rb
class SamplesController < ApplicationController
def index
# Add some fake samples
fake_samples = [{name: "blah"},{name: "pretty blah"}]
# respond to the type of request
respond_to do |f|
f.html
f.json {render :json => fake_samples}
end
end
...
end
That should be pretty straight forward. Now all we have to do is modify our SamplesCtrl
to make an http resquest using Angular's $http
object.
/assets/javascripts/samples_controller.js
...
// Add the `$http` dependency to list
SampleAppCtrls.controller("SamplesCtrl", ["$scope", "$http",
function($scope){
// fake samples
$scope.fakeSamples = [{name: "bunny", description: "fluffy"}
, {name: "Green Stuff", description: "meh"}
, {name: "elephant", description: "big"}
];
}]);
Now try writing a get request for more samples as follows.
SampleAppCtrls.controller("SamplesCtrl", ["$scope", "$http",
function($scope){
// fake samples
$scope.fakeSamples = [{name: "bunny", description: "fluffy"}
, {name: "Green Stuff", description: "meh"}
, {name: "elephant", description: "big"}
];
// requesting more samples
$http.get("/samples.json").success(function(data){
console.log(data);
$scope.fakeSamples = $scope.fakeSamples.concat(data);
});
}]);
If we try to do an $http.post
request we might get a 422 an unprocessible entity respone from server. This is most likely due to not including a CSRF
token or authenticity token. Let's create a Sample
model in our database, before we get any further with making post
requests.
$ rails g model sample name description
...
$ rake db:migrate
Now setup a create
method in our SamplesController
samples_controller.rb
class SamplesController < ApplicationController
...
def create
new_sample = params[:sample]
# In Rails 4
# new_sample = params.require(:sample).permit(:name, :description)
sample = Sample.create(new_sample)
respond_to do |f|
f.html {redirect_to samples_path}
f.json {render json: sample }
end
end
end
Now we can try our first attempt at making a simple $http
post request with an included authenticity token, which we will refactor shortly.
/assets/javascripts/samples_controller.js
$scope.saveSample = function(){
$http({method: "post",
url: "/samples",
data: {sample:
{name: $scope.mock_sample},
"authenticity_token": $('meta[name=csrf-token]').attr('content')}
}).success(function(data){
console.log(data);
});
};